{"thread":{"id":"43954","subject":"[PATCH 02/22] sequencer: use memoized sequencer directory path","startedAt":"2016-08-29T08:04:27Z","lastAt":"2016-11-06T14:05:26Z","messageCount":352,"participants":["Johannes Schindelin","Dennis Kaarsemaker","Jakub Narębski","Junio C Hamano","Johannes Sixt","Stefan Beller","Jeff King","Torsten Bögershausen","Max Horn","Lars Schneider"],"isPatch":true,"patchVersion":1,"patchTotal":22},"messages":[{"id":"300410","messageId":"d032a9d765aaca0655b1e363e67d9bf24864396c.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 02/22] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:09Z","receivedAt":"2016-08-29T08:04:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/commit.c |  2 +-\n sequencer.c      | 11 ++++++-----\n sequencer.h      |  5 +----\n 3 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 77e3dc8..0221190 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -173,7 +173,7 @@ static void determine_whence(struct wt_status *s)\n \t\twhence = FROM_MERGE;\n \telse if (file_exists(git_path_cherry_pick_head())) {\n \t\twhence = FROM_CHERRY_PICK;\n-\t\tif (file_exists(git_path(SEQ_DIR)))\n+\t\tif (file_exists(git_path_seq_dir()))\n \t\t\tsequencer_in_use = 1;\n \t}\n \telse\ndiff --git a/sequencer.c b/sequencer.c\nindex b6481bb..4d2b4e3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -21,10 +21,11 @@\n const char sign_off_header[] = \"Signed-off-by: \";\n static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n \n-static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n-static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n-static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n-static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n+GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n+\n+static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n+static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n+static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n static int is_rfc2822_line(const char *buf, int len)\n {\n@@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n+\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n \tremove_dir_recursively(&seq_dir, 0);\n \tstrbuf_release(&seq_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex 2ca096b..c955594 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -1,10 +1,7 @@\n #ifndef SEQUENCER_H\n #define SEQUENCER_H\n \n-#define SEQ_DIR\t\t\"sequencer\"\n-#define SEQ_HEAD_FILE\t\"sequencer/head\"\n-#define SEQ_TODO_FILE\t\"sequencer/todo\"\n-#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n+const char *git_path_seq_dir(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300411","messageId":"66d69469a64bd80d3bf2b99a250ae04a649d94d1.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 01/22] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:03:48Z","receivedAt":"2016-08-29T08:04:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 6 ++----\n sequencer.h      | 1 +\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4e69380..7365559 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -178,10 +178,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n@@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n \tparse_args(argc, argv, &opts);\ndiff --git a/sequencer.h b/sequencer.h\nindex 5ed5cb1..2ca096b 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -47,6 +47,7 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n+#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300412","messageId":"cover.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":null,"subject":"[PATCH 00/22] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:03:41Z","receivedAt":"2016-08-29T08:04:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series marks the  '4' in the countdown to speed up rebase -i\nby implementing large parts in C. It is based on the `libify-sequencer`\npatch series that I submitted last week.\n\nThe patches in this series merely prepare the sequencer code for the\nnext patch series that actually teaches the sequencer to run an\ninteractive rebase.\n\nThe reason to split these two patch series is simple: to keep them at a\nsensible size.\n\nThe two patch series after that are much smaller: a two-patch \"series\"\nthat switches rebase -i to use the sequencer (except with --root or\n--preserve-merges), and a couple of patches to move several pretty\nexpensive script processing steps to C (think: autosquash).\n\nThe end game of this patch series is a git-rebase--helper that makes\nrebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\nthat even MacOSX and Linux benefit (4x and 3x, respectively).\n\nI have been working on this since early February, whenever time allowed,\nand it is time to put it into the users' hands. To that end, I will most\nlikely submit the remaining three patch series in the next two days, and\nintegrate the whole shebang into Git for Windows 2.10.0.\n\nTherefore I would be most grateful for every in-depth review.\n\n\nJohannes Schindelin (22):\n  sequencer: use static initializers for replay_opts\n  sequencer: use memoized sequencer directory path\n  sequencer: avoid unnecessary indirection\n  sequencer: future-proof remove_sequencer_state()\n  sequencer: allow the sequencer to take custody of malloc()ed data\n  sequencer: release memory that was allocated when reading options\n  sequencer: future-proof read_populate_todo()\n  sequencer: remove overzealous assumption\n  sequencer: completely revamp the \"todo\" script parsing\n  sequencer: avoid completely different messages for different actions\n  sequencer: get rid of the subcommand field\n  sequencer: refactor the code to obtain a short commit name\n  sequencer: remember the onelines when parsing the todo file\n  sequencer: prepare for rebase -i's commit functionality\n  sequencer: introduce a helper to read files written by scripts\n  sequencer: prepare for rebase -i's GPG settings\n  sequencer: allow editing the commit message on a case-by-case basis\n  sequencer: support amending commits\n  sequencer: support cleaning up commit messages\n  sequencer: remember do_recursive_merge()'s return value\n  sequencer: left-trim the lines read from the script\n  sequencer: refactor write_message()\n\n builtin/commit.c                |   2 +-\n builtin/revert.c                |  42 ++-\n sequencer.c                     | 573 +++++++++++++++++++++++++++-------------\n sequencer.h                     |  27 +-\n t/t3510-cherry-pick-sequence.sh |  11 -\n 5 files changed, 428 insertions(+), 227 deletions(-)\n\nBased-On: libify-sequencer at https://github.com/dscho/git\nFetch-Base-Via: git fetch https://github.com/dscho/git libify-sequencer\nPublished-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v1\nFetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v1\n\n-- \n2.10.0.rc1.114.g2bd6b38\n\nbase-commit: 2d6d71e2a2d410b12d783f0a8edd22791f303c12\n"},{"id":"300413","messageId":"e5e6c27038c7db226a787da6b7ee343b2b310654.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 03/22] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:15Z","receivedAt":"2016-08-29T08:04:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We really do not need the *pointer to a* pointer to the options in\nthe read_populate_opts() function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 4d2b4e3..14ef79b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -809,11 +809,11 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static int read_populate_opts(struct replay_opts **opts)\n+static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n+\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n \t\treturn error(_(\"Malformed options sheet: %s\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n@@ -1038,7 +1038,7 @@ static int sequencer_continue(struct replay_opts *opts)\n \n \tif (!file_exists(git_path_todo_file()))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(&opts) ||\n+\tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n \t\treturn -1;\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300414","messageId":"2245e7db4d4c028f63b2f4c41097559f91756f2c.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 04/22] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:28Z","receivedAt":"2016-08-29T08:04:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In a couple of commits, we will teach the sequencer to handle the\nnitty gritty of the interactive rebase, which keeps its state in a\ndifferent directory.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 24 ++++++++++++++++--------\n 1 file changed, 16 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 14ef79b..c4b223b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,11 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+static const char *get_dir(const struct replay_opts *opts)\n+{\n+\treturn git_path_seq_dir();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -109,13 +114,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(void)\n+static void remove_sequencer_state(const struct replay_opts *opts)\n {\n-\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n-\tremove_dir_recursively(&seq_dir, 0);\n-\tstrbuf_release(&seq_dir);\n+\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -895,6 +900,9 @@ static int sequencer_rollback(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tstruct strbuf buf = STRBUF_INIT;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tf = fopen(git_path_head_file(), \"r\");\n \tif (!f && errno == ENOENT) {\n \t\t/*\n@@ -924,7 +932,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n \treturn 0;\n fail:\n@@ -1018,7 +1026,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \treturn 0;\n }\n \n@@ -1079,7 +1087,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t * one that is being continued\n \t */\n \tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(opts);\n \t\treturn 0;\n \t}\n \tif (opts->subcommand == REPLAY_ROLLBACK)\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300415","messageId":"e4e7eab3d0610faa9d3173a585902e50128d8e15.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:32Z","receivedAt":"2016-08-29T08:04:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\nlike a one-shot command when it reads its configuration: memory is\nallocated and released only when the command exits.\n\nThis is kind of okay for git-cherry-pick, which *is* a one-shot\ncommand. All the work to make the sequencer its work horse was\ndone to allow using the functionality as a library function, though,\nincluding proper clean-up after use.\n\nThis patch introduces an API to pass the responsibility of releasing\ncertain memory to the sequencer.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 13 +++++++++++++\n sequencer.h |  8 +++++++-\n 2 files changed, 20 insertions(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c4b223b..b5be0f9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -114,9 +114,22 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n+{\n+\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n+\topts->owned[opts->owned_nr++] = set_me_free_after_use;\n+\n+\treturn set_me_free_after_use;\n+}\n+\n static void remove_sequencer_state(const struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n+\tint i;\n+\n+\tfor (i = 0; i < opts->owned_nr; i++)\n+\t\tfree(opts->owned[i]);\n+\tfree(opts->owned);\n \n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\ndiff --git a/sequencer.h b/sequencer.h\nindex c955594..20b708a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -43,8 +43,14 @@ struct replay_opts {\n \n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n+\n+\t/* malloc()ed data entrusted to the sequencer */\n+\tvoid **owned;\n+\tint owned_nr, owned_alloc;\n };\n-#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n+#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n+\n+void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use);\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300416","messageId":"e4b48a9a73ff33179556c0137caae85bfb4a48d9.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:37Z","receivedAt":"2016-08-29T08:04:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer reads options from disk and stores them in its struct\nfor use during sequencer's operations.\n\nWith this patch, the memory is released afterwards, plugging a\nmemory leak.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b5be0f9..8d79091 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -131,6 +131,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \t\tfree(opts->owned[i]);\n \tfree(opts->owned);\n \n+\tfree(opts->xopts);\n+\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n@@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n \telse if (!strcmp(key, \"options.mainline\"))\n \t\topts->mainline = git_config_int(key, value);\n-\telse if (!strcmp(key, \"options.strategy\"))\n+\telse if (!strcmp(key, \"options.strategy\")) {\n \t\tgit_config_string(&opts->strategy, key, value);\n-\telse if (!strcmp(key, \"options.gpg-sign\"))\n+\t\tsequencer_entrust(opts, (char *) opts->strategy);\n+\t}\n+\telse if (!strcmp(key, \"options.gpg-sign\")) {\n \t\tgit_config_string(&opts->gpg_sign, key, value);\n+\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n+\t}\n \telse if (!strcmp(key, \"options.strategy-option\")) {\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n-\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n+\t\topts->xopts[opts->xopts_nr++] =\n+\t\t\tsequencer_entrust(opts, xstrdup(value));\n \t} else\n \t\treturn error(_(\"Invalid key: %s\"), key);\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300417","messageId":"4043fd4b955d6a3bed1b187d9529d5382db5b961.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 07/22] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:42Z","receivedAt":"2016-08-29T08:04:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Over the next commits, we will work on improving the sequencer to the\npoint where it can process the edit script of an interactive rebase. To\nthat end, we will need to teach the sequencer to read interactive\nrebase's todo file. In preparation, we consolidate all places where\nthat todo file is needed to call a function that we will later extend.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d79091..982b6e9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n \treturn git_path_seq_dir();\n }\n \n+static const char *get_todo_path(const struct replay_opts *opts)\n+{\n+\treturn git_path_todo_file();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -772,25 +777,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n static int read_populate_todo(struct commit_list **todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n+\tconst char *todo_file = get_todo_path(opts);\n \tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n-\tfd = open(git_path_todo_file(), O_RDONLY);\n+\tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"),\n-\t\t\t\t   git_path_todo_file());\n+\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n \tif (strbuf_read(&buf, fd, 0) < 0) {\n \t\tclose(fd);\n \t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n+\t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n \tstrbuf_release(&buf);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n-\t\t\tgit_path_todo_file());\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n@@ -1064,7 +1068,7 @@ static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n \n-\tif (!file_exists(git_path_todo_file()))\n+\tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300418","messageId":"3c8c60e0799fdf176c72e7e17c257d33b2a362bc.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:04:47Z","receivedAt":"2016-08-29T08:04:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer was introduced to make the cherry-pick and revert\nfunctionality available as library function, with the original idea\nbeing to extend the sequencer to also implement the rebase -i\nfunctionality.\n\nThe test to ensure that all of the commands in the script are identical\nto the overall operation does not mesh well with that.\n\nTherefore let's just get rid of the test that wants to verify that this\nlimitation is still in place, in preparation for the upcoming work to\nteach the sequencer to do rebase -i's work.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t3510-cherry-pick-sequence.sh | 11 -----------\n 1 file changed, 11 deletions(-)\n\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 7b7a89d..6465edf 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n \ttest_expect_code 128 git cherry-pick --continue\n '\n \n-test_expect_success 'malformed instruction sheet 2' '\n-\tpristine_detach initial &&\n-\ttest_expect_code 1 git cherry-pick base..anotherpick &&\n-\techo \"resolved\" >foo &&\n-\tgit add foo &&\n-\tgit commit &&\n-\tsed \"s/pick/revert/\" .git/sequencer/todo >new_sheet &&\n-\tcp new_sheet .git/sequencer/todo &&\n-\ttest_expect_code 128 git cherry-pick --continue\n-'\n-\n test_expect_success 'empty commit set' '\n \tpristine_detach initial &&\n \ttest_expect_code 128 git cherry-pick base..base\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300419","messageId":"163aaa2a64ddf6dfb28c77c821726e14cc78619e.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:05:13Z","receivedAt":"2016-08-29T08:05:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When we came up with the \"sequencer\" idea, we really wanted to have\nkind of a plumbing equivalent of the interactive rebase. Hence the\nchoice of words: the \"todo\" script, a \"pick\", etc.\n\nHowever, when it came time to implement the entire shebang, somehow this\nidea got lost and the sequencer was used as working horse for\ncherry-pick and revert instead. So as not to interfere with the\ninteractive rebase, it even uses a separate directory to store its\nstate.\n\nFurthermore, it also is stupidly strict about the \"todo\" script it\naccepts: while it parses commands in a way that was *designed* to be\nsimilar to the interactive rebase, it then goes on to *error out* if the\ncommands disagree with the overall action (cherry-pick or revert).\n\nFinally, the sequencer code chose to deviate from the interactive rebase\ncode insofar that it *reformats* the \"todo\" script instead of just\nwriting the part of the parsed script that were not yet processed. This\nis not only unnecessary churn, but might well lose information that is\nvaluable to the user (i.e. comments after the commands).\n\nLet's just bite the bullet and rewrite the entire parser; the code now\nbecomes not only more elegant: it allows us to go on and teach the\nsequencer how to parse *true* \"todo\" scripts as used by the interactive\nrebase itself. In a way, the sequencer is about to grow up to do its\nolder brother's job. Better.\n\nWhile at it, do not stop at the first problem, but list *all* of the\nproblems. This helps the user by allowing to address all issues in\none go rather than going back and forth until the todo list is valid.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 241 +++++++++++++++++++++++++++++++++---------------------------\n 1 file changed, 134 insertions(+), 107 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 982b6e9..cbdce6d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -473,7 +473,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \t\treturn 1;\n }\n \n-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n+enum todo_command {\n+\tTODO_PICK,\n+\tTODO_REVERT\n+};\n+\n+static const char *todo_command_strings[] = {\n+\t\"pick\",\n+\t\"revert\"\n+};\n+\n+static const char *command_to_string(const enum todo_command command)\n+{\n+\tif (command < ARRAY_SIZE(todo_command_strings))\n+\t\treturn todo_command_strings[command];\n+\tdie(\"Unknown command: %d\", command);\n+}\n+\n+\n+static int do_pick_commit(enum todo_command command, struct commit *commit,\n+\t\tstruct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -535,7 +554,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t/* TRANSLATORS: The first %s will be \"revert\" or\n \t\t   \"cherry-pick\", the second %s a SHA1 */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n-\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n+\t\t\tcommand_to_string(command),\n+\t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n@@ -548,7 +568,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * reverse of it if we are revert.\n \t */\n \n-\tif (opts->action == REPLAY_REVERT) {\n+\tif (command == TODO_REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -589,7 +609,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t}\n \t}\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n@@ -615,17 +635,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * However, if the merge did not even start, then we don't want to\n \t * write it at all.\n \t */\n-\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n+\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n-\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n+\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n \n \tif (res) {\n-\t\terror(opts->action == REPLAY_REVERT\n+\t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n \t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n@@ -683,116 +703,107 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n-\t\tstruct replay_opts *opts)\n+struct todo_item {\n+\tenum todo_command command;\n+\tstruct commit *commit;\n+\tsize_t offset_in_buf;\n+};\n+\n+struct todo_list {\n+\tstruct strbuf buf;\n+\tstruct todo_item *items;\n+\tint nr, alloc, current;\n+};\n+\n+#define TODO_LIST_INIT { STRBUF_INIT, NULL, 0, 0, 0 }\n+\n+static void todo_list_release(struct todo_list *todo_list)\n {\n-\tstruct commit_list *cur = NULL;\n-\tconst char *sha1_abbrev = NULL;\n-\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n-\tconst char *subject;\n-\tint subject_len;\n+\tstrbuf_release(&todo_list->buf);\n+\tfree(todo_list->items);\n+\ttodo_list->items = NULL;\n+\ttodo_list->nr = todo_list->alloc = 0;\n+}\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n-\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n-\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n-\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n-\t\t\tsubject_len, subject);\n-\t\tunuse_commit_buffer(cur->item, commit_buffer);\n-\t}\n-\treturn 0;\n+struct todo_item *append_todo(struct todo_list *todo_list)\n+{\n+\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n+\treturn todo_list->items + todo_list->nr++;\n }\n \n-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n {\n \tunsigned char commit_sha1[20];\n-\tenum replay_action action;\n \tchar *end_of_object_name;\n-\tint saved, status, padding;\n-\n-\tif (starts_with(bol, \"pick\")) {\n-\t\taction = REPLAY_PICK;\n-\t\tbol += strlen(\"pick\");\n-\t} else if (starts_with(bol, \"revert\")) {\n-\t\taction = REPLAY_REVERT;\n-\t\tbol += strlen(\"revert\");\n-\t} else\n-\t\treturn NULL;\n+\tint i, saved, status, padding;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n+\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n+\t\t\titem->command = i;\n+\t\t\tbreak;\n+\t\t}\n+\tif (i >= ARRAY_SIZE(todo_command_strings))\n+\t\treturn -1;\n \n \t/* Eat up extra spaces/ tabs before object name */\n \tpadding = strspn(bol, \" \\t\");\n \tif (!padding)\n-\t\treturn NULL;\n+\t\treturn -1;\n \tbol += padding;\n \n-\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n+\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n \tsaved = *end_of_object_name;\n \t*end_of_object_name = '\\0';\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n-\t/*\n-\t * Verify that the action matches up with the one in\n-\t * opts; we don't support arbitrary instructions\n-\t */\n-\tif (action != opts->action) {\n-\t\tif (action == REPLAY_REVERT)\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot revert during another revert.\")\n-\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n-\t\telse\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n-\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n-\t\treturn NULL;\n-\t}\n-\n \tif (status < 0)\n-\t\treturn NULL;\n+\t\treturn -1;\n \n-\treturn lookup_commit_reference(commit_sha1);\n+\titem->commit = lookup_commit_reference(commit_sha1);\n+\treturn !item->commit;\n }\n \n-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n-\t\t\tstruct replay_opts *opts)\n+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n {\n-\tstruct commit_list **next = todo_list;\n-\tstruct commit *commit;\n+\tstruct todo_item *item;\n \tchar *p = buf;\n-\tint i;\n+\tint i, res = 0;\n \n \tfor (i = 1; *p; i++) {\n \t\tchar *eol = strchrnul(p, '\\n');\n-\t\tcommit = parse_insn_line(p, eol, opts);\n-\t\tif (!commit)\n-\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n-\t\tnext = commit_list_append(commit, next);\n+\n+\t\titem = append_todo(todo_list);\n+\t\titem->offset_in_buf = p - todo_list->buf.buf;\n+\t\tif (parse_insn_line(item, p, eol)) {\n+\t\t\terror(\"Invalid line: %.*s\", (int)(eol - p), p);\n+\t\t\tres |= error(_(\"Could not parse line %d.\"), i);\n+\t\t\titem->command = -1;\n+\t\t}\n \t\tp = *eol ? eol + 1 : eol;\n \t}\n-\tif (!*todo_list)\n+\tif (!todo_list->nr)\n \t\treturn error(_(\"No commits parsed.\"));\n-\treturn 0;\n+\treturn res;\n }\n \n-static int read_populate_todo(struct commit_list **todo_list,\n+static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n \tconst char *todo_file = get_todo_path(opts);\n-\tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n+\tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n-\tif (strbuf_read(&buf, fd, 0) < 0) {\n+\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\tstrbuf_release(&buf);\n \t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n-\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n-\tstrbuf_release(&buf);\n+\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n@@ -848,18 +859,33 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int walk_revs_populate_todo(struct commit_list **todo_list,\n+static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n+\tenum todo_command command = opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT;\n \tstruct commit *commit;\n-\tstruct commit_list **next;\n \n \tif (prepare_revs(opts))\n \t\treturn -1;\n \n-\tnext = todo_list;\n-\twhile ((commit = get_revision(opts->revs)))\n-\t\tnext = commit_list_append(commit, next);\n+\twhile ((commit = get_revision(opts->revs))) {\n+\t\tstruct todo_item *item = append_todo(todo_list);\n+\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n+\t\tconst char *subject;\n+\t\tint subject_len;\n+\n+\t\titem->command = command;\n+\t\titem->commit = commit;\n+\t\titem->offset_in_buf = todo_list->buf.len;\n+\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n+\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n+\t\t\topts->action == REPLAY_PICK ?  \"pick\" : \"revert\",\n+\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n+\t\t\t\tDEFAULT_ABBREV),\n+\t\t\tsubject_len, subject);\n+\t\tunuse_commit_buffer(commit, commit_buffer);\n+\t}\n \treturn 0;\n }\n \n@@ -964,30 +990,24 @@ static int sequencer_rollback(struct replay_opts *opts)\n \treturn -1;\n }\n \n-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstatic struct lock_file todo_lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint fd;\n+\tconst char *todo_path = get_todo_path(opts);\n+\tint next = todo_list->current, offset, fd;\n \n-\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n+\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"),\n \t\t\t\t   git_path_todo_file());\n-\tif (format_todo(&buf, todo_list, opts) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n-\t}\n-\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n-\t\t\t\t   git_path_todo_file());\n-\t}\n-\tif (commit_lock_file(&todo_lock) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n-\t}\n-\tstrbuf_release(&buf);\n+\toffset = next < todo_list->nr ?\n+\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n+\tif (write_in_full(fd, todo_list->buf.buf + offset,\n+\t\t\ttodo_list->buf.len - offset) < 0)\n+\t\treturn error(_(\"Could not write to %s (%s)\"),\n+\t\t\ttodo_path, strerror(errno));\n+\tif (commit_lock_file(&todo_lock) < 0)\n+\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1026,9 +1046,8 @@ static int save_opts(struct replay_opts *opts)\n \treturn res;\n }\n \n-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *cur;\n \tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n@@ -1038,10 +1057,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tif (save_todo(cur, opts))\n+\twhile (todo_list->current < todo_list->nr) {\n+\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n+\t\tif (save_todo(todo_list, opts))\n \t\t\treturn -1;\n-\t\tres = do_pick_commit(cur->item, opts);\n+\t\tres = do_pick_commit(item->command, item->commit, opts);\n+\t\ttodo_list->current++;\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -1066,7 +1087,8 @@ static int continue_single_pick(void)\n \n static int sequencer_continue(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n \n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n@@ -1083,21 +1105,24 @@ static int sequencer_continue(struct replay_opts *opts)\n \t}\n \tif (index_differs_from(\"HEAD\", 0))\n \t\treturn error_dirty_index(opts);\n-\ttodo_list = todo_list->next;\n-\treturn pick_commits(todo_list, opts);\n+\ttodo_list.current++;\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n static int single_pick(struct commit *cmit, struct replay_opts *opts)\n {\n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(cmit, opts);\n+\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n }\n \n int sequencer_pick_revisions(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n \tunsigned char sha1[20];\n-\tint i;\n+\tint i, res;\n \n \tif (opts->subcommand == REPLAY_NONE)\n \t\tassert(opts->revs);\n@@ -1171,7 +1196,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tif (save_head(sha1_to_hex(sha1)) ||\n \t\t\tsave_opts(opts))\n \t\treturn -1;\n-\treturn pick_commits(todo_list, opts);\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300420","messageId":"1e940c58329ff5f224ec5bc48927a28ff4d1bf66.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 10/22] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:05:34Z","receivedAt":"2016-08-29T08:05:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cbdce6d..1b65202 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -232,11 +232,8 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(action_name(opts));\n \n-\t/* Different translation strings for cherry-pick and revert */\n-\tif (opts->action == REPLAY_PICK)\n-\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n-\telse\n-\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n+\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\t\taction_name(opts));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300421","messageId":"12bffd6ca4eb7acc00a102d13348bb96ad08371d.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:05:57Z","receivedAt":"2016-08-29T08:06:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The `git-rebase-todo` file contains a list of commands. Most of those\ncommands have the form\n\n\t<verb> <sha1> <oneline>\n\nThe <oneline> is displayed primarily for the user's convenience, as\nrebase -i really interprets only the <verb> <sha1> part. However, there\nare *some* places in interactive rebase where the <oneline> is used to\ndisplay messages, e.g. for reporting at which commit we stopped.\n\nSo let's just remember it when parsing the todo file; we keep a copy of\nthe entire todo file anyway (to write out the new `done` and\n`git-rebase-todo` file just before processing each command), so all we\nneed to do is remember the begin and end offsets.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 06759d4..3398774 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n struct todo_item {\n \tenum todo_command command;\n \tstruct commit *commit;\n+\tconst char *arg;\n+\tint arg_len;\n \tsize_t offset_in_buf;\n };\n \n@@ -760,6 +762,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n+\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n+\titem->arg_len = (int)(eol - item->arg);\n+\n \tif (status < 0)\n \t\treturn -1;\n \n@@ -880,6 +885,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \n \t\titem->command = command;\n \t\titem->commit = commit;\n+\t\titem->arg = NULL;\n+\t\titem->arg_len = 0;\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300422","messageId":"1d83fa095c03eac9abfd1038ff7791bae8ace984.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:01Z","receivedAt":"2016-08-29T08:06:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In interactive rebases, we commit a little bit differently than the\nsequencer did so far: we heed the \"author-script\", the \"message\" and\nthe \"amend\" files in the .git/rebase-merge/ subdirectory.\n\nLikewise, we may want to edit the commit message *even* when providing\na file containing the suggested commit message. Therefore we change the\ncode to not even provide a default message when we do not want any, and\nto call the editor explicitly.\n\nAs interactive rebase's GPG settings are configured differently from\nhow cherry-pick (and therefore sequencer) handles them, we will leave\nsupport for that to the next commit.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------\n sequencer.h |  3 ++\n 2 files changed, 83 insertions(+), 12 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 3398774..b124980 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,16 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+/*\n+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n+ * GIT_AUTHOR_DATE that will be used for the commit that is currently\n+ * being rebased.\n+ */\n+static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+\n+/* We will introduce the 'interactive rebase' mode later */\n+#define IS_REBASE_I() 0\n+\n static const char *get_dir(const struct replay_opts *opts)\n {\n \treturn git_path_seq_dir();\n@@ -377,20 +387,72 @@ static int is_index_unchanged(void)\n \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n }\n \n+static char **read_author_script(void)\n+{\n+\tstruct strbuf script = STRBUF_INIT;\n+\tint i, count = 0;\n+\tchar *p, *p2, **env;\n+\tsize_t env_size;\n+\n+\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n+\t\treturn NULL;\n+\n+\tfor (p = script.buf; *p; p++)\n+\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n+\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n+\t\telse if (*p == '\\'')\n+\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n+\t\telse if (*p == '\\n') {\n+\t\t\t*p = '\\0';\n+\t\t\tcount++;\n+\t\t}\n+\n+\tenv_size = (count + 1) * sizeof(*env);\n+\tstrbuf_grow(&script, env_size);\n+\tmemmove(script.buf + env_size, script.buf, script.len);\n+\tp = script.buf + env_size;\n+\tenv = (char **)strbuf_detach(&script, NULL);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tenv[i] = p;\n+\t\tp += strlen(p) + 1;\n+\t}\n+\tenv[count] = NULL;\n+\n+\treturn env;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n  * author date and name.\n  * If we are revert, or if our cherry-pick results in a hand merge,\n- * we had better say that the current user is responsible for that.\n+ * we had better say that the current user is responsible for that\n+ * (except, of course, while running an interactive rebase).\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n+int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\t\t  int allow_empty)\n {\n+\tchar **env = NULL;\n \tstruct argv_array array;\n \tint rc;\n \tconst char *value;\n \n+\tif (IS_REBASE_I()) {\n+\t\tenv = read_author_script();\n+\t\tif (!env)\n+\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\t\t\"tree. If these changes are meant to be\\n\"\n+\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n+\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"If they are meant to go into a new commit, \"\n+\t\t\t\t\"run:\\n\\n\"\n+\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"In both case, once you're done, continue \"\n+\t\t\t\t\"with:\\n\\n\"\n+\t\t\t\t\"  git rebase --continue\\n\");\n+\t}\n+\n \targv_array_init(&array);\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n@@ -399,14 +461,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n \t\targv_array_push(&array, \"-s\");\n-\tif (!opts->edit) {\n-\t\targv_array_push(&array, \"-F\");\n-\t\targv_array_push(&array, defmsg);\n-\t\tif (!opts->signoff &&\n-\t\t    !opts->record_origin &&\n-\t\t    git_config_get_value(\"commit.cleanup\", &value))\n-\t\t\targv_array_push(&array, \"--cleanup=verbatim\");\n-\t}\n+\tif (defmsg)\n+\t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (opts->edit)\n+\t\targv_array_push(&array, \"-e\");\n+\telse if (!opts->signoff && !opts->record_origin &&\n+\t\t git_config_get_value(\"commit.cleanup\", &value))\n+\t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n \tif (allow_empty)\n \t\targv_array_push(&array, \"--allow-empty\");\n@@ -414,8 +475,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&array, \"--allow-empty-message\");\n \n-\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\trc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,\n+\t\t\t(const char *const *)env);\n \targv_array_clear(&array);\n+\tfree(env);\n+\n \treturn rc;\n }\n \n@@ -664,7 +728,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = run_git_commit(git_path_merge_msg(), opts, allow);\n+\t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\t\topts, allow);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -859,6 +924,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n+\tif (IS_REBASE_I())\n+\t\treturn 0;\n+\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\ndiff --git a/sequencer.h b/sequencer.h\nindex 674f11e..9f63c31 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -49,6 +49,9 @@ int sequencer_continue(struct replay_opts *opts);\n int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n+int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n+\t\t\t  int allow_empty);\n+\n extern const char sign_off_header[];\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300423","messageId":"c6a37af958f59390c00429a5b38b34d34c9a5b95.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:08Z","receivedAt":"2016-08-29T08:06:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The rebase command sports a `--gpg-sign` option that is heeded by the\ninteractive rebase.\n\nThis patch teaches the sequencer that trick, as part of the bigger\neffort to make the sequencer the work horse of the interactive rebase.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 48 +++++++++++++++++++++++++++++++++++++++++++-----\n 1 file changed, 43 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 4204cc8..e094ac2 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -15,6 +15,7 @@\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n #include \"argv-array.h\"\n+#include \"quote.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n  * being rebased.\n  */\n static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+/*\n+ * The following files are written by git-rebase just after parsing the\n+ * command-line (and are only consumed, not modified, by the sequencer).\n+ */\n+static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n \n /* We will introduce the 'interactive rebase' mode later */\n #define IS_REBASE_I() 0\n@@ -129,6 +135,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n+{\n+\tstatic struct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_reset(&buf);\n+\tif (opts->gpg_sign)\n+\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n+\treturn buf.buf;\n+}\n+\n void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n {\n \tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n@@ -471,17 +487,20 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \n \tif (IS_REBASE_I()) {\n \t\tenv = read_author_script();\n-\t\tif (!env)\n+\t\tif (!env) {\n+\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\n \t\t\treturn error(\"You have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit --amend %s\\n\\n\"\n \t\t\t\t\"If they are meant to go into a new commit, \"\n \t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit %s\\n\\n\"\n \t\t\t\t\"In both case, once you're done, continue \"\n \t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\");\n+\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t}\n \t}\n \n \targv_array_init(&array);\n@@ -955,8 +974,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n-\tif (IS_REBASE_I())\n+\tif (IS_REBASE_I()) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n+\t\t\tif (buf.len && buf.buf[buf.len - 1] == '\\n') {\n+\t\t\t\tif (--buf.len &&\n+\t\t\t\t    buf.buf[buf.len - 1] == '\\r')\n+\t\t\t\t\tbuf.len--;\n+\t\t\t\tbuf.buf[buf.len] = '\\0';\n+\t\t\t}\n+\n+\t\t\tif (!starts_with(buf.buf, \"-S\"))\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\telse {\n+\t\t\t\topts->gpg_sign = buf.buf + 2;\n+\t\t\t\tstrbuf_detach(&buf, NULL);\n+\t\t\t}\n+\t\t}\n+\n \t\treturn 0;\n+\t}\n \n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300424","messageId":"c0c7caa40a452ed9328c21302e4399562d40ec12.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 15/22] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:05Z","receivedAt":"2016-08-29T08:06:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As we are slowly teaching the sequencer to perform the hard work for\nthe interactive rebase, we need to read files that were written by\nshell scripts.\n\nThese files typically contain a single line and are invariably ended\nby a line feed (and possibly a carriage return before that). Let's use\na helper to read such files and to remove the line ending.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 31 +++++++++++++++++++++++++++++++\n 1 file changed, 31 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b124980..4204cc8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -239,6 +239,37 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \treturn 0;\n }\n \n+/*\n+ * Reads a file that was presumably written by a shell script, i.e.\n+ * with an end-of-line marker that needs to be stripped.\n+ *\n+ * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n+ */\n+static int read_oneliner(struct strbuf *buf,\n+\tconst char *path, int skip_if_empty)\n+{\n+\tint orig_len = buf->len;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (strbuf_read_file(buf, path, 0) < 0) {\n+\t\twarning_errno(\"could not read '%s'\", path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n+\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n+\t\t\t--buf->len;\n+\t\tbuf->buf[buf->len] = '\\0';\n+\t}\n+\n+\tif (skip_if_empty && buf->len == orig_len)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static struct tree *empty_tree(void)\n {\n \treturn lookup_tree(EMPTY_TREE_SHA1_BIN);\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300425","messageId":"96adba0eee05a7b2b46b726f7e231b6732e80882.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 17/22] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:13Z","receivedAt":"2016-08-29T08:06:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In the upcoming commits, we will implement more and more of rebase\n-i's functionality. One particular feature of the commands to come is\nthat some of them allow editing the commit message while others don't,\ni.e. we cannot define in the replay_opts whether the commit message\nshould be edited or not.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n sequencer.h | 2 +-\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex e094ac2..7e17d14 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -478,7 +478,7 @@ static char **read_author_script(void)\n  * (except, of course, while running an interactive rebase).\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty)\n+\t\t\t  int allow_empty, int edit)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -513,7 +513,7 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n-\tif (opts->edit)\n+\tif (edit)\n \t\targv_array_push(&array, \"-e\");\n \telse if (!opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n@@ -779,7 +779,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow);\n+\t\t\topts, allow, opts->edit);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex 9f63c31..fd02baf 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -50,7 +50,7 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty);\n+\t\t\t  int allow_empty, int edit);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300426","messageId":"c4e474af8e6237522f4c452ca90c2e2670059e60.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 18/22] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:23Z","receivedAt":"2016-08-29T08:06:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This teaches the sequencer_commit() function to take an argument that\nwill allow us to implement \"todo\" commands that need to amend the commit\nmessages (\"fixup\", \"squash\" and \"reword\").\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 ++++--\n sequencer.h | 2 +-\n 2 files changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 7e17d14..20f7590 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -478,7 +478,7 @@ static char **read_author_script(void)\n  * (except, of course, while running an interactive rebase).\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit)\n+\t\t\t  int allow_empty, int edit, int amend)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -507,6 +507,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n \n+\tif (amend)\n+\t\targv_array_push(&array, \"--amend\");\n \tif (opts->gpg_sign)\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n@@ -779,7 +781,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow, opts->edit);\n+\t\t\topts, allow, opts->edit, 0);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex fd02baf..2106c0d 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -50,7 +50,7 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit);\n+\t\t\t  int allow_empty, int edit, int amend);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300427","messageId":"eeb3d11d235a0220a9a125a21d1b09a73d2c61dc.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 19/22] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:29Z","receivedAt":"2016-08-29T08:06:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer_commit() function already knows how to amend commits, and\nwith this new option, it can also clean up commit messages (i.e. strip\nout commented lines). This is needed to implement rebase -i's 'fixup'\nand 'squash' commands as sequencer commands.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n sequencer.h |  3 ++-\n 2 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 20f7590..5ec956f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -478,7 +478,8 @@ static char **read_author_script(void)\n  * (except, of course, while running an interactive rebase).\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend)\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -515,9 +516,12 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (cleanup_commit_message)\n+\t\targv_array_push(&array, \"--cleanup=strip\");\n \tif (edit)\n \t\targv_array_push(&array, \"-e\");\n-\telse if (!opts->signoff && !opts->record_origin &&\n+\telse if (!cleanup_commit_message &&\n+\t\t !opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n \t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n@@ -781,7 +785,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow, opts->edit, 0);\n+\t\t\topts, allow, opts->edit, 0, 0);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex 2106c0d..e272549 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -50,7 +50,8 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend);\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300428","messageId":"1f79d41e3417a0b1f0cffccc40e97f1a2c5ef987.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 20/22] sequencer: remember do_recursive_merge()'s return value","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:35Z","receivedAt":"2016-08-29T08:06:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The return value of do_recursive_merge() may be positive (indicating merge\nconflicts), se let's OR later error conditions so as not to overwrite them\nwith 0.\n\nThis is not yet a problem, but preparing for the patches to come: we will\nteach the sequencer to do rebase -i's job.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5ec956f..0614b90 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -623,7 +623,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \tconst char *base_label, *next_label;\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n-\tint res, unborn = 0, allow;\n+\tint res = 0, unborn = 0, allow;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -734,7 +734,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \n \tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n-\t\tres = do_recursive_merge(base, next, base_label, next_label,\n+\t\tres |= do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n \t\t\treturn res;\n@@ -743,7 +743,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tstruct commit_list *common = NULL;\n \t\tstruct commit_list *remotes = NULL;\n \n-\t\tres = write_message(&msgbuf, git_path_merge_msg());\n+\t\tres |= write_message(&msgbuf, git_path_merge_msg());\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n@@ -780,11 +780,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \n \tallow = allow_empty(opts, commit);\n \tif (allow < 0) {\n-\t\tres = allow;\n+\t\tres |= allow;\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\tres |= sequencer_commit(opts->edit ?\n+\t\t\t\tNULL : git_path_merge_msg(),\n \t\t\topts, allow, opts->edit, 0, 0);\n \n leave:\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300429","messageId":"4b99922194d97f012459a473da48ec31d18c687f.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 12/22] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:05:48Z","receivedAt":"2016-08-29T08:06:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ba1fd05..06759d4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -157,13 +157,18 @@ struct commit_message {\n \tconst char *message;\n };\n \n+static const char *short_commit_name(struct commit *commit)\n+{\n+\treturn find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+}\n+\n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n \tint subject_len;\n \n \tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n-\tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+\tabbrev = short_commit_name(commit);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n@@ -647,8 +652,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n-\t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n-\t\t      msg.subject);\n+\t\t      short_commit_name(commit), msg.subject);\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t\tgoto leave;\n@@ -880,9 +884,7 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n \t\t\topts->action == REPLAY_PICK ?  \"pick\" : \"revert\",\n-\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n-\t\t\t\tDEFAULT_ABBREV),\n-\t\t\tsubject_len, subject);\n+\t\t\tshort_commit_name(commit), subject_len, subject);\n \t\tunuse_commit_buffer(commit, commit_buffer);\n \t}\n \treturn 0;\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300430","messageId":"cb4253698ae3eca066c031e0aec4e83ede1fa3e5.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 22/22] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:46Z","receivedAt":"2016-08-29T08:06:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The write_message() function safely writes an strbuf to a file.\nSometimes this is inconvenient, though: the text to be written may not\nbe stored in a strbuf, or the strbuf should not be released after\nwriting.\n\nLet's allow for such use cases by refactoring write_message() to allow\nfor a convenience function write_file_gently(). As some of the upcoming\ncallers of that new function will want to append a newline character,\nlet's just add a flag for that, too.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 21 ++++++++++++++++++---\n 1 file changed, 18 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5efed2e..f5b5e5e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -239,22 +239,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(struct strbuf *msgbuf, const char *filename)\n+static int write_with_lock_file(const char *filename,\n+\t\t\t\tconst void *buf, size_t len, int append_eol)\n {\n \tstatic struct lock_file msg_file;\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n+\tif (write_in_full(msg_fd, buf, len) < 0)\n \t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tstrbuf_release(msgbuf);\n+\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n+\t\treturn error_errno(_(\"Could not write eol to %s\"), filename);\n \tif (commit_lock_file(&msg_file) < 0)\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n \n \treturn 0;\n }\n \n+static int write_message(struct strbuf *msgbuf, const char *filename)\n+{\n+\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n+\tstrbuf_release(msgbuf);\n+\treturn res;\n+}\n+\n+static int write_file_gently(const char *filename,\n+\t\t\t     const char *text, int append_eol)\n+{\n+\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n+}\n+\n /*\n  * Reads a file that was presumably written by a shell script, i.e.\n  * with an end-of-line marker that needs to be stripped.\n-- \n2.10.0.rc1.114.g2bd6b38\n"},{"id":"300431","messageId":"8c30113a920e075e5ecd68ba31b4007de3e2dbc2.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:06:41Z","receivedAt":"2016-08-29T08:07:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Interactive rebase's scripts may be indented; We need to handle this\ncase, too, now that we prepare the sequencer to process interactive\nrebases.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 0614b90..5efed2e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -864,6 +864,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tchar *end_of_object_name;\n \tint i, saved, status, padding;\n \n+\t/* left-trim */\n+\tbol += strspn(bol, \" \\t\");\n+\n \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n \t\t\titem->command = i;\n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300432","messageId":"258635d3aa7f70cb1b20ea722e10ad439406b31e.1472457609.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH 11/22] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T08:05:43Z","receivedAt":"2016-08-29T08:07:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The subcommands are used exactly once, at the very beginning of\nsequencer_pick_revisions(), to determine what to do. This is an\nunnecessary level of indirection: we can simply call the correct\nfunction to begin with. So let's do that.\n\nWhile at it, ensure that the subcommands return an error code so that\nthey do not have to die() all over the place (bad practice for library\nfunctions...).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 36 ++++++++++++++++--------------------\n sequencer.c      | 35 +++++++++++------------------------\n sequencer.h      | 13 ++++---------\n 3 files changed, 31 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 7365559..c9ae4dc 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \t\tdie(_(\"%s: %s cannot be used with %s\"), me, this_opt, base_opt);\n }\n \n-static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n+static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tconst char *me = action_name(opts);\n@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n-\t/* Set the subcommand */\n-\tif (cmd == 'q')\n-\t\topts->subcommand = REPLAY_REMOVE_STATE;\n-\telse if (cmd == 'c')\n-\t\topts->subcommand = REPLAY_CONTINUE;\n-\telse if (cmd == 'a')\n-\t\topts->subcommand = REPLAY_ROLLBACK;\n-\telse\n-\t\topts->subcommand = REPLAY_NONE;\n-\n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\tchar *this_operation;\n-\t\tif (opts->subcommand == REPLAY_REMOVE_STATE)\n+\t\tif (cmd == 'q')\n \t\t\tthis_operation = \"--quit\";\n-\t\telse if (opts->subcommand == REPLAY_CONTINUE)\n+\t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n \t\telse {\n-\t\t\tassert(opts->subcommand == REPLAY_ROLLBACK);\n+\t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n \t\t}\n \n@@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--edit\", opts->edit,\n \t\t\t\tNULL);\n \n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\topts->revs = NULL;\n \t} else {\n \t\tstruct setup_revision_opt s_r_opt;\n@@ -174,6 +164,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n \tif (argc > 1)\n \t\tusage_with_options(usage_str, options);\n+\n+\tif (cmd == 'q')\n+\t\treturn sequencer_remove_state(opts);\n+\tif (cmd == 'c')\n+\t\treturn sequencer_continue(opts);\n+\tif (cmd == 'a')\n+\t\treturn sequencer_rollback(opts);\n+\treturn sequencer_pick_revisions(opts);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n@@ -185,8 +183,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -199,8 +196,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\ndiff --git a/sequencer.c b/sequencer.c\nindex 1b65202..ba1fd05 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -127,7 +127,7 @@ void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n \treturn set_me_free_after_use;\n }\n \n-static void remove_sequencer_state(const struct replay_opts *opts)\n+int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tint i;\n@@ -141,6 +141,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n+\n+\treturn 0;\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -941,7 +943,7 @@ static int rollback_single_pick(void)\n \treturn reset_for_rollback(head_sha1);\n }\n \n-static int sequencer_rollback(struct replay_opts *opts)\n+int sequencer_rollback(struct replay_opts *opts)\n {\n \tFILE *f;\n \tunsigned char sha1[20];\n@@ -979,9 +981,8 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n fail:\n \tstrbuf_release(&buf);\n \treturn -1;\n@@ -1068,8 +1069,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state(opts);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n }\n \n static int continue_single_pick(void)\n@@ -1082,11 +1082,14 @@ static int continue_single_pick(void)\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n \n-static int sequencer_continue(struct replay_opts *opts)\n+int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tint res;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n@@ -1121,26 +1124,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tint i, res;\n \n-\tif (opts->subcommand == REPLAY_NONE)\n-\t\tassert(opts->revs);\n-\n+\tassert(opts->revs);\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\t/*\n-\t * Decide what to do depending on the arguments; a fresh\n-\t * cherry-pick should be handled differently from an existing\n-\t * one that is being continued\n-\t */\n-\tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state(opts);\n-\t\treturn 0;\n-\t}\n-\tif (opts->subcommand == REPLAY_ROLLBACK)\n-\t\treturn sequencer_rollback(opts);\n-\tif (opts->subcommand == REPLAY_CONTINUE)\n-\t\treturn sequencer_continue(opts);\n-\n \tfor (i = 0; i < opts->revs->pending.nr; i++) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = opts->revs->pending.objects[i].name;\ndiff --git a/sequencer.h b/sequencer.h\nindex 20b708a..674f11e 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -10,16 +10,8 @@ enum replay_action {\n \tREPLAY_PICK\n };\n \n-enum replay_subcommand {\n-\tREPLAY_NONE,\n-\tREPLAY_REMOVE_STATE,\n-\tREPLAY_CONTINUE,\n-\tREPLAY_ROLLBACK\n-};\n-\n struct replay_opts {\n \tenum replay_action action;\n-\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -48,11 +40,14 @@ struct replay_opts {\n \tvoid **owned;\n \tint owned_nr, owned_alloc;\n };\n-#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n+#define REPLAY_OPTS_INIT { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n \n void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use);\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n+int sequencer_continue(struct replay_opts *opts);\n+int sequencer_rollback(struct replay_opts *opts);\n+int sequencer_remove_state(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.rc1.114.g2bd6b38\n\n\n"},{"id":"300434","messageId":"1472462360.4265.21.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"66d69469a64bd80d3bf2b99a250ae04a649d94d1.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 01/22] sequencer: use static initializers for replay_opts","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:19:20Z","receivedAt":"2016-08-29T09:19:30Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n\n> +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n\nThis looked off to me, as it replaces memset(..., 0, ...) so is not\n100% equivalent. But the changed functions both set opts.action and\ncall parse_args which sets opts.subcommand.\n\nD.\n"},{"id":"300435","messageId":"1472462696.4265.23.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"2245e7db4d4c028f63b2f4c41097559f91756f2c.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 04/22] sequencer: future-proof remove_sequencer_state()","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:24:56Z","receivedAt":"2016-08-29T09:25:56Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:04 +0200, Johannes Schindelin wrote:\n\n> +       if (read_and_refresh_cache(opts))\n> +               return -1;\n> +\n\nThis doesn't seem to be related to the get_dir changes?\n\nD.\n"},{"id":"300436","messageId":"1472463570.4265.24.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"4b99922194d97f012459a473da48ec31d18c687f.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 12/22] sequencer: refactor the code to obtain a short commit name","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:39:30Z","receivedAt":"2016-08-29T09:40:34Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:05 +0200, Johannes Schindelin wrote:\n\n<snip actual commit>\n\nI fail to see the point of this patch, would you mind enlightening me?\n\nD.\n"},{"id":"300439","messageId":"1472464060.4265.27.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"c0c7caa40a452ed9328c21302e4399562d40ec12.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 15/22] sequencer: introduce a helper to read files written by scripts","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:47:40Z","receivedAt":"2016-08-29T09:47:53Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:06 +0200, Johannes Schindelin wrote:\n> +       if (strbuf_read_file(buf, path, 0) < 0) {\n> +               warning_errno(\"could not read '%s'\", path);\n> +               return 0;\n> +       }\n> +\n> +       if (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n> +               if (--buf->len > orig_len && buf->buf[buf->len - 1]\n> == '\\r')\n> +                       --buf->len;\n> +               buf->buf[buf->len] = '\\0';\n> +       }\n\nWhy not use open + strbuf_getline instead of hand-rolling a newline\neradicator?\n\nD.\n"},{"id":"300441","messageId":"1472464293.4265.28.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"1f79d41e3417a0b1f0cffccc40e97f1a2c5ef987.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 20/22] sequencer: remember do_recursive_merge()'s return value","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:51:33Z","receivedAt":"2016-08-29T09:51:56Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:06 +0200, Johannes Schindelin wrote:\n\n> The return value of do_recursive_merge() may be positive (indicating merge\n> conflicts), se let's OR later error conditions so as not to overwrite them\n> with 0.\n\ns/se/so/?\n\nD.\n"},{"id":"300442","messageId":"1472464596.4265.29.camel@kaarsemaker.net","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 00/22] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-08-29T09:56:36Z","receivedAt":"2016-08-29T09:57:22Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n\n> Therefore I would be most grateful for every in-depth review.\n\nTried to do that, but could come up only with a few nits. I think the\napproach is sensible.\n\nD.\n"},{"id":"300447","messageId":"alpine.DEB.2.20.1608291254240.129229@virtualbox","threadId":"43954","inReplyTo":"1472462360.4265.21.camel@kaarsemaker.net","subject":"Re: [PATCH 01/22] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T10:54:43Z","receivedAt":"2016-08-29T10:54:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n> \n> > +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n> \n> This looked off to me, as it replaces memset(..., 0, ...) so is not\n> 100% equivalent. But the changed functions both set opts.action and\n> call parse_args which sets opts.subcommand.\n\nOkay... Do you want me to change anything?\n\nCiao,\nDscho\n"},{"id":"300448","messageId":"alpine.DEB.2.20.1608291258280.129229@virtualbox","threadId":"43954","inReplyTo":"1472462696.4265.23.camel@kaarsemaker.net","subject":"Re: [PATCH 04/22] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T10:58:54Z","receivedAt":"2016-08-29T10:59:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:04 +0200, Johannes Schindelin wrote:\n> \n> > +       if (read_and_refresh_cache(opts))\n> > +               return -1;\n> > +\n> \n> This doesn't seem to be related to the get_dir changes?\n\nGood eyes.\n\nLet me investigate why I have it here...\n\nCiao,\nDscho"},{"id":"300449","messageId":"alpine.DEB.2.20.1608291301350.129229@virtualbox","threadId":"43954","inReplyTo":"1472463570.4265.24.camel@kaarsemaker.net","subject":"Re: [PATCH 12/22] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T11:04:10Z","receivedAt":"2016-08-29T11:04:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:05 +0200, Johannes Schindelin wrote:\n> \n> <snip actual commit>\n> \n> I fail to see the point of this patch, would you mind enlightening me?\n\nTwo reasons:\n\n1) by refactoring it into a function, the code is more DRY (with all the\nadvantages that come with it, such as: only a single point to change if\nchanging the behavior)\n\n2) it is easier to reuse the code in upcoming patches (that would be in\nthe next patch series)\n\nWill amend the commit message.\n\nCiao,\nDscho\n"},{"id":"300450","messageId":"alpine.DEB.2.20.1608291307560.129229@virtualbox","threadId":"43954","inReplyTo":"1472464060.4265.27.camel@kaarsemaker.net","subject":"Re: [PATCH 15/22] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T11:08:30Z","receivedAt":"2016-08-29T11:08:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:06 +0200, Johannes Schindelin wrote:\n> > +       if (strbuf_read_file(buf, path, 0) < 0) {\n> > +               warning_errno(\"could not read '%s'\", path);\n> > +               return 0;\n> > +       }\n> > +\n> > +       if (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n> > +               if (--buf->len > orig_len && buf->buf[buf->len - 1]\n> > == '\\r')\n> > +                       --buf->len;\n> > +               buf->buf[buf->len] = '\\0';\n> > +       }\n> \n> Why not use open + strbuf_getline instead of hand-rolling a newline\n> eradicator?\n\nBecause strbuf_getline() erases the strbuf instead of appending to it\n(which is what we sometimes need when converting shell scripts to C).\n\nCiao,\nDscho"},{"id":"300451","messageId":"alpine.DEB.2.20.1608291309280.129229@virtualbox","threadId":"43954","inReplyTo":"1472464293.4265.28.camel@kaarsemaker.net","subject":"Re: [PATCH 20/22] sequencer: remember do_recursive_merge()'s return value","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T11:09:38Z","receivedAt":"2016-08-29T11:10:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:06 +0200, Johannes Schindelin wrote:\n> \n> > The return value of do_recursive_merge() may be positive (indicating merge\n> > conflicts), se let's OR later error conditions so as not to overwrite them\n> > with 0.\n> \n> s/se/so/?\n\nGood eyes.\n\nFixed,\nDscho\n"},{"id":"300452","messageId":"alpine.DEB.2.20.1608291309480.129229@virtualbox","threadId":"43954","inReplyTo":"1472464596.4265.29.camel@kaarsemaker.net","subject":"Re: [PATCH 00/22] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T11:10:08Z","receivedAt":"2016-08-29T11:11:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n\n> On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n> \n> > Therefore I would be most grateful for every in-depth review.\n> \n> Tried to do that, but could come up only with a few nits. I think the\n> approach is sensible.\n\nThank you for the review!\n\nCiao,\nDscho\n"},{"id":"300453","messageId":"alpine.DEB.2.20.1608291317370.129229@virtualbox","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608291258280.129229@virtualbox","subject":"Re: [PATCH 04/22] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T11:19:32Z","receivedAt":"2016-08-29T11:20:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dennis,\n\nOn Mon, 29 Aug 2016, Johannes Schindelin wrote:\n\n> On Mon, 29 Aug 2016, Dennis Kaarsemaker wrote:\n> \n> > On ma, 2016-08-29 at 10:04 +0200, Johannes Schindelin wrote:\n> > \n> > > +       if (read_and_refresh_cache(opts))\n> > > +               return -1;\n> > > +\n> > \n> > This doesn't seem to be related to the get_dir changes?\n> \n> Good eyes.\n> \n> Let me investigate why I have it here...\n\nUnfortunately my reflogs got corrupted by the git-worktree\nimplementations, so I cannot back that far.\n\nLooking at the code, and after running the tests, I am convinced that it\nis a leftover of some misguided attempt to implement \"git rebase -i\n--abort\" in sequencer_rollback().\n\nI removed this hunk from the patch.\n\nAgain, Thank you so much for your review!\nDscho"},{"id":"300472","messageId":"8c36fb5f-42a2-e4a7-1b7d-c8e60de593e4@gmail.com","threadId":"43954","inReplyTo":"1472462360.4265.21.camel@kaarsemaker.net","subject":"Re: [PATCH 01/22] sequencer: use static initializers for replay_opts","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-29T17:41:01Z","receivedAt":"2016-08-29T17:41:28Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 11:19, Dennis Kaarsemaker pisze:\n> On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n> \n>> +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n> \n> This looked off to me, as it replaces memset(..., 0, ...) so is not\n> 100% equivalent. But the changed functions both set opts.action and\n> call parse_args which sets opts.subcommand.\n\nThis information would be nice to have in the commit message.\n\n-- \nJakub Narębski\n\n"},{"id":"300491","messageId":"10e19839-2875-2610-0af3-0b86831916f0@gmail.com","threadId":"43954","inReplyTo":"d032a9d765aaca0655b1e363e67d9bf24864396c.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 02/22] sequencer: use memoized sequencer directory path","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-29T19:54:58Z","receivedAt":"2016-08-29T19:55:14Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/commit.c |  2 +-\n>  sequencer.c      | 11 ++++++-----\n>  sequencer.h      |  5 +----\n>  3 files changed, 8 insertions(+), 10 deletions(-)\n\nJust a sidenote: it would be probably easier to read with *.h before\n*.c (at least this particular one).\n\n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 77e3dc8..0221190 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -173,7 +173,7 @@ static void determine_whence(struct wt_status *s)\n>  \t\twhence = FROM_MERGE;\n>  \telse if (file_exists(git_path_cherry_pick_head())) {\n>  \t\twhence = FROM_CHERRY_PICK;\n> -\t\tif (file_exists(git_path(SEQ_DIR)))\n> +\t\tif (file_exists(git_path_seq_dir()))\n>  \t\t\tsequencer_in_use = 1;\n>  \t}\n>  \telse\n\nSo it is more \"Use memoized sequencer directory path\" rather than\n\"sequencer: use memoized sequencer directory path\" - it replaces\nall occurrences of SEQ_DIR,... that's why it can be removed from\n'sequencer.h'.\n\nThough perhaps I misunderstood \"sequencer: \" prefix there.  Don't\nmind me then.\n\n> diff --git a/sequencer.c b/sequencer.c\n> index b6481bb..4d2b4e3 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -21,10 +21,11 @@\n>  const char sign_off_header[] = \"Signed-off-by: \";\n>  static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n>  \n> -static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n> -static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n> -static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n> -static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n> +GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n> +\n> +static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n> +static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n> +static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n\nThis also makes the ordering of memoized-path variables more\nsensible.  Good work.\n\n>  \n>  static int is_rfc2822_line(const char *buf, int len)\n>  {\n> @@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n>  {\n>  \tstruct strbuf seq_dir = STRBUF_INIT;\n>  \n> -\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n> +\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n>  \tremove_dir_recursively(&seq_dir, 0);\n>  \tstrbuf_release(&seq_dir);\n>  }\n> diff --git a/sequencer.h b/sequencer.h\n> index 2ca096b..c955594 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -1,10 +1,7 @@\n>  #ifndef SEQUENCER_H\n>  #define SEQUENCER_H\n>  \n> -#define SEQ_DIR\t\t\"sequencer\"\n> -#define SEQ_HEAD_FILE\t\"sequencer/head\"\n> -#define SEQ_TODO_FILE\t\"sequencer/todo\"\n> -#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n> +const char *git_path_seq_dir(void);\n\nRight, I see this matches other git_path_*() functions declared in cache.h\n\n>  \n>  #define APPEND_SIGNOFF_DEDUP (1u << 0)\n>  \n> \n\n"},{"id":"300495","messageId":"90d26cba-0013-eb31-ba40-52f3e2f9d239@gmail.com","threadId":"43954","inReplyTo":"e5e6c27038c7db226a787da6b7ee343b2b310654.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 03/22] sequencer: avoid unnecessary indirection","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-29T20:22:51Z","receivedAt":"2016-08-29T20:24:00Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n\n> We really do not need the *pointer to a* pointer to the options in\n> the read_populate_opts() function.\n\nRight.\n \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 4d2b4e3..14ef79b 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -809,11 +809,11 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  \treturn 0;\n>  }\n>  \n> -static int read_populate_opts(struct replay_opts **opts)\n> +static int read_populate_opts(struct replay_opts *opts)\n\nEspecially that other *_populate_*() use 'struct replay_opts *opts':\n\n   read_populate_todo(struct commit_list **todo_list, struct replay_opts *opts)\n   walk_revs_populate_todo(struct commit_list **todo_list, struct replay_opts *opts)\n\nThough they use **todo_list, because they modify this list;\nmaybe that was why read_populate_opts was using **opts instead\nof *opts?\n\n>  {\n>  \tif (!file_exists(git_path_opts_file()))\n>  \t\treturn 0;\n> -\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n> +\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n>  \t\treturn error(_(\"Malformed options sheet: %s\"),\n>  \t\t\tgit_path_opts_file());\n>  \treturn 0;\n> @@ -1038,7 +1038,7 @@ static int sequencer_continue(struct replay_opts *opts)\n>  \n>  \tif (!file_exists(git_path_todo_file()))\n>  \t\treturn continue_single_pick();\n> -\tif (read_populate_opts(&opts) ||\n> +\tif (read_populate_opts(opts) ||\n>  \t\t\tread_populate_todo(&todo_list, opts))\n>  \t\treturn -1;\n>  \n> \n\n"},{"id":"300497","messageId":"99fd1126-53d1-36e4-facd-7e18ba06e3c0@gmail.com","threadId":"43954","inReplyTo":"1f79d41e3417a0b1f0cffccc40e97f1a2c5ef987.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 20/22] sequencer: remember do_recursive_merge()'s return value","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-29T20:32:40Z","receivedAt":"2016-08-29T20:32:57Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> diff --git a/sequencer.c b/sequencer.c\n> index 5ec956f..0614b90 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -623,7 +623,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \tconst char *base_label, *next_label;\n>  \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n>  \tstruct strbuf msgbuf = STRBUF_INIT;\n> -\tint res, unborn = 0, allow;\n> +\tint res = 0, unborn = 0, allow;\n\nNot that I am against this part of change, making initialization\nexplicit, but why we are initializing automatic variables with 0,\nwhich would be the default value anyway?  I thought our coding\nguidelines discourage initializing with 0 or NULL...\n\nPuzzled,\n-- \nJakub Narębski\n\n"},{"id":"300507","messageId":"xmqqlgzf8ej7.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"99fd1126-53d1-36e4-facd-7e18ba06e3c0@gmail.com","subject":"Re: [PATCH 20/22] sequencer: remember do_recursive_merge()'s return value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T21:13:16Z","receivedAt":"2016-08-29T21:13:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n>\n>> diff --git a/sequencer.c b/sequencer.c\n>> index 5ec956f..0614b90 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\n>> @@ -623,7 +623,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>>  \tconst char *base_label, *next_label;\n>>  \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n>>  \tstruct strbuf msgbuf = STRBUF_INIT;\n>> -\tint res, unborn = 0, allow;\n>> +\tint res = 0, unborn = 0, allow;\n>\n> Not that I am against this part of change, making initialization\n> explicit, but why we are initializing automatic variables with 0,\n> which would be the default value anyway?\n\nBecause an on-stack \"auto\" begins its life with an undefined value,\nunlike a file-scope static (and global variables) that can be in BSS\nsegment.\n\n> I thought our coding\n> guidelines discourage initializing with 0 or NULL...\n\nYou are confused between the two, I am afraid.\n\n"},{"id":"300513","messageId":"xmqq8tvf8dmz.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"1d83fa095c03eac9abfd1038ff7791bae8ace984.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T21:32:36Z","receivedAt":"2016-08-29T21:32:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +/* We will introduce the 'interactive rebase' mode later */\n> +#define IS_REBASE_I() 0\n\nI do not see a point in naming this all caps.  The use site would be\na lot more pleasant to read when the reader does not have to care if\nthis is implemented as a preprocessor macro or a helper function.\n\n> @@ -377,20 +387,72 @@ static int is_index_unchanged(void)\n>  \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n>  }\n>  \n> +static char **read_author_script(void)\n> +{\n> +\tstruct strbuf script = STRBUF_INIT;\n> +\tint i, count = 0;\n> +\tchar *p, *p2, **env;\n> +\tsize_t env_size;\n> +\n> +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n> +\t\treturn NULL;\n> +\n> +\tfor (p = script.buf; *p; p++)\n> +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n> +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n> +\t\telse if (*p == '\\'')\n> +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n> +\t\telse if (*p == '\\n') {\n> +\t\t\t*p = '\\0';\n> +\t\t\tcount++;\n> +\t\t}\n\nHmph.  What is this loop doing?  Is it decoding a sq-quoted buffer\nor something?  Don't we have a helper function to do that?\n\n> +\tenv_size = (count + 1) * sizeof(*env);\n> +\tstrbuf_grow(&script, env_size);\n> +\tmemmove(script.buf + env_size, script.buf, script.len);\n> +\tp = script.buf + env_size;\n> +\tenv = (char **)strbuf_detach(&script, NULL);\n> +\n> +\tfor (i = 0; i < count; i++) {\n> +\t\tenv[i] = p;\n> +\t\tp += strlen(p) + 1;\n> +\t}\n> +\tenv[count] = NULL;\n> +\n> +\treturn env;\n> +}\n> +\n>  /*\n>   * If we are cherry-pick, and if the merge did not result in\n>   * hand-editing, we will hit this commit and inherit the original\n>   * author date and name.\n>   * If we are revert, or if our cherry-pick results in a hand merge,\n> - * we had better say that the current user is responsible for that.\n> + * we had better say that the current user is responsible for that\n> + * (except, of course, while running an interactive rebase).\n>   */\n\nThe added \"(except, ...)\" reads as if \"even if we are reverting, if\nthat is done as part of an interactive rebase, the authorship rule\nfor a revert does not apply\".\n\nIf that is not what you meant, i.e. if you did not mean to imply\nthat \"rebase -i\" doing a revert is a normal thing, this needs to be\nrephrased to avoid the misinterpretation.\n"},{"id":"300515","messageId":"733a899a-470b-79b3-b059-b38313a7057d@gmail.com","threadId":"43954","inReplyTo":"e4e7eab3d0610faa9d3173a585902e50128d8e15.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-29T21:59:36Z","receivedAt":"2016-08-29T21:59:56Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n\n> The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> like a one-shot command when it reads its configuration: memory is\n> allocated and released only when the command exits.\n> \n> This is kind of okay for git-cherry-pick, which *is* a one-shot\n> command. All the work to make the sequencer its work horse was\n> done to allow using the functionality as a library function, though,\n> including proper clean-up after use.\n> \n> This patch introduces an API to pass the responsibility of releasing\n> certain memory to the sequencer.\n\nSo how this API would be / is meant to be used?  From the following\npatches (which I shouldn't have to read to understand this one)\nit looks like it is about strdup'ed strings from option parsing.\nOr would there be something more in the future?\n\nWould sequencer as a library function be called multiple times,\nor only once?\n\n\nI'm trying to find out how this is solved in other places of Git\ncode, and I have stumbled upon free_util in string_list...\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 13 +++++++++++++\n>  sequencer.h |  8 +++++++-\n>  2 files changed, 20 insertions(+), 1 deletion(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index c4b223b..b5be0f9 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -114,9 +114,22 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n>  \treturn 1;\n>  }\n>  \n> +void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n> +{\n> +\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n> +\topts->owned[opts->owned_nr++] = set_me_free_after_use;\n> +\n> +\treturn set_me_free_after_use;\n\nI was wondering what this 'set_me_free_after_use' parameter is about;\nwouldn't it be more readable if this parameter was called 'owned_data'\nor 'owned_ptr'?\n\n> +}\n> +\n>  static void remove_sequencer_state(const struct replay_opts *opts)\n>  {\n>  \tstruct strbuf dir = STRBUF_INIT;\n> +\tint i;\n> +\n> +\tfor (i = 0; i < opts->owned_nr; i++)\n> +\t\tfree(opts->owned[i]);\n\nI guess you can remove owned data in any order, regardless if you\nstore struct or its members first...\n\n> +\tfree(opts->owned);\n>  \n>  \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n>  \tremove_dir_recursively(&dir, 0);\n> diff --git a/sequencer.h b/sequencer.h\n> index c955594..20b708a 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -43,8 +43,14 @@ struct replay_opts {\n>  \n>  \t/* Only used by REPLAY_NONE */\n>  \tstruct rev_info *revs;\n> +\n> +\t/* malloc()ed data entrusted to the sequencer */\n> +\tvoid **owned;\n> +\tint owned_nr, owned_alloc;\n\nI'm not sure about naming conventions for those types of data, but\nwouldn't 'owned_data' be a better name?  I could be wrong here...\n\n>  };\n> -#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n> +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n\nNb. it is a pity that we cannot use named initializers for structs,\nso called designated inits.  It would make this macro more readable.\n\n> +\n> +void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use);\n>  \n>  int sequencer_pick_revisions(struct replay_opts *opts);\n>  \n> \n\n"},{"id":"300532","messageId":"e0a00df7-d4e7-3809-ae93-b29b1f1c7ea4@kdbg.org","threadId":"43954","inReplyTo":"733a899a-470b-79b3-b059-b38313a7057d@gmail.com","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-08-30T05:33:23Z","receivedAt":"2016-08-30T05:33:32Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 29.08.2016 um 23:59 schrieb Jakub Narębski:\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n>> -#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n>> +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n>\n> Nb. it is a pity that we cannot use named initializers for structs,\n> so called designated inits.  It would make this macro more readable.\n\nIt is actually pointless to add the 0's and NULL's here. This should  be \nsufficient:\n\n#define REPLAY_OPTS_INIT { -1, -1 }\n\nbecause initialization with 0 (or NULL) is the default for any omitted \nmembers.\n\n-- Hannes\n\n"},{"id":"300534","messageId":"alpine.DEB.2.20.1608291906300.129229@virtualbox","threadId":"43954","inReplyTo":"8c36fb5f-42a2-e4a7-1b7d-c8e60de593e4@gmail.com","subject":"Re: [PATCH 01/22] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T17:06:53Z","receivedAt":"2016-08-30T06:21:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Mon, 29 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 11:19, Dennis Kaarsemaker pisze:\n> > On ma, 2016-08-29 at 10:03 +0200, Johannes Schindelin wrote:\n> > \n> >> +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }\n> > \n> > This looked off to me, as it replaces memset(..., 0, ...) so is not\n> > 100% equivalent. But the changed functions both set opts.action and\n> > call parse_args which sets opts.subcommand.\n> \n> This information would be nice to have in the commit message.\n\nClarified in the commit message.\n\nCiao,\nJohannes"},{"id":"300536","messageId":"alpine.DEB.2.20.1608291908140.129229@virtualbox","threadId":"43954","inReplyTo":"10e19839-2875-2610-0af3-0b86831916f0@gmail.com","subject":"Re: [PATCH 02/22] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T17:10:58Z","receivedAt":"2016-08-30T06:25:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Mon, 29 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  builtin/commit.c |  2 +-\n> >  sequencer.c      | 11 ++++++-----\n> >  sequencer.h      |  5 +----\n> >  3 files changed, 8 insertions(+), 10 deletions(-)\n> \n> Just a sidenote: it would be probably easier to read with *.h before\n> *.c (at least this particular one).\n\nI agree, but I did not find any way to reorder this without substantial\nmanual work...\n\n> > diff --git a/builtin/commit.c b/builtin/commit.c\n> > index 77e3dc8..0221190 100644\n> > --- a/builtin/commit.c\n> > +++ b/builtin/commit.c\n> > @@ -173,7 +173,7 @@ static void determine_whence(struct wt_status *s)\n> >  \t\twhence = FROM_MERGE;\n> >  \telse if (file_exists(git_path_cherry_pick_head())) {\n> >  \t\twhence = FROM_CHERRY_PICK;\n> > -\t\tif (file_exists(git_path(SEQ_DIR)))\n> > +\t\tif (file_exists(git_path_seq_dir()))\n> >  \t\t\tsequencer_in_use = 1;\n> >  \t}\n> >  \telse\n> \n> So it is more \"Use memoized sequencer directory path\" rather than\n> \"sequencer: use memoized sequencer directory path\" - it replaces\n> all occurrences of SEQ_DIR,... that's why it can be removed from\n> 'sequencer.h'.\n> \n> Though perhaps I misunderstood \"sequencer: \" prefix there.  Don't\n> mind me then.\n\nThe idea is that this path is declared and defined in the sequencer. There\nare other call sites, too, so they have to be changed at the same time...\n\nI'd really like to keep the \"sequencer:\" prefix because it is semantically\ncorrect: this change is about the sequencer, not about the other call\nsites.\n\nCiao,\nJohannes"},{"id":"300537","messageId":"alpine.DEB.2.20.1608291913270.129229@virtualbox","threadId":"43954","inReplyTo":"90d26cba-0013-eb31-ba40-52f3e2f9d239@gmail.com","subject":"Re: [PATCH 03/22] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-29T17:15:17Z","receivedAt":"2016-08-30T06:29:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Mon, 29 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> \n> > We really do not need the *pointer to a* pointer to the options in\n> > the read_populate_opts() function.\n> \n> Right.\n>  \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 6 +++---\n> >  1 file changed, 3 insertions(+), 3 deletions(-)\n> > \n> > diff --git a/sequencer.c b/sequencer.c\n> > index 4d2b4e3..14ef79b 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -809,11 +809,11 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n> >  \treturn 0;\n> >  }\n> >  \n> > -static int read_populate_opts(struct replay_opts **opts)\n> > +static int read_populate_opts(struct replay_opts *opts)\n> \n> Especially that other *_populate_*() use 'struct replay_opts *opts':\n> \n>    read_populate_todo(struct commit_list **todo_list, struct replay_opts *opts)\n>    walk_revs_populate_todo(struct commit_list **todo_list, struct replay_opts *opts)\n> \n> Though they use **todo_list, because they modify this list;\n> maybe that was why read_populate_opts was using **opts instead\n> of *opts?\n\nI won't speculate about the reasons why it was made so.\n\nAbout read_populate_todo(): it uses **todo_list, but still only *opts.\n\nIn any case, in a later patch, the todo_list parsing is completely\nrevamped anyway, so I did not want to \"fix\" anything that would get\nreverted later on.\n\nCiao,\nJohannes"},{"id":"300539","messageId":"alpine.DEB.2.20.1608300836030.129229@virtualbox","threadId":"43954","inReplyTo":"xmqq8tvf8dmz.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T06:53:30Z","receivedAt":"2016-08-30T06:53:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 29 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +/* We will introduce the 'interactive rebase' mode later */\n> > +#define IS_REBASE_I() 0\n> \n> I do not see a point in naming this all caps.\n\nOld habit. Macros are all-caps.\n\n> The use site would be a lot more pleasant to read when the reader does\n> not have to care if this is implemented as a preprocessor macro or a\n> helper function.\n\nI converted this to a helper function.\n\n> > @@ -377,20 +387,72 @@ static int is_index_unchanged(void)\n> >  \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n> >  }\n> >  \n> > +static char **read_author_script(void)\n> > +{\n> > +\tstruct strbuf script = STRBUF_INIT;\n> > +\tint i, count = 0;\n> > +\tchar *p, *p2, **env;\n> > +\tsize_t env_size;\n> > +\n> > +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n> > +\t\treturn NULL;\n> > +\n> > +\tfor (p = script.buf; *p; p++)\n> > +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n> > +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n> > +\t\telse if (*p == '\\'')\n> > +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n> > +\t\telse if (*p == '\\n') {\n> > +\t\t\t*p = '\\0';\n> > +\t\t\tcount++;\n> > +\t\t}\n> \n> Hmph.  What is this loop doing?  Is it decoding a sq-quoted buffer\n> or something?  Don't we have a helper function to do that?\n\nWell, it is not just decoding an sq-quoted buffer, but several lines with\ndefinitions we sq-quoted ourselves, individually.\n\nThe quote.[ch] code currently has no code to dequote lines individually.\n\nAt this point, I would prefer to keep this code as-is, as I tested it over\nthe course of months and do not want to introduce regressions *now*.\n\n> > +\tenv_size = (count + 1) * sizeof(*env);\n> > +\tstrbuf_grow(&script, env_size);\n> > +\tmemmove(script.buf + env_size, script.buf, script.len);\n> > +\tp = script.buf + env_size;\n> > +\tenv = (char **)strbuf_detach(&script, NULL);\n> > +\n> > +\tfor (i = 0; i < count; i++) {\n> > +\t\tenv[i] = p;\n> > +\t\tp += strlen(p) + 1;\n> > +\t}\n> > +\tenv[count] = NULL;\n> > +\n> > +\treturn env;\n> > +}\n> > +\n> >  /*\n> >   * If we are cherry-pick, and if the merge did not result in\n> >   * hand-editing, we will hit this commit and inherit the original\n> >   * author date and name.\n> >   * If we are revert, or if our cherry-pick results in a hand merge,\n> > - * we had better say that the current user is responsible for that.\n> > + * we had better say that the current user is responsible for that\n> > + * (except, of course, while running an interactive rebase).\n> >   */\n> \n> The added \"(except, ...)\" reads as if \"even if we are reverting, if\n> that is done as part of an interactive rebase, the authorship rule\n> for a revert does not apply\".\n> \n> If that is not what you meant, i.e. if you did not mean to imply\n> that \"rebase -i\" doing a revert is a normal thing, this needs to be\n> rephrased to avoid the misinterpretation.\n\nI rephrased it.\n\nCiao,\nDscho\n"},{"id":"300540","messageId":"alpine.DEB.2.20.1608300915470.129229@virtualbox","threadId":"43954","inReplyTo":"733a899a-470b-79b3-b059-b38313a7057d@gmail.com","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T07:29:36Z","receivedAt":"2016-08-30T07:29:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Mon, 29 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> \n> > The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> > like a one-shot command when it reads its configuration: memory is\n> > allocated and released only when the command exits.\n> > \n> > This is kind of okay for git-cherry-pick, which *is* a one-shot\n> > command. All the work to make the sequencer its work horse was done to\n> > allow using the functionality as a library function, though, including\n> > proper clean-up after use.\n> > \n> > This patch introduces an API to pass the responsibility of releasing\n> > certain memory to the sequencer.\n> \n> So how this API would be / is meant to be used?\n\nI added an example to the commit message.\n\n> Would sequencer as a library function be called multiple times,\n> or only once?\n\nThe point of a library function is that it should not care.\n\n> I'm trying to find out how this is solved in other places of Git\n> code, and I have stumbled upon free_util in string_list...\n\nI wanted this to be flexible enough to take care of any type of data, not\njust strings.\n\nAnd while the string_list has a void *util field, it would be rather silly\nto add strings to a string list for the sole purpose of free()ing their\nutil fields in the end.\n\n(That was the conclusion I came to after a search of my own.)\n\n> > +void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n> > +{\n> > +\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n> > +\topts->owned[opts->owned_nr++] = set_me_free_after_use;\n> > +\n> > +\treturn set_me_free_after_use;\n> \n> I was wondering what this 'set_me_free_after_use' parameter is about;\n> wouldn't it be more readable if this parameter was called 'owned_data'\n> or 'owned_ptr'?\n\nIf I read \"owned_ptr\" as a function's parameter, I would assume that the\nassociated memory is owned by the caller. So I would be puzzled reading\nthat name.\n\n> >  static void remove_sequencer_state(const struct replay_opts *opts)\n> >  {\n> >  \tstruct strbuf dir = STRBUF_INIT;\n> > +\tint i;\n> > +\n> > +\tfor (i = 0; i < opts->owned_nr; i++)\n> > +\t\tfree(opts->owned[i]);\n> \n> I guess you can remove owned data in any order, regardless if you\n> store struct or its members first...\n\nIndeed, this is not like a C++ destructor. It's free().\n\n> > diff --git a/sequencer.h b/sequencer.h\n> > index c955594..20b708a 100644\n> > --- a/sequencer.h\n> > +++ b/sequencer.h\n> > @@ -43,8 +43,14 @@ struct replay_opts {\n> >  \n> >  \t/* Only used by REPLAY_NONE */\n> >  \tstruct rev_info *revs;\n> > +\n> > +\t/* malloc()ed data entrusted to the sequencer */\n> > +\tvoid **owned;\n> > +\tint owned_nr, owned_alloc;\n> \n> I'm not sure about naming conventions for those types of data, but\n> wouldn't 'owned_data' be a better name?  I could be wrong here...\n\nThe convention seemed to be \"void *X; int X_nr, X_alloc;\", so I stuck with\nit.\n\nThanks for your review!\nJohannes"},{"id":"300541","messageId":"alpine.DEB.2.20.1608300929420.129229@virtualbox","threadId":"43954","inReplyTo":"e0a00df7-d4e7-3809-ae93-b29b1f1c7ea4@kdbg.org","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T07:30:21Z","receivedAt":"2016-08-30T07:31:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Hannes,\n\nOn Tue, 30 Aug 2016, Johannes Sixt wrote:\n\n> Am 29.08.2016 um 23:59 schrieb Jakub Narębski:\n> > W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> > > -#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL,\n> > > NULL, NULL, 0, 0, NULL }\n> > > +#define REPLAY_OPTS_INIT { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL,\n> > > NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n> >\n> > Nb. it is a pity that we cannot use named initializers for structs,\n> > so called designated inits.  It would make this macro more readable.\n> \n> It is actually pointless to add the 0's and NULL's here. This should  be\n> sufficient:\n> \n> #define REPLAY_OPTS_INIT { -1, -1 }\n> \n> because initialization with 0 (or NULL) is the default for any omitted\n> members.\n\nD'oh. You're right. The same applies to TODO_LIST_INIT, of course.\n\nFixed,\nJohannes"},{"id":"300553","messageId":"e1cebf74-1592-5ddc-9979-eeffcbf4d788@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608300915470.129229@virtualbox","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-30T11:08:12Z","receivedAt":"2016-08-30T11:08:51Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 30.08.2016 o 09:29, Johannes Schindelin pisze:\n> On Mon, 29 Aug 2016, Jakub Narębski wrote: \n>> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n\n>>> +void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n>>> +{\n>>> +\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n>>> +\topts->owned[opts->owned_nr++] = set_me_free_after_use;\n>>> +\n>>> +\treturn set_me_free_after_use;\n>>\n>> I was wondering what this 'set_me_free_after_use' parameter is about;\n>> wouldn't it be more readable if this parameter was called 'owned_data'\n>> or 'owned_ptr'?\n> \n> If I read \"owned_ptr\" as a function's parameter, I would assume that the\n> associated memory is owned by the caller. So I would be puzzled reading\n> that name.\n\nRight.  Well, it is difficult to come up with a good name for this\nparameter that would make sense both in a declaration as an information\nfor a caller, and in the function itself as information about what it\nholds.\n\nIn my personal opinion 'set_me_free_after_use' is not the best name,\nbut I unfortunately do not have a better proposal.  Maybe 'entrust_ptr',\nor 'entrusted_data' / 'entrusted_ptr' / 'entrusted'?\n\nThere are two hard things in computer science: cache invalidation, \n*naming things*, and off-by-one errors ;-)\n\n\nP.S. It would be nice to have generic mechanism for taking custody\nof data to help libification, either at this or at lower level (on\nthe level of xstrdup, etc.), but that can safely wait.  It even should\nwait, so that we can see that this approach is a good one, before\ntrying to generalize it.  That should be not a blocker for this series,\nIMVHO.\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"300566","messageId":"9797cb9e-115c-bbea-51d2-a5d686aca514@gmail.com","threadId":"43954","inReplyTo":"e4b48a9a73ff33179556c0137caae85bfb4a48d9.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-30T14:54:52Z","receivedAt":"2016-08-30T14:55:02Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n\n> The sequencer reads options from disk and stores them in its struct\n> for use during sequencer's operations.\n> \n> With this patch, the memory is released afterwards, plugging a\n> memory leak.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 13 ++++++++++---\n>  1 file changed, 10 insertions(+), 3 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index b5be0f9..8d79091 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -131,6 +131,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n>  \t\tfree(opts->owned[i]);\n>  \tfree(opts->owned);\n>  \n> +\tfree(opts->xopts);\n> +\n\nThis looks like independent change, not related to using the\nsequencer_entrust() to store options read from disk in replay_opts\nstruct to be able to free memory afterwards.\n\nI guess you wanted to avoid one line changes...\n\n>  \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n>  \tremove_dir_recursively(&dir, 0);\n>  \tstrbuf_release(&dir);\n> @@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n\nSidenote: this patch would be easier to read if lines were reordered\nas below, but I don't think any slider heuristics could help achieve\nthat automatically.  Also, the patch might be invalid...\n\n>  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n>  \telse if (!strcmp(key, \"options.mainline\"))\n>  \t\topts->mainline = git_config_int(key, value);\n> -\telse if (!strcmp(key, \"options.strategy\"))\n> +\telse if (!strcmp(key, \"options.strategy\")) {\n>  \t\tgit_config_string(&opts->strategy, key, value);\n> +\t\tsequencer_entrust(opts, (char *) opts->strategy);\n\nI wonder if the ability to free strings dup-ed by git_config_string()\nbe something that is part of replay_opts, or rather remove_sequencer_state(),\nthat is a list of\n\n\tfree(opts->strategy);\n\tfree(opts->gpg_sign);\n\nAnd of course\n\n\tfor (i = 0; i < opts->xopts_nr; i++)\n\t\tfree(opts->xopts[i]);\n\tfree(opts->xopts);\n\nThough... free(NULL) is nop as per standard, but can we rely on it?\nIf it is a problem, we can create xfree(ptr) being if(ptr)free(ptr);\n\nThe *_entrust() mechanism is more generic, but do we use this general-ness?\nWell, it could be xstrdup or git_config_string doing entrust'ing...\n\n\n> +\t}\n> -\telse if (!strcmp(key, \"options.gpg-sign\"))\n> +\telse if (!strcmp(key, \"options.gpg-sign\")) {\n>  \t\tgit_config_string(&opts->gpg_sign, key, value);\n> +\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n> +\t}\n>  \telse if (!strcmp(key, \"options.strategy-option\")) {\n>  \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n> -\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n> +\t\topts->xopts[opts->xopts_nr++] =\n> +\t\t\tsequencer_entrust(opts, xstrdup(value));\n\nNice.\n\n>  \t} else\n>  \t\treturn error(_(\"Invalid key: %s\"), key);\n>  \n> \n\n"},{"id":"300567","messageId":"cb4402e9-6765-961d-0d67-43b74db05ef1@gmail.com","threadId":"43954","inReplyTo":"4043fd4b955d6a3bed1b187d9529d5382db5b961.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 07/22] sequencer: future-proof read_populate_todo()","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-30T16:07:50Z","receivedAt":"2016-08-30T16:08:03Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n\n> Over the next commits, we will work on improving the sequencer to the\n> point where it can process the edit script of an interactive rebase. To\n> that end, we will need to teach the sequencer to read interactive\n> rebase's todo file. In preparation, we consolidate all places where\n> that todo file is needed to call a function that we will later extend.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 18 +++++++++++-------\n>  1 file changed, 11 insertions(+), 7 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 8d79091..982b6e9 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n>  \treturn git_path_seq_dir();\n>  }\n>  \n> +static const char *get_todo_path(const struct replay_opts *opts)\n> +{\n> +\treturn git_path_todo_file();\n> +}\n\nI guess that in the future commit the return value of get_todo_path()\nwould change depending on what sequencer is used for, cherry-pick or\ninteractive rebase, that is, contents of replay_opts...\n\n> +\n>  static int is_rfc2822_line(const char *buf, int len)\n>  {\n>  \tint i;\n> @@ -772,25 +777,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n>  static int read_populate_todo(struct commit_list **todo_list,\n>  \t\t\tstruct replay_opts *opts)\n>  {\n> +\tconst char *todo_file = get_todo_path(opts);\n\n...and that's why you have added this temporary variable here, to\nnot repeat get_todo_path(opts) calculations...\n\n>  \tstruct strbuf buf = STRBUF_INIT;\n>  \tint fd, res;\n>  \n> -\tfd = open(git_path_todo_file(), O_RDONLY);\n> +\tfd = open(todo_file, O_RDONLY);\n>  \tif (fd < 0)\n> -\t\treturn error_errno(_(\"Could not open %s\"),\n> -\t\t\t\t   git_path_todo_file());\n> +\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n\n... So that's why it is s/git_path_todo_file()/todo_file/ replacement,\nand not simply...\n\n>  \tif (strbuf_read(&buf, fd, 0) < 0) {\n>  \t\tclose(fd);\n>  \t\tstrbuf_release(&buf);\n> -\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n> +\t\treturn error(_(\"Could not read %s.\"), todo_file);\n>  \t}\n>  \tclose(fd);\n>  \n>  \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n>  \tstrbuf_release(&buf);\n>  \tif (res)\n> -\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n> -\t\t\tgit_path_todo_file());\n> +\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n>  \treturn 0;\n>  }\n>  \n> @@ -1064,7 +1068,7 @@ static int sequencer_continue(struct replay_opts *opts)\n>  {\n>  \tstruct commit_list *todo_list = NULL;\n>  \n> -\tif (!file_exists(git_path_todo_file()))\n> +\tif (!file_exists(get_todo_path(opts)))\n\n...the s/git_path_todo_file()/git_todo_path(opts)/, isn't it?\n\n>  \t\treturn continue_single_pick();\n>  \tif (read_populate_opts(opts) ||\n>  \t\t\tread_populate_todo(&todo_list, opts))\n> \n\nLooks good; though I have not checked if all calling sites were converted.\n\nGood work,\n-- \nJakub Narębski\n\n"},{"id":"300578","messageId":"xmqqfupm5fix.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608300836030.129229@virtualbox","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T17:32:22Z","receivedAt":"2016-08-30T17:32:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +static char **read_author_script(void)\n>> > +{\n>> > +\tstruct strbuf script = STRBUF_INIT;\n>> > +\tint i, count = 0;\n>> > +\tchar *p, *p2, **env;\n>> > +\tsize_t env_size;\n>> > +\n>> > +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n>> > +\t\treturn NULL;\n>> > +\n>> > +\tfor (p = script.buf; *p; p++)\n>> > +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n>> > +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n>> > +\t\telse if (*p == '\\'')\n>> > +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n>> > +\t\telse if (*p == '\\n') {\n>> > +\t\t\t*p = '\\0';\n>> > +\t\t\tcount++;\n>> > +\t\t}\n>> \n>> Hmph.  What is this loop doing?  Is it decoding a sq-quoted buffer\n>> or something?  Don't we have a helper function to do that?\n>\n> Well, it is not just decoding an sq-quoted buffer, but several lines with\n> definitions we sq-quoted ourselves, individually.\n>\n> The quote.[ch] code currently has no code to dequote lines individually.\n\nThere is a function with exactly the same name in builtin/am.c and I\nassume that it is reading from a file with the same format, which\nuses a helper to read one variable line at a time.  Hopefully that\ncan be refactored so that more parsing is shared between the two\nusers.\n\nTwo functions with the same name reading from the same format, even\nwhen they expect to produce the same result in different internal\nformat, without even being aware of each other is a bad enough\n\"regression\" in maintainability of the code.  One of them not even\nusing sq_dequote() helper and reinventing is even worse.\n"},{"id":"300580","messageId":"alpine.DEB.2.20.1608301846360.129229@virtualbox","threadId":"43954","inReplyTo":"cb4402e9-6765-961d-0d67-43b74db05ef1@gmail.com","subject":"Re: [PATCH 07/22] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T16:48:42Z","receivedAt":"2016-08-30T17:37:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Tue, 30 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> \n> > Over the next commits, we will work on improving the sequencer to the\n> > point where it can process the edit script of an interactive rebase. To\n> > that end, we will need to teach the sequencer to read interactive\n> > rebase's todo file. In preparation, we consolidate all places where\n> > that todo file is needed to call a function that we will later extend.\n> > \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 18 +++++++++++-------\n> >  1 file changed, 11 insertions(+), 7 deletions(-)\n> > \n> > diff --git a/sequencer.c b/sequencer.c\n> > index 8d79091..982b6e9 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n> >  \treturn git_path_seq_dir();\n> >  }\n> >  \n> > +static const char *get_todo_path(const struct replay_opts *opts)\n> > +{\n> > +\treturn git_path_todo_file();\n> > +}\n> \n> I guess that in the future commit the return value of get_todo_path()\n> would change depending on what sequencer is used for, cherry-pick or\n> interactive rebase, that is, contents of replay_opts...\n\nRight.\n\n> >  static int is_rfc2822_line(const char *buf, int len)\n> >  {\n> >  \tint i;\n> > @@ -772,25 +777,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n> >  static int read_populate_todo(struct commit_list **todo_list,\n> >  \t\t\tstruct replay_opts *opts)\n> >  {\n> > +\tconst char *todo_file = get_todo_path(opts);\n> \n> ...and that's why you have added this temporary variable here, to\n> not repeat get_todo_path(opts) calculations...\n\n... and to repeat only 9 characters instead of 19...\n\n> > -\tfd = open(git_path_todo_file(), O_RDONLY);\n> > +\tfd = open(todo_file, O_RDONLY);\n> >  \tif (fd < 0)\n> > -\t\treturn error_errno(_(\"Could not open %s\"),\n> > -\t\t\t\t   git_path_todo_file());\n> > +\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n> \n> ... So that's why it is s/git_path_todo_file()/todo_file/ replacement,\n> and not simply...\n> \n> > @@ -1064,7 +1068,7 @@ static int sequencer_continue(struct replay_opts *opts)\n> >  {\n> >  \tstruct commit_list *todo_list = NULL;\n> >  \n> > -\tif (!file_exists(git_path_todo_file()))\n> > +\tif (!file_exists(get_todo_path(opts)))\n> \n> ...the s/git_path_todo_file()/git_todo_path(opts)/, isn't it?\n\nCorrect.\n\n> Looks good; though I have not checked if all calling sites were converted.\n\nThanks for the review!\nJohannes"},{"id":"300585","messageId":"alpine.DEB.2.20.1608301948310.129229@virtualbox","threadId":"43954","inReplyTo":"9797cb9e-115c-bbea-51d2-a5d686aca514@gmail.com","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T17:52:59Z","receivedAt":"2016-08-30T17:53:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Tue, 30 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> \n> > The sequencer reads options from disk and stores them in its struct\n> > for use during sequencer's operations.\n> > \n> > With this patch, the memory is released afterwards, plugging a\n> > memory leak.\n> > \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 13 ++++++++++---\n> >  1 file changed, 10 insertions(+), 3 deletions(-)\n> > \n> > diff --git a/sequencer.c b/sequencer.c\n> > index b5be0f9..8d79091 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -131,6 +131,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n> >  \t\tfree(opts->owned[i]);\n> >  \tfree(opts->owned);\n> >  \n> > +\tfree(opts->xopts);\n> > +\n> \n> This looks like independent change, not related to using the\n> sequencer_entrust() to store options read from disk in replay_opts\n> struct to be able to free memory afterwards.\n> \n> I guess you wanted to avoid one line changes...\n\nActually, it is not an independent change, but it free()s memory that has\nbeen allocated while reading the options, as the commit message says ;-)\n\n> > @@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n> \n> Sidenote: this patch would be easier to read if lines were reordered\n> as below, but I don't think any slider heuristics could help achieve\n> that automatically.  Also, the patch might be invalid...\n> \n> >  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n> >  \telse if (!strcmp(key, \"options.mainline\"))\n> >  \t\topts->mainline = git_config_int(key, value);\n> > -\telse if (!strcmp(key, \"options.strategy\"))\n> > +\telse if (!strcmp(key, \"options.strategy\")) {\n> >  \t\tgit_config_string(&opts->strategy, key, value);\n> > +\t\tsequencer_entrust(opts, (char *) opts->strategy);\n> \n> I wonder if the ability to free strings dup-ed by git_config_string()\n> be something that is part of replay_opts, or rather remove_sequencer_state(),\n> that is a list of\n> \n> \tfree(opts->strategy);\n> \tfree(opts->gpg_sign);\n\nThat is not necessarily possible because the way sequencer works, the\noptions may have not actually be read from the file, but may be populated\nby the caller (in which case we do not necessarily want to require\nstrdup()ing the strings just so that the sequencer can clean stuff up\nafterwards).\n\n> Though... free(NULL) is nop as per standard, but can we rely on it?\n\nWe can, and we do.\n\n> The *_entrust() mechanism is more generic, but do we use this general-ness?\n> Well, it could be xstrdup or git_config_string doing entrust'ing...\n\nRight, but that is exactly what I wanted to avoid, because it is rather\ninelegant to strdup() strings just so that we do not have to record what\nto free() and what not to free().\n\nBTW I have no objection at all to generalize this sequencer_entrust()\nmechanism further (read: to other, similar use cases), should it withstand\nthe test of time.\n\nCiao,\nJohannes"},{"id":"300590","messageId":"alpine.DEB.2.20.1608302005440.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqfupm5fix.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-30T18:18:42Z","receivedAt":"2016-08-30T18:19:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 30 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> > +static char **read_author_script(void)\n> >> > +{\n> >> > +\tstruct strbuf script = STRBUF_INIT;\n> >> > +\tint i, count = 0;\n> >> > +\tchar *p, *p2, **env;\n> >> > +\tsize_t env_size;\n> >> > +\n> >> > +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n> >> > +\t\treturn NULL;\n> >> > +\n> >> > +\tfor (p = script.buf; *p; p++)\n> >> > +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n> >> > +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n> >> > +\t\telse if (*p == '\\'')\n> >> > +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n> >> > +\t\telse if (*p == '\\n') {\n> >> > +\t\t\t*p = '\\0';\n> >> > +\t\t\tcount++;\n> >> > +\t\t}\n> >> \n> >> Hmph.  What is this loop doing?  Is it decoding a sq-quoted buffer\n> >> or something?  Don't we have a helper function to do that?\n> >\n> > Well, it is not just decoding an sq-quoted buffer, but several lines with\n> > definitions we sq-quoted ourselves, individually.\n> >\n> > The quote.[ch] code currently has no code to dequote lines individually.\n> \n> There is a function with exactly the same name in builtin/am.c and I\n> assume that it is reading from a file with the same format, which\n> uses a helper to read one variable line at a time.  Hopefully that\n> can be refactored so that more parsing is shared between the two\n> users.\n> \n> Two functions with the same name reading from the same format, even\n> when they expect to produce the same result in different internal\n> format, without even being aware of each other is a bad enough\n> \"regression\" in maintainability of the code.  One of them not even\n> using sq_dequote() helper and reinventing is even worse.\n\nFirst of all, builtin/am's read_author_script() really, really, really\nonly wants to read stuff into the am_state struct.\n\nThat alone is already so incompatible that I do not think it can be\nrepaired.\n\nFurther, builtin/am's read_author_script() reads *only* the\nGIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE lines (opening the\nfile three times for the task). And then it *requires* the corresponding\nvalues to be sq-quoted.\n\nI do not have a use case for this myself, but rebase -i explicitly eval's\nthe author script, so it is conceivable that some enterprisey user makes\nuse of this feature to set other environment variables. The thing is that\nrebase -i cannot necessarily expect all of those files in its state\ndirectory to be under tight control -- in stark contrast to git-am.\n\nI could imagine that this could be fixed by abstracting the functionality\nmore, and use your favored sq_dequote() (which may actually fail in case\nof an enterprisey usage as outlined above), and adapting builtin/am's\nread_author_script() to make use of that refactored approach.\n\nThis is a huge task, make no mistake, in particular because we need to\nensure compatibility with non-standard usage. So I do not think I can\ntackle that any time soon. Certainly not as part of an iteration of this\nhere patch series.\n\nCiao,\nDscho\n"},{"id":"300594","messageId":"xmqqk2ey3yha.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"e1cebf74-1592-5ddc-9979-eeffcbf4d788@gmail.com","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T18:25:53Z","receivedAt":"2016-08-30T18:26:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> In my personal opinion 'set_me_free_after_use' is not the best name,\n> but I unfortunately do not have a better proposal.  Maybe 'entrust_ptr',\n> or 'entrusted_data' / 'entrusted_ptr' / 'entrusted'?\n\nIs this to accumulate to-be-freed pointers?\n\nI think we often call a local variable that points at a piece of\nmemory to be freed \"to_free\", and that is an appropriate name for\nwhat this function is trying to do.\n\nIt is a bit surprising that the careless memory management in this\ncodepath leaks only the dumb pieces of memory (as opposed to\npointers to structures like string list that needs _clear()\nfunctions, in which case we cannot get away with list of\nto-be-freed).  I guess we were somewhat lucky ;-)\n"},{"id":"300595","messageId":"xmqqfupm3ya1.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"e4b48a9a73ff33179556c0137caae85bfb4a48d9.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T18:30:14Z","receivedAt":"2016-08-30T18:30:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> @@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n>  \telse if (!strcmp(key, \"options.mainline\"))\n>  \t\topts->mainline = git_config_int(key, value);\n> -\telse if (!strcmp(key, \"options.strategy\"))\n> +\telse if (!strcmp(key, \"options.strategy\")) {\n>  \t\tgit_config_string(&opts->strategy, key, value);\n> -\telse if (!strcmp(key, \"options.gpg-sign\"))\n> +\t\tsequencer_entrust(opts, (char *) opts->strategy);\n> +\t}\n> +\telse if (!strcmp(key, \"options.gpg-sign\")) {\n>  \t\tgit_config_string(&opts->gpg_sign, key, value);\n> +\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n> +\t}\n>  \telse if (!strcmp(key, \"options.strategy-option\")) {\n>  \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n> -\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n> +\t\topts->xopts[opts->xopts_nr++] =\n> +\t\t\tsequencer_entrust(opts, xstrdup(value));\n>  \t} else\n>  \t\treturn error(_(\"Invalid key: %s\"), key);\n\nHmm.\n\nI would have expected a call to sequencer_opts_clear(&opts) once the\nmachinery is done with the options structure, and among these places\nwhere an old value in opts->field is overwritten by a new one would\nget\n\n\tfree(opt->field); opt->field = ... new value ...;\n\nPerhaps there was a good reason to do it this way (one valid reason\nmay be that there is _no_ good place to declare that opts is now\ndone and it is safe to call sequencer_opts_clear() on it), but this\nlooks backwards from the way things are usually done.\n\n"},{"id":"300606","messageId":"e07303b5-028a-6804-7471-356e0b7293d0@kdbg.org","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608301948310.129229@virtualbox","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-08-30T20:46:58Z","receivedAt":"2016-08-30T20:47:06Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 30.08.2016 um 19:52 schrieb Johannes Schindelin:\n> Right, but that is exactly what I wanted to avoid, because it is rather\n> inelegant to strdup() strings just so that we do not have to record what\n> to free() and what not to free().\n\nPlease, excuse, but when I have to choose what is more \"elegant\":\n\n  1. strdup() sometimes so that I can later free() always\n  2. use sequencer_entrust()\n\nI would choose 1. at all times.\n\nParticularly in this case: parsing options does not sound like a major \ndrain of resources, neither CPU- nor memory-wise.\n\n-- Hannes\n\n"},{"id":"300610","messageId":"20bf659c-c081-a05f-f18a-bf0b43e0dbf3@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608301948310.129229@virtualbox","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-30T22:00:02Z","receivedAt":"2016-08-30T22:02:00Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 30.08.2016 o 19:52, Johannes Schindelin pisze:\n> Hi Kuba,\n> \n> On Tue, 30 Aug 2016, Jakub Narębski wrote:\n> \n>> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n>>\n>>> The sequencer reads options from disk and stores them in its struct\n>>> for use during sequencer's operations.\n>>>\n>>> With this patch, the memory is released afterwards, plugging a\n>>> memory leak.\n>>>\n>>> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>>> ---\n>>>  sequencer.c | 13 ++++++++++---\n>>>  1 file changed, 10 insertions(+), 3 deletions(-)\n>>>\n>>> diff --git a/sequencer.c b/sequencer.c\n>>> index b5be0f9..8d79091 100644\n>>> --- a/sequencer.c\n>>> +++ b/sequencer.c\n>>> @@ -131,6 +131,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n>>>  \t\tfree(opts->owned[i]);\n>>>  \tfree(opts->owned);\n>>>  \n>>> +\tfree(opts->xopts);\n>>> +\n>>\n>> This looks like independent change, not related to using the\n>> sequencer_entrust() to store options read from disk in replay_opts\n>> struct to be able to free memory afterwards.\n>>\n>> I guess you wanted to avoid one line changes...\n> \n> Actually, it is not an independent change, but it free()s memory that has\n> been allocated while reading the options, as the commit message says ;-)\n> \n>>> @@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>>\n>> Sidenote: this patch would be easier to read if lines were reordered\n>> as below, but I don't think any slider heuristics could help achieve\n>> that automatically.  Also, the patch might be invalid...\n>>\n>>>  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n>>>  \telse if (!strcmp(key, \"options.mainline\"))\n>>>  \t\topts->mainline = git_config_int(key, value);\n>>> -\telse if (!strcmp(key, \"options.strategy\"))\n>>> +\telse if (!strcmp(key, \"options.strategy\")) {\n>>>  \t\tgit_config_string(&opts->strategy, key, value);\n>>> +\t\tsequencer_entrust(opts, (char *) opts->strategy);\n>>\n>> I wonder if the ability to free strings dup-ed by git_config_string()\n>> be something that is part of replay_opts, or rather remove_sequencer_state(),\n>> that is a list of\n>>\n>> \tfree(opts->strategy);\n>> \tfree(opts->gpg_sign);\n> \n> That is not necessarily possible because the way sequencer works, the\n> options may have not actually be read from the file, but may be populated\n> by the caller (in which case we do not necessarily want to require\n> strdup()ing the strings just so that the sequencer can clean stuff up\n> afterwards).\n\nI guess from cursory browsing through the Git code that _currently_\nthey are only read from the config file, where git_config_string()\nstrdup's them, isn't it?  And we want to prepare for the future, where\nthe caller would prepare replay_opts, and the caller would be responsible\nfor freeing data if necessary?\n\nWould there be any sane situation where some of data should be owned\nby caller (and freed by caller), and some of data should be owned by\nsequencer library API (and freed in remove_sequencer_state())?  If\nnot, perhaps *_entrust() mechanism is overthinking it, and we simply\nneed 'is_strdup' boolean flag or something like that...\n\n>> The *_entrust() mechanism is more generic, but do we use this general-ness?\n>> Well, it could be xstrdup or git_config_string doing entrust'ing...\n> \n> Right, but that is exactly what I wanted to avoid, because it is rather\n> inelegant to strdup() strings just so that we do not have to record what\n> to free() and what not to free().\n\nMaybe inelegant, but it might be easier than inventing and implementing\n*_entrust() mechanism, like Hannes wrote.\n\n> \n> BTW I have no objection at all to generalize this sequencer_entrust()\n> mechanism further (read: to other, similar use cases), should it withstand\n> the test of time.\n\nYeah, that's my take on it too.\n\n-- \nJakub Narębski\n\n"},{"id":"300611","messageId":"xmqqr3953o8m.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"e07303b5-028a-6804-7471-356e0b7293d0@kdbg.org","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T22:07:05Z","receivedAt":"2016-08-30T22:07:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 30.08.2016 um 19:52 schrieb Johannes Schindelin:\n>> Right, but that is exactly what I wanted to avoid, because it is rather\n>> inelegant to strdup() strings just so that we do not have to record what\n>> to free() and what not to free().\n>\n> Please, excuse, but when I have to choose what is more \"elegant\":\n>\n>  1. strdup() sometimes so that I can later free() always\n>  2. use sequencer_entrust()\n>\n> I would choose 1. at all times.\n\nLet's not bring elegance or aesthetics in.  It is like asking if\ngarbage collected systems are elegant.  I do not think it is a valid\nquestion.  GC is a good pragmatic compromise after (1) declaring\nthat keeping track of allocation is too cumbersome and programmers'\ntime is better spent elsewhere, and (2) making sure hiccups caused\nby GC can be minimized to keep the latency down to acceptable\nlevels.  There are good compromises and bad ones.\n\nDoes the proposed entrust() thing qualify as a good pragmatic\ncompromise like GC does?\n\n> Particularly in this case: parsing options does not sound like a\n> major drain of resources, neither CPU- nor memory-wise.\n\nIf entrust() does not have any CPU- or memory-cost, then comparing\nit with having to strdup() sometimes might be a useful comparison.\n\nBut the entrust() thing has the allocation cost in order to track of\nwhat needs to be done at runtime, and just like strdup() needs to be\ndone on things that are being borrowed, entrust() needs to be\navoided on things that are being borrowed (and the caller needs to\nbe sure not to entrust() the same piece of memory twice), so it does\nnot reduce the cost on programmers' and readers' mental burden--the\nprogrammer always has to know which piece of memory is borrowed and\nwhich are owned by the subsystem.\n\nSo...\n"},{"id":"300613","messageId":"xmqqinuh3mx1.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"xmqqfupm5fix.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T22:35:38Z","receivedAt":"2016-08-30T22:35:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Two functions with the same name reading from the same format, even\n> when they expect to produce the same result in different internal\n> format, without even being aware of each other is a bad enough\n> \"regression\" in maintainability of the code.  One of them not even\n> using sq_dequote() helper and reinventing is even worse.\n\nSo, here is what I did as a lunch-break-hack.  The \"same result in\ndifferent internal format\" calls for a fairly light-weight mechanism\nto convey the necessary information that can be shared by callers\nwith different needs, and I chose string-list for that.\n\nTotally untested, but parse_key_value_squoted() would be a good\nfoundation to build on.  The caller in \"am\" deliberately wants to be\nstrict (e.g. it wants to error out when the user mucked with the\nfile, so it insists on the three variables to appear in a known\norder and rejects input that violates its assumption), but the\nfunction does not mind if other callers want to be more lenient.\n\n-- >8 --\nFrom: Junio C Hamano <gitster@pobox.com>\nDate: Tue, 30 Aug 2016 12:36:42 -0700\nSubject: [PATCH] am: refactor read_author_script()\n\nBy splitting the part that reads from a file and the part that\nparses the variable definitions from the contents, make the latter\ncan be more reusable in the future.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 103 ++++++++++++++++++++++++++---------------------------------\n 1 file changed, 45 insertions(+), 58 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 739b34d..b36d1f0 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -28,6 +28,7 @@\n #include \"rerere.h\"\n #include \"prompt.h\"\n #include \"mailinfo.h\"\n+#include \"string-list.h\"\n \n /**\n  * Returns 1 if the file is empty or does not exist, 0 otherwise.\n@@ -258,38 +259,29 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state,\n }\n \n /**\n- * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE\n- * as a newly-allocated string. VALUE must be a quoted string, and the KEY must\n- * match `key`. Returns NULL on failure.\n- *\n- * This is used by read_author_script() to read the GIT_AUTHOR_* variables from\n- * the author-script.\n+ * Take a series of KEY='VALUE' lines where VALUE part is\n+ * sq-quoted, and append <KEY, VALUE> at the end of the string list\n  */\n-static char *read_shell_var(FILE *fp, const char *key)\n+static int parse_key_value_squoted(char *buf, struct string_list *list)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *str;\n-\n-\tif (strbuf_getline_lf(&sb, fp))\n-\t\tgoto fail;\n-\n-\tif (!skip_prefix(sb.buf, key, &str))\n-\t\tgoto fail;\n-\n-\tif (!skip_prefix(str, \"=\", &str))\n-\t\tgoto fail;\n-\n-\tstrbuf_remove(&sb, 0, str - sb.buf);\n-\n-\tstr = sq_dequote(sb.buf);\n-\tif (!str)\n-\t\tgoto fail;\n-\n-\treturn strbuf_detach(&sb, NULL);\n-\n-fail:\n-\tstrbuf_release(&sb);\n-\treturn NULL;\n+\twhile (*buf) {\n+\t\tstruct string_list_item *item;\n+\t\tchar *np;\n+\t\tchar *cp = strchr(buf, '=');\n+\t\tif (!cp)\n+\t\t\treturn -1;\n+\t\tnp = strchrnul(cp, '\\n');\n+\t\t*cp++ = '\\0';\n+\t\titem = string_list_append(list, buf);\n+\n+\t\tbuf = np + (*np == '\\n');\n+\t\t*np = '\\0';\n+\t\tcp = sq_dequote(cp);\n+\t\tif (!cp)\n+\t\t\treturn -1;\n+\t\titem->util = xstrdup(cp);\n+\t}\n+\treturn 0;\n }\n \n /**\n@@ -311,44 +303,39 @@ static char *read_shell_var(FILE *fp, const char *key)\n static int read_author_script(struct am_state *state)\n {\n \tconst char *filename = am_path(state, \"author-script\");\n-\tFILE *fp;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct string_list kv = STRING_LIST_INIT_DUP;\n+\tint retval = -1; /* assume failure */\n+\tint fd;\n \n \tassert(!state->author_name);\n \tassert(!state->author_email);\n \tassert(!state->author_date);\n \n-\tfp = fopen(filename, \"r\");\n-\tif (!fp) {\n+\tfd = open(filename, O_RDONLY);\n+\tif (fd < 0) {\n \t\tif (errno == ENOENT)\n \t\t\treturn 0;\n \t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n \t}\n+\tstrbuf_read(&buf, fd, 0);\n+\tclose(fd);\n+\tif (parse_key_value_squoted(buf.buf, &kv))\n+\t\tgoto finish;\n \n-\tstate->author_name = read_shell_var(fp, \"GIT_AUTHOR_NAME\");\n-\tif (!state->author_name) {\n-\t\tfclose(fp);\n-\t\treturn -1;\n-\t}\n-\n-\tstate->author_email = read_shell_var(fp, \"GIT_AUTHOR_EMAIL\");\n-\tif (!state->author_email) {\n-\t\tfclose(fp);\n-\t\treturn -1;\n-\t}\n-\n-\tstate->author_date = read_shell_var(fp, \"GIT_AUTHOR_DATE\");\n-\tif (!state->author_date) {\n-\t\tfclose(fp);\n-\t\treturn -1;\n-\t}\n-\n-\tif (fgetc(fp) != EOF) {\n-\t\tfclose(fp);\n-\t\treturn -1;\n-\t}\n-\n-\tfclose(fp);\n-\treturn 0;\n+\tif (kv.nr != 3 ||\n+\t    strcmp(kv.items[0].string, \"GIT_AUTHOR_NAME\") ||\n+\t    strcmp(kv.items[1].string, \"GIT_AUTHOR_EMAIL\") ||\n+\t    strcmp(kv.items[2].string, \"GIT_AUTHOR_DATE\"))\n+\t\tgoto finish;\n+\tstate->author_name = kv.items[0].util;\n+\tstate->author_email = kv.items[1].util;\n+\tstate->author_date = kv.items[2].util;\n+\tretval = 0;\n+finish:\n+\tstring_list_clear(&kv, !!retval);\n+\tstrbuf_release(&buf);\n+\treturn retval;\n }\n \n /**\n-- \n2.10.0-rc2-246-g4fd2c60\n\n"},{"id":"300632","messageId":"alpine.DEB.2.20.1608311005210.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqfupm3ya1.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 06/22] sequencer: release memory that was allocated when reading options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T08:07:44Z","receivedAt":"2016-08-31T08:07:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 30 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > @@ -811,13 +813,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n> >  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n> >  \telse if (!strcmp(key, \"options.mainline\"))\n> >  \t\topts->mainline = git_config_int(key, value);\n> > -\telse if (!strcmp(key, \"options.strategy\"))\n> > +\telse if (!strcmp(key, \"options.strategy\")) {\n> >  \t\tgit_config_string(&opts->strategy, key, value);\n> > -\telse if (!strcmp(key, \"options.gpg-sign\"))\n> > +\t\tsequencer_entrust(opts, (char *) opts->strategy);\n> > +\t}\n> > +\telse if (!strcmp(key, \"options.gpg-sign\")) {\n> >  \t\tgit_config_string(&opts->gpg_sign, key, value);\n> > +\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n> > +\t}\n> >  \telse if (!strcmp(key, \"options.strategy-option\")) {\n> >  \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n> > -\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n> > +\t\topts->xopts[opts->xopts_nr++] =\n> > +\t\t\tsequencer_entrust(opts, xstrdup(value));\n> >  \t} else\n> >  \t\treturn error(_(\"Invalid key: %s\"), key);\n> \n> Hmm.\n> \n> I would have expected a call to sequencer_opts_clear(&opts) once the\n> machinery is done with the options structure,\n\nIt is part of sequencer_remove_state().\n\n> and among these places where an old value in opts->field is overwritten\n> by a new one would get\n> \n> \tfree(opt->field); opt->field = ... new value ...;\n\nThat is *exactly* what we *cannot* do.\n\nYou see, the replay_opts struct is *not necessarily* populated by\nread_populate_opts(). So we really cannot tell whether we are free to\nfree(opt->field) or whether some other code still wants to reference that\nmemory in the end (or for that matter, whether it was malloc()ed).\n\nThat is the *precise* reason for the existence of sequencer_entrust().\n\nCiao,\nDscho\n"},{"id":"300633","messageId":"alpine.DEB.2.20.1608311018020.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqinuh3mx1.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 14/22] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T08:19:16Z","receivedAt":"2016-08-31T08:20:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 30 Aug 2016, Junio C Hamano wrote:\n\n> From: Junio C Hamano <gitster@pobox.com>\n> Date: Tue, 30 Aug 2016 12:36:42 -0700\n> Subject: [PATCH] am: refactor read_author_script()\n> \n> [...]\n\nThank you so much for that! I will use that as a starting point to\nrefactor the two read_author_script() functions into one.\n\nJust don't look surprised when you see this patch as part of my patch\nseries, Signed-off-by me...\n\nCiao,\nDscho\n"},{"id":"300634","messageId":"alpine.DEB.2.20.1608311019290.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqk2ey3yha.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 05/22] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T08:20:56Z","receivedAt":"2016-08-31T08:21:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 30 Aug 2016, Junio C Hamano wrote:\n\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n> > In my personal opinion 'set_me_free_after_use' is not the best name,\n> > but I unfortunately do not have a better proposal.  Maybe 'entrust_ptr',\n> > or 'entrusted_data' / 'entrusted_ptr' / 'entrusted'?\n> \n> Is this to accumulate to-be-freed pointers?\n\nYes.\n\n> I think we often call a local variable that points at a piece of\n> memory to be freed \"to_free\", and that is an appropriate name for\n> what this function is trying to do.\n\nI changed it to that.\n\n> It is a bit surprising that the careless memory management in this\n> codepath leaks only the dumb pieces of memory (as opposed to\n> pointers to structures like string list that needs _clear()\n> functions, in which case we cannot get away with list of\n> to-be-freed).  I guess we were somewhat lucky ;-)\n\nYeah, the carelessness is more like a convenience where the config\nmachinery is reused to parse the values.\n\nCiao,\nDscho"},{"id":"300689","messageId":"09fd1436-301a-b0e1-c32a-81a47e4eb351@gmail.com","threadId":"43954","inReplyTo":"3c8c60e0799fdf176c72e7e17c257d33b2a362bc.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T13:41:05Z","receivedAt":"2016-08-31T13:41:25Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> The sequencer was introduced to make the cherry-pick and revert\n> functionality available as library function, with the original idea\n> being to extend the sequencer to also implement the rebase -i\n> functionality.\n> \n> The test to ensure that all of the commands in the script are identical\n> to the overall operation does not mesh well with that.\n\nActually the question is what does the test that got removed in this\ncommit actually check.  Is it high-level sanity check that todo list\nfor git-cherry-pick contains only 'pick', and for git-revert contains\nonly 'revert'?  Or does it check that at the low level sequencer\nfails when instruction sheet includes only identical operations?\n\nOnly if it is the latter (we are testing too low level details of\nhow sequencer code works, tying too tightly test with implementation)\nthe test should be removed.  I see that earlier test check that\nsequencer handles correctly invalid instructions in todo.\n\n> Therefore let's just get rid of the test that wants to verify that this\n> limitation is still in place, in preparation for the upcoming work to\n> teach the sequencer to do rebase -i's work.\n\nIs it \"upcoming work\" as in one of the patches in this series?\nIf so, which patch?\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  t/t3510-cherry-pick-sequence.sh | 11 -----------\n>  1 file changed, 11 deletions(-)\n> \n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 7b7a89d..6465edf 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n>  \ttest_expect_code 128 git cherry-pick --continue\n>  '\n>  \n> -test_expect_success 'malformed instruction sheet 2' '\n\nHmmm... the description is somewhat lacking (especially compared to\nthe rest of test), anyway.\n\nBTW. we should probably rename 'malformed instruction sheet 2'\nto 'malformed instruction sheet' if there are no further such\ntests after this removal, isn't it?\n\n> -\tpristine_detach initial &&\n> -\ttest_expect_code 1 git cherry-pick base..anotherpick &&\n> -\techo \"resolved\" >foo &&\n> -\tgit add foo &&\n> -\tgit commit &&\n> -\tsed \"s/pick/revert/\" .git/sequencer/todo >new_sheet &&\n> -\tcp new_sheet .git/sequencer/todo &&\n> -\ttest_expect_code 128 git cherry-pick --continue\n> -'\n> -\n>  test_expect_success 'empty commit set' '\n>  \tpristine_detach initial &&\n>  \ttest_expect_code 128 git cherry-pick base..base\n> \n\n"},{"id":"300701","messageId":"135c9ac7-49a6-8aa1-fc10-02c2a1fd0b1a@gmail.com","threadId":"43954","inReplyTo":"163aaa2a64ddf6dfb28c77c821726e14cc78619e.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T17:29:05Z","receivedAt":"2016-08-31T17:29:28Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n\n> When we came up with the \"sequencer\" idea, we really wanted to have\n> kind of a plumbing equivalent of the interactive rebase. Hence the\n> choice of words: the \"todo\" script, a \"pick\", etc.\n> \n> However, when it came time to implement the entire shebang, somehow this\n> idea got lost and the sequencer was used as working horse for\n> cherry-pick and revert instead. So as not to interfere with the\n> interactive rebase, it even uses a separate directory to store its\n> state.\n> \n> Furthermore, it also is stupidly strict about the \"todo\" script it\n> accepts: while it parses commands in a way that was *designed* to be\n> similar to the interactive rebase, it then goes on to *error out* if the\n> commands disagree with the overall action (cherry-pick or revert).\n\nDoes this mean that after the change you would be able to continue\n\"git revert\" with \"git cherry-pick --continue\", and vice versa?  Or that\nit would be possible for git-cherry-pick to do reverts (e.g. with ^<rev>)?\n\nThat's what we need to decide before becoming more lenient.\n \nBTW. perhaps we would be able to continue with 'git continue', regardless\nof what we have started with, I wonder...\n\n>\n> Finally, the sequencer code chose to deviate from the interactive rebase\n> code insofar that it *reformats* the \"todo\" script instead of just\n> writing the part of the parsed script that were not yet processed. This\n> is not only unnecessary churn, but might well lose information that is\n> valuable to the user (i.e. comments after the commands).\n\nThat's a very good change.\n\n>\n> Let's just bite the bullet and rewrite the entire parser; the code now\n> becomes not only more elegant: it allows us to go on and teach the\n> sequencer how to parse *true* \"todo\" scripts as used by the interactive\n> rebase itself. In a way, the sequencer is about to grow up to do its\n> older brother's job. Better.\n\nSidenote: this is not your fault, but Git doesn't do a good job on\nchanges which are mostly rewrites, trying to match stray '}' and the\nlike in generated diff.  I wonder if existing diff heuristic options\ncould help here.\n\n> \n> While at it, do not stop at the first problem, but list *all* of the\n> problems. This helps the user by allowing to address all issues in\n> one go rather than going back and forth until the todo list is valid.\n\nThat is also a good change, though I wonder how often users need\nto worry about this outside interactive rebase case.  If it is\npreparation for rebase -i, where instruction list is written by\nprone to errors human, it would be nice to have this information\nin the commit message.\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 241 +++++++++++++++++++++++++++++++++---------------------------\n>  1 file changed, 134 insertions(+), 107 deletions(-)\n\nNote: I have moved some lines of diff so that the change is more\nreadable to humans (but it results often in --++-++ chunk).\n\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 982b6e9..cbdce6d 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -473,7 +473,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n>  \t\treturn 1;\n>  }\n>  \n> -static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n> +enum todo_command {\n> +\tTODO_PICK,\n> +\tTODO_REVERT\n> +};\n\nDo we have a naming convention for enums elements?  Or are we explicitly\nmaking enums and #defines interchangeable?  I wonder...\n\n...uh, I see we don't have naming convention, but all caps snake-case\nnames dominate:\n\n  $ git grep -A2 'enum .* {'\n  [...]\n  diff.h:enum color_diff {\n  diff.h- DIFF_RESET = 0,\n  diff.h- DIFF_CONTEXT = 1,\n  --\n  dir.c:enum path_treatment {\n  dir.c-  path_none = 0,\n  dir.c-  path_recurse,\n  --\n\nShouldn't we say 'TODO_PICK = 0' explicitly, though?\n\n> +\n> +static const char *todo_command_strings[] = {\n> +\t\"pick\",\n> +\t\"revert\"\n> +};\n\nIt's a bit pity that we cannot use designated inits, and hanging comma,\n(from ISO C99 standard).  That is:\n\n  +static const char *todo_command_strings[] = {\n  +\t[TODO_PICK]   = \"pick\",\n  +\t[TODO_REVERT] = \"revert\",\n  +};\n\n\n> +\n> +static const char *command_to_string(const enum todo_command command)\n> +{\n> +\tif (command < ARRAY_SIZE(todo_command_strings))\n> +\t\treturn todo_command_strings[command];\n> +\tdie(\"Unknown command: %d\", command);\n> +}\n> +\n> +\n> +static int do_pick_commit(enum todo_command command, struct commit *commit,\n> +\t\tstruct replay_opts *opts)\n>  {\n>  \tunsigned char head[20];\n>  \tstruct commit *base, *next, *parent;\n> @@ -535,7 +554,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n>  \t\t/* TRANSLATORS: The first %s will be \"revert\" or\n>  \t\t   \"cherry-pick\", the second %s a SHA1 */\n>  \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n\nI wonder if we should not change also the error message: it is no\nlonger about command, but about operation in todo list (from what\nI understand).  Though admittedly current message works for both...\n\n> -\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n> +\t\t\tcommand_to_string(command),\n> +\t\t\toid_to_hex(&parent->object.oid));\n>  \n>  \tif (get_message(commit, &msg) != 0)\n>  \t\treturn error(_(\"Cannot get commit message for %s\"),\n> @@ -548,7 +568,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n\nFrom here on changes are about\n\n  s/opts->action == REPLAY_\\(PICK\\|REVERT\\)/command == TODO_\\1/\n\nDo we still need opts->action, or it is just needed less,\nand it is 'todo' instruction that decides about command\n(as it should)?\n\n>  \t * reverse of it if we are revert.\n>  \t */\n>  \n> -\tif (opts->action == REPLAY_REVERT) {\n> +\tif (command == TODO_REVERT) {\n>  \t\tbase = commit;\n>  \t\tbase_label = msg.label;\n>  \t\tnext = parent;\n> @@ -589,7 +609,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n>  \t\t}\n>  \t}\n>  \n> -\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n> +\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n>  \t\tres = do_recursive_merge(base, next, base_label, next_label,\n>  \t\t\t\t\t head, &msgbuf, opts);\n>  \t\tif (res < 0)\n> @@ -615,17 +635,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n>  \t * However, if the merge did not even start, then we don't want to\n>  \t * write it at all.\n>  \t */\n> -\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n> +\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n>  \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n>  \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n>  \t\tres = -1;\n> -\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n> +\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n>  \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n>  \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n>  \t\tres = -1;\n>  \n>  \tif (res) {\n> -\t\terror(opts->action == REPLAY_REVERT\n> +\t\terror(command == TODO_REVERT\n>  \t\t      ? _(\"could not revert %s... %s\")\n>  \t\t      : _(\"could not apply %s... %s\"),\n>  \t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n\nAnd here those changes end.\n\n  s/opts->action == REPLAY_\\(PICK\\|REVERT\\)/command == TODO_\\1/\n\nI wonder if Coccinelle / Undebt would help here; or would simple\nsed or query-and-replace-regexp be enough...\n\n> @@ -683,116 +703,107 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>  \treturn 0;\n>  }\n>  \n> -static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n> -\t\tstruct replay_opts *opts)\n> +struct todo_item {\n> +\tenum todo_command command;\n> +\tstruct commit *commit;\n> +\tsize_t offset_in_buf;\n> +};\n> +\n> +struct todo_list {\n> +\tstruct strbuf buf;\n> +\tstruct todo_item *items;\n> +\tint nr, alloc, current;\n> +};\n\nSo there should be s/commit_list [*]{1,2}todo_list/todo_list *todo_list/\nfrom here on?\n\nHmmm... commit_list is, as defined in commit.h, a linked list.\nHere todo_list uses growable array implementation of list.  Which\nis I guess better on current CPU architecture, with slow memory,\nlimited-size caches, and adjacency prefetching.\n\nI guess using items_nr and items_alloc would be not necessary\n(and a bit funny / overkill).\n\n> +\n> +#define TODO_LIST_INIT { STRBUF_INIT, NULL, 0, 0, 0 }\n\nSame as with other patches in this series, it would be enough to\n\n  +#define TODO_LIST_INIT { STRBUF_INIT }\n\nYou are consistent.\n\n> +\n> +static void todo_list_release(struct todo_list *todo_list)\n>  {\n\nGrh... stray '{' matched...\n\n> -\tstruct commit_list *cur = NULL;\n> -\tconst char *sha1_abbrev = NULL;\n> -\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n> -\tconst char *subject;\n> -\tint subject_len;\n> +\tstrbuf_release(&todo_list->buf);\n> +\tfree(todo_list->items);\n> +\ttodo_list->items = NULL;\n> +\ttodo_list->nr = todo_list->alloc = 0;\n> +}\n>  \n> -\tfor (cur = todo_list; cur; cur = cur->next) {\n> -\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n> -\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n> -\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> -\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n> -\t\t\tsubject_len, subject);\n> -\t\tunuse_commit_buffer(cur->item, commit_buffer);\n> -\t}\n> -\treturn 0;\n> +struct todo_item *append_todo(struct todo_list *todo_list)\n\nErrr... I don't quite understand the name of this function.\nWhat are you appending here to the todo_list?\n\nCompare string_list_append() and string_list_append_nodup(),\nwhere the second parameter is item to append.\n\nI'm not against what this function does (grow array if needed, and\nreturn pointer to the new todo_item that is to be filled), but\nI don't quite agree with the name.  Naming is hard... :-(\n[See later in reply for a proposal.]\n\n> +{\n> +\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n> +\treturn todo_list->items + todo_list->nr++;\n>  }\n>  \n> -static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n> +static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n\nWhy the change of return type?  \n\nI guess the previous code used only opts->action out of whole replay_opts,\nand now we use item->command instead; that is why replay_opts is replaced\nby todo_item.\n\nWhy now struct todo_item is first when struct replay_opts was last?\nNot that I say is was a bad change...\n\n>  {\n>  \tunsigned char commit_sha1[20];\n> -\tenum replay_action action;\n>  \tchar *end_of_object_name;\n> -\tint saved, status, padding;\n> -\n> -\tif (starts_with(bol, \"pick\")) {\n> -\t\taction = REPLAY_PICK;\n> -\t\tbol += strlen(\"pick\");\n> -\t} else if (starts_with(bol, \"revert\")) {\n> -\t\taction = REPLAY_REVERT;\n> -\t\tbol += strlen(\"revert\");\n> -\t} else\n> -\t\treturn NULL;\n> +\tint i, saved, status, padding;\n\nint i or enum?  Just kidding...\n\n> +\n> +\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n> +\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n\nskip_prefix() is such a nice abstraction...\n\n> +\t\t\titem->command = i;\n> +\t\t\tbreak;\n> +\t\t}\n\nNice.  Replacing if-elsif chain with loop.  \n\nI guess any hashmap would be serious overkill, as there are and would be\nonly a few actions possible.\n\n> +\tif (i >= ARRAY_SIZE(todo_command_strings))\n> +\t\treturn -1;\n>  \n>  \t/* Eat up extra spaces/ tabs before object name */\n>  \tpadding = strspn(bol, \" \\t\");\n>  \tif (!padding)\n> -\t\treturn NULL;\n> +\t\treturn -1;\n>  \tbol += padding;\n>  \n> -\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n> +\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n\nWhy is this cast needed?\n\nAnd do we say '(char *) bol' or '(char *)bol'?\n\n>  \tsaved = *end_of_object_name;\n>  \t*end_of_object_name = '\\0';\n>  \tstatus = get_sha1(bol, commit_sha1);\n>  \t*end_of_object_name = saved;\n>  \n> -\t/*\n> -\t * Verify that the action matches up with the one in\n> -\t * opts; we don't support arbitrary instructions\n> -\t */\n> -\tif (action != opts->action) {\n> -\t\tif (action == REPLAY_REVERT)\n> -\t\t      error((opts->action == REPLAY_REVERT)\n> -\t\t\t    ? _(\"Cannot revert during another revert.\")\n\nErrr... could the above ever happen?  Namely\n\n  action != opts->action && action == REPLAY_REVERT && opts->action == REPLAY_REVERT\n\nSurely not.\n\n> -\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n> -\t\telse\n> -\t\t      error((opts->action == REPLAY_REVERT)\n> -\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n> -\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n> -\t\treturn NULL;\n> -\t}\n\nAnyway, while it is / would be a good idea to prevent starting any\nsequencer-based command (cherry-pick, revert, soon rebase -i) when\nother command is in progress (cherry-pick, revert, soon rebase -i).\nThat is, if cherry-pick / revert waits for user action, you cannot\nrun another cherry-pick or revert.\n\nWhich I guess the above code was not about...\n\n> -\n>  \tif (status < 0)\n> -\t\treturn NULL;\n> +\t\treturn -1;\n>  \n> -\treturn lookup_commit_reference(commit_sha1);\n> +\titem->commit = lookup_commit_reference(commit_sha1);\n> +\treturn !item->commit;\n>  }\n>  \n> -static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n> -\t\t\tstruct replay_opts *opts)\n> +static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n>  {\n> -\tstruct commit_list **next = todo_list;\n> -\tstruct commit *commit;\n> +\tstruct todo_item *item;\n>  \tchar *p = buf;\n> -\tint i;\n> +\tint i, res = 0;\n>  \n>  \tfor (i = 1; *p; i++) {\n>  \t\tchar *eol = strchrnul(p, '\\n');\n> -\t\tcommit = parse_insn_line(p, eol, opts);\n> -\t\tif (!commit)\n> -\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n> -\t\tnext = commit_list_append(commit, next);\n> +\n> +\t\titem = append_todo(todo_list);\n\nA better name, in my personal option, would be\n\n  +\t\titem = todo_list_next(todo_list);\n\nOr todo_next(todo_list).\n\n> +\t\titem->offset_in_buf = p - todo_list->buf.buf;\n> +\t\tif (parse_insn_line(item, p, eol)) {\n> +\t\t\terror(\"Invalid line: %.*s\", (int)(eol - p), p);\n\nThis error message should, I think, be also translatable:\n\n  +\t\t\terror(_(\"Invalid line: %.*s\"), (int)(eol - p), p);\n\n> +\t\t\tres |= error(_(\"Could not parse line %d.\"), i);\n\nWouldn't it make more sense to reverse order of errors, that is\nfirst tell which line, and then show it?  \n\nBTW. would be we able to show where exactly there was problem parsing,\nthat is at which character in line?  Or is it something for the future?\n\n> +\t\t\titem->command = -1;\n> +\t\t}\n>  \t\tp = *eol ? eol + 1 : eol;\n>  \t}\n> -\tif (!*todo_list)\n> +\tif (!todo_list->nr)\n>  \t\treturn error(_(\"No commits parsed.\"));\n> -\treturn 0;\n> +\treturn res;\n\nAh, so 'res' is \"was there an error\" in any of lines.  Nice.\n\n>  }\n>  \n> -static int read_populate_todo(struct commit_list **todo_list,\n> +static int read_populate_todo(struct todo_list *todo_list,\n>  \t\t\tstruct replay_opts *opts)\n>  {\n>  \tconst char *todo_file = get_todo_path(opts);\n\nIf I understand it correctly, replay_opts is used only to find out\ncorrect todo_file, isn't it?\n\n> -\tstruct strbuf buf = STRBUF_INIT;\n>  \tint fd, res;\n>  \n> +\tstrbuf_reset(&todo_list->buf);\n>  \tfd = open(todo_file, O_RDONLY);\n>  \tif (fd < 0)\n>  \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n> -\tif (strbuf_read(&buf, fd, 0) < 0) {\n> +\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n>  \t\tclose(fd);\n> -\t\tstrbuf_release(&buf);\n\nA question: when is todo_list->buf released?\n\n>  \t\treturn error(_(\"Could not read %s.\"), todo_file);\n>  \t}\n>  \tclose(fd);\n>  \n> -\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n> +\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n> -\tstrbuf_release(&buf);\n>  \tif (res)\n>  \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n>  \treturn 0;\n\nNice.\n\n> @@ -848,18 +859,33 @@ static int read_populate_opts(struct replay_opts *opts)\n>  \treturn 0;\n>  }\n>  \n> -static int walk_revs_populate_todo(struct commit_list **todo_list,\n> +static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \t\t\t\tstruct replay_opts *opts)\n>  {\n> +\tenum todo_command command = opts->action == REPLAY_PICK ?\n> +\t\tTODO_PICK : TODO_REVERT;\n>  \tstruct commit *commit;\n> -\tstruct commit_list **next;\n>  \n>  \tif (prepare_revs(opts))\n>  \t\treturn -1;\n>  \n> -\tnext = todo_list;\n> -\twhile ((commit = get_revision(opts->revs)))\n> -\t\tnext = commit_list_append(commit, next);\n> +\twhile ((commit = get_revision(opts->revs))) {\n> +\t\tstruct todo_item *item = append_todo(todo_list);\n> +\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n\nI see that you are creating todo file contents while walking revision list,\nsomething that was left for later in current / previous implementation\nof the sequencer...\n\n[Added: I see it was done by format_todo() called from save_todo()]\n\n> +\t\tconst char *subject;\n> +\t\tint subject_len;\n> +\n> +\t\titem->command = command;\n> +\t\titem->commit = commit;\n> +\t\titem->offset_in_buf = todo_list->buf.len;\n> +\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> +\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n> +\t\t\topts->action == REPLAY_PICK ?  \"pick\" : \"revert\",\n\nWouldn't it be simpler to use\n\n  +\t\t\ttodo_command_strings[command],\n\nAlso, this string does not change during the loop, though I guess\ncompiler should be able to optimize it.\n\n> +\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n> +\t\t\t\tDEFAULT_ABBREV),\n> +\t\t\tsubject_len, subject);\n\n...Did format of the 'todo' file changed?  And if yes, was it in backward\ncompatible way, so that \"git revert\" or \"git cherry-pick\" started with\nold version of Git can be continued with new version, and what is also\nimportant (for somebody who sometimes uses system-installed Git, and\nsometimes user-compiled one) the reverse: started with new, continued\nwith old?\n\n> +\t\tunuse_commit_buffer(commit, commit_buffer);\n> +\t}\n>  \treturn 0;\n>  }\n>  \n> @@ -964,30 +990,24 @@ static int sequencer_rollback(struct replay_opts *opts)\n>  \treturn -1;\n>  }\n>  \n> -static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n> +static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n>  \tstatic struct lock_file todo_lock;\n> -\tstruct strbuf buf = STRBUF_INIT;\n> -\tint fd;\n> +\tconst char *todo_path = get_todo_path(opts);\n> +\tint next = todo_list->current, offset, fd;\n\nThe \"next = todo_list->current\" looks a bit strange.  Also, we do not\nchange todo_list->current, we use it in one place, so it can be used\ndirectly without help of temporary / helper variable.  But that is\njust my personal opinion.\n\nAlso, from 'next', 'offset' and 'fd', all those are different\nuses of int: the index (int, rarely size_t), the offset in string\n(formally ptrdiff_t, or size_t, but usually int), and the file descriptor.\nI think from those the file descriptor could be kept in separate line;\nit would help diff to be more readable.  But this is fairly marginal\nnitpicking, and a matter of personal opinion.\n\n>  \n> -\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n> +\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n>  \tif (fd < 0)\n>  \t\treturn error_errno(_(\"Could not lock '%s'\"),\n>  \t\t\t\t   git_path_todo_file());\n\nWe should use 'todo_path' here... and this should be done in\none of earlier patches, isn't it?\n\nThis means that\n\n  +\tconst char *todo_path = get_todo_path(opts);\n\nshould better be moved to earlier patch, too.\n\nOr maybe not.  But it looks like missed git_path_todo_file() -> get_todo_path(opts)\n[-> todo_path ] change.  If it was left because of planned whole rewrite,\nit should be mentioned in the commit message of that earlier commit,\nisn't it?\n\n> -\tif (format_todo(&buf, todo_list, opts) < 0) {\n> -\t\tstrbuf_release(&buf);\n> -\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n\nCan we still get this error?  Could we get this error anyway,\nand under what conditions?\n\n> -\t}\n> -\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n> -\t\tstrbuf_release(&buf);\n> -\t\treturn error_errno(_(\"Could not write to %s\"),\n> -\t\t\t\t   git_path_todo_file());\n> -\t}\n> +\toffset = next < todo_list->nr ?\n> +\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n> +\tif (write_in_full(fd, todo_list->buf.buf + offset,\n> +\t\t\ttodo_list->buf.len - offset) < 0)\n> +\t\treturn error(_(\"Could not write to %s (%s)\"),\n> +\t\t\ttodo_path, strerror(errno));\n\nAh, so it saves the remaining todo_items on todo_list, not the\nwhole todo_list... the name does not fully show it.\n\n> -\tif (commit_lock_file(&todo_lock) < 0) {\n> -\t\tstrbuf_release(&buf);\n> -\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n> -\t}\n> -\tstrbuf_release(&buf);\n> +\tif (commit_lock_file(&todo_lock) < 0)\n> +\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n\nNote: this is unrelated change, but we usually put paths in quotes, like this\n\n  +\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n\n(in this and earlier error message), so that paths containing spaces show\ncorrectly and readably to the user.  Though this possibly is not a problem\nfor this path.\n\nAlso, how user is to understand \"wrapping up\"?\n\n>  \treturn 0;\n>  }\n>  \n> @@ -1026,9 +1046,8 @@ static int save_opts(struct replay_opts *opts)\n>  \treturn res;\n>  }\n>  \n> -static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n> +static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n> -\tstruct commit_list *cur;\n>  \tint res;\n>  \n>  \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n> @@ -1038,10 +1057,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n>  \tif (read_and_refresh_cache(opts))\n>  \t\treturn -1;\n>  \n> -\tfor (cur = todo_list; cur; cur = cur->next) {\n> +\twhile (todo_list->current < todo_list->nr) {\n\nWhy replace for loop with while loop?  Especially that now it\nlooks more for-y ;-)\n\n  +\tfor ( ; todo_list->current < todo_list->nr; todo_list->current++) {\n\nOh... I now see why.\n\n> +\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n> -\t\tif (save_todo(cur, opts))\n> +\t\tif (save_todo(todo_list, opts))\n>  \t\t\treturn -1;\n> -\t\tres = do_pick_commit(cur->item, opts);\n> +\t\tres = do_pick_commit(item->command, item->commit, opts);\n\nI don't quite understand what sequencer tried to do here, but the\nchange looks all right.\n\n> +\t\ttodo_list->current++;\n>  \t\tif (res)\n>  \t\t\treturn res;\n>  \t}\n> @@ -1066,7 +1087,8 @@ static int continue_single_pick(void)\n>  \n>  static int sequencer_continue(struct replay_opts *opts)\n>  {\n> -\tstruct commit_list *todo_list = NULL;\n> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n> +\tint res;\n>  \n>  \tif (!file_exists(get_todo_path(opts)))\n>  \t\treturn continue_single_pick();\n> @@ -1083,21 +1105,24 @@ static int sequencer_continue(struct replay_opts *opts)\n>  \t}\n>  \tif (index_differs_from(\"HEAD\", 0))\n>  \t\treturn error_dirty_index(opts);\n> -\ttodo_list = todo_list->next;\n> -\treturn pick_commits(todo_list, opts);\n> +\ttodo_list.current++;\n> +\tres = pick_commits(&todo_list, opts);\n> +\ttodo_list_release(&todo_list);\n> +\treturn res;\n\nNice.  Looks correct.\n\n>  }\n>  \n>  static int single_pick(struct commit *cmit, struct replay_opts *opts)\n>  {\n>  \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n> -\treturn do_pick_commit(cmit, opts);\n> +\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n> +\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n\nThe ternary conditional operator here translates one enum to other enum,\nisn't it?\n\n>  }\n>  \n>  int sequencer_pick_revisions(struct replay_opts *opts)\n>  {\n> -\tstruct commit_list *todo_list = NULL;\n> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n>  \tunsigned char sha1[20];\n> -\tint i;\n> +\tint i, res;\n>  \n>  \tif (opts->subcommand == REPLAY_NONE)\n>  \t\tassert(opts->revs);\n> @@ -1171,7 +1196,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n>  \tif (save_head(sha1_to_hex(sha1)) ||\n>  \t\t\tsave_opts(opts))\n>  \t\treturn -1;\n> -\treturn pick_commits(todo_list, opts);\n> +\tres = pick_commits(&todo_list, opts);\n> +\ttodo_list_release(&todo_list);\n> +\treturn res;\n\nLooks correct.  And consistent.\n\n>  }\n>  \n>  void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n> \n\n"},{"id":"300704","messageId":"30b04497-dfb8-914b-42c4-8bc66347d347@gmail.com","threadId":"43954","inReplyTo":"1e940c58329ff5f224ec5bc48927a28ff4d1bf66.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 10/22] sequencer: avoid completely different messages for different actions","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T17:58:29Z","receivedAt":"2016-08-31T17:58:56Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"CC-ed to Jiang Xin, L10N coordinator.\n\nW dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 7 ++-----\n>  1 file changed, 2 insertions(+), 5 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index cbdce6d..1b65202 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -232,11 +232,8 @@ static int error_dirty_index(struct replay_opts *opts)\n>  \tif (read_cache_unmerged())\n>  \t\treturn error_resolve_conflict(action_name(opts));\n>  \n> -\t/* Different translation strings for cherry-pick and revert */\n> -\tif (opts->action == REPLAY_PICK)\n> -\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n> -\telse\n> -\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n> +\terror(_(\"Your local changes would be overwritten by %s.\"),\n> +\t\taction_name(opts));\n\nIf I understand it correctly, it would make \"revert\" or \"cherry-pick\"\nuntranslated part of error message.  You would need to use translation\non the result with \"_(action_name(opts))\", you would have to mark\ntodo_command_strings elements for gettext lexicon with N_(...).\n\nI am rather against this change (see also below).\n\n\nFrom the first glance I though that there would be no problem with\ntranslation legos / jigsaw it introduces, namely that the \"revert\"\nand \"cherry-pick\" would require different rest of text:\n\n po/bg.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/bg.po-msgstr \"Локалните ви промени ще бъдат презаписани при отбирането на подавания.\"\n --\n po/bg.po:msgid \"Your local changes would be overwritten by revert.\"\n po/bg.po-msgstr \"Локалните ви промени ще бъдат презаписани при отмяната на подавания.\"\n\n po/de.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/de.po-msgstr \"Ihre lokalen Änderungen würden durch den Cherry-Pick überschrieben werden.\"\n --\n po/de.po:msgid \"Your local changes would be overwritten by revert.\"\n po/de.po-msgstr \"Ihre lokalen Änderungen würden durch den Revert überschrieben werden.\"\n\nBut it turns out that \"revert\" and \"cherry-pick\" can be of different\ngender:\n\n po/ca.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/ca.po-msgstr \"Els vostres canvis locals se sobreescriurien pel recull de cireres.\"\n --\n po/ca.po:msgid \"Your local changes would be overwritten by revert.\"\n po/ca.po-msgstr \"Els vostres canvis locals se sobreescriurien per la reversió.\"\n\nIn some cases \"revert\" and \"cherry-pick\" are not translated literally\n(but compare translation for similar language: po/bg.po, without this):\n\n po/ru.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/ru.po-msgstr \"Ваши локальные изменение будут перезаписаны отбором лучшего.\"\n --\n po/ru.po:msgid \"Your local changes would be overwritten by revert.\"\n po/ru.po-msgstr \"Ваши локальные изменение будут перезаписаны возвратом коммита.\"\n\nSimilar for (but here one side uses untranslated English term...):\n\n po/vi.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/vi.po-msgstr \"Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh cherry-pick.\"\n --\n po/vi.po:msgid \"Your local changes would be overwritten by revert.\"\n po/vi.po-msgstr \"Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh hoàn nguyên.\"\n\nFor some I don't know which is the case:\n\n po/zh_CN.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/zh_CN.po-msgstr \"您的本地修改将被拣选操作覆盖。\"\n --\n po/zh_CN.po:msgid \"Your local changes would be overwritten by revert.\"\n po/zh_CN.po-msgstr \"您的本地修改将被还原操作覆盖。\"\n\nUnless we want to require to use English terms:\n\n po/sv.po:msgid \"Your local changes would be overwritten by cherry-pick.\"\n po/sv.po-msgstr \"Dina lokala ändringar skulle skrivas över av \\\"cherry-pick\\\".\"\n --\n po/sv.po:msgid \"Your local changes would be overwritten by revert.\"\n po/sv.po-msgstr \"Dina lokala ändringar skulle skrivas över av \\\"revert\\\".\"\n\n\n>  \n>  \tif (advice_commit_before_merge)\n>  \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n> \n\n"},{"id":"300707","messageId":"2ba846cc-0e0f-fc7a-27d1-3b8ad66ea72b@gmail.com","threadId":"43954","inReplyTo":"258635d3aa7f70cb1b20ea722e10ad439406b31e.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 11/22] sequencer: get rid of the subcommand field","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T18:24:16Z","receivedAt":"2016-08-31T18:24:27Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n\n> The subcommands are used exactly once, at the very beginning of\n> sequencer_pick_revisions(), to determine what to do. This is an\n> unnecessary level of indirection: we can simply call the correct\n> function to begin with. So let's do that.\n\nLooks good.  Parsing is moved from parse_args(), now unnecessary,\nto the new run_sequencer().  Which also picked up dispatch from\nsequencer_pick_revisions() - that sometimes didn't pick revisions :-o.\n\n\"All problems in computer science can be solved by another level\n of indirection, except of course for the problem of too many\n indirections.\" -- David John Wheeler\n\n> \n> While at it, ensure that the subcommands return an error code so that\n> they do not have to die() all over the place (bad practice for library\n> functions...).\n\nThis perhaps should be moved to a separate patch, but I guess\nthere is a reason behind \"while at it\".\n\nAlso subcommand functions no longer are local to sequencer.c\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/revert.c | 36 ++++++++++++++++--------------------\n>  sequencer.c      | 35 +++++++++++------------------------\n>  sequencer.h      | 13 ++++---------\n>  3 files changed, 31 insertions(+), 53 deletions(-)\n\nNice size reduction.\n\n\n\n"},{"id":"300708","messageId":"alpine.DEB.2.20.1608311706400.129229@virtualbox","threadId":"43954","inReplyTo":"09fd1436-301a-b0e1-c32a-81a47e4eb351@gmail.com","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-08-31T18:36:32Z","receivedAt":"2016-08-31T18:37:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n> > The sequencer was introduced to make the cherry-pick and revert\n> > functionality available as library function, with the original idea\n> > being to extend the sequencer to also implement the rebase -i\n> > functionality.\n> > \n> > The test to ensure that all of the commands in the script are identical\n> > to the overall operation does not mesh well with that.\n> \n> Actually the question is what does the test that got removed in this\n> commit actually check.  Is it high-level sanity check that todo list\n> for git-cherry-pick contains only 'pick', and for git-revert contains\n> only 'revert'?\n\nIt might have been that at some stage.\n\nBut should we really check that? Or should we check the *effects*?\n\nI am of the opinion that overzealous checking of certain implementation\ndetails is something to be avoided.\n\n> > Therefore let's just get rid of the test that wants to verify that this\n> > limitation is still in place, in preparation for the upcoming work to\n> > teach the sequencer to do rebase -i's work.\n> \n> Is it \"upcoming work\" as in one of the patches in this series?\n> If so, which patch?\n\nI left this a little vague, didn't I? ;-)\n\nThe problem is that the `git-rebase-todo` most definitely does *not* want\nto be restricted to a single command.\n\nSo if you must have a patch that disagrees with this overzealous check,\nthe \"revamp todo parsing\" one is probably the first. But it is better to\nthink of this at a higher level than just patches: it is wrong to limit\nthe todo script to contain only identical commands.\n\n> > diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> > index 7b7a89d..6465edf 100755\n> > --- a/t/t3510-cherry-pick-sequence.sh\n> > +++ b/t/t3510-cherry-pick-sequence.sh\n> > @@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n> >  \ttest_expect_code 128 git cherry-pick --continue\n> >  '\n> >  \n> > -test_expect_success 'malformed instruction sheet 2' '\n> \n> Hmmm... the description is somewhat lacking (especially compared to\n> the rest of test), anyway.\n> \n> BTW. we should probably rename 'malformed instruction sheet 2'\n> to 'malformed instruction sheet' if there are no further such\n> tests after this removal, isn't it?\n\nNo, we cannot rename it after this patch because the patch removes it ;-)\n(It is not a file name but really a label for a test case.)\n\nThanks for the review,\nJohannes"},{"id":"300709","messageId":"52d61bef-668b-fdc4-30b3-a34c11b39f81@gmail.com","threadId":"43954","inReplyTo":"12bffd6ca4eb7acc00a102d13348bb96ad08371d.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T18:37:53Z","receivedAt":"2016-08-31T18:38:05Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n\n> The `git-rebase-todo` file contains a list of commands. Most of those\n> commands have the form\n> \n> \t<verb> <sha1> <oneline>\n> \n> The <oneline> is displayed primarily for the user's convenience, as\n> rebase -i really interprets only the <verb> <sha1> part. However, there\n> are *some* places in interactive rebase where the <oneline> is used to\n> display messages, e.g. for reporting at which commit we stopped.\n> \n> So let's just remember it when parsing the todo file; we keep a copy of\n> the entire todo file anyway (to write out the new `done` and\n> `git-rebase-todo` file just before processing each command), so all we\n> need to do is remember the begin and end offsets.\n\nActually what we remember is pointer and length, or begin offset and length,\nnot offset and offset.\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nNice, I'll see how it is used later (and in which commit in series).\n\n> ---\n>  sequencer.c | 7 +++++++\n>  1 file changed, 7 insertions(+)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 06759d4..3398774 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>  struct todo_item {\n>  \tenum todo_command command;\n>  \tstruct commit *commit;\n> +\tconst char *arg;\n> +\tint arg_len;\n\nWhy 'arg', and not 'oneline', or 'subject'?\nI'm not saying it is bad name.\n\n>  \tsize_t offset_in_buf;\n>  };\n>  \n> @@ -760,6 +762,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n>  \tstatus = get_sha1(bol, commit_sha1);\n>  \t*end_of_object_name = saved;\n>  \n> +\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n> +\titem->arg_len = (int)(eol - item->arg);\n> +\n\nDoes it work correctly for line without <oneline>, that is\n\n  \t<verb> <sha1>\n\nI think it does, but I not entirely sure.\n\n>  \tif (status < 0)\n>  \t\treturn -1;\n>  \n> @@ -880,6 +885,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \n>  \t\titem->command = command;\n>  \t\titem->commit = commit;\n> +\t\titem->arg = NULL;\n> +\t\titem->arg_len = 0;\n>  \t\titem->offset_in_buf = todo_list->buf.len;\n>  \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n>  \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n> \n\n"},{"id":"300716","messageId":"18293d15-0a83-d7aa-78fb-14891efd6ea4@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608311706400.129229@virtualbox","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T18:46:35Z","receivedAt":"2016-08-31T18:47:20Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 31.08.2016 o 20:36, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote: \n>> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n \n> I am of the opinion that overzealous checking of certain implementation\n> details is something to be avoided.\n\nI agree.\n\n>>> Therefore let's just get rid of the test that wants to verify that this\n>>> limitation is still in place, in preparation for the upcoming work to\n>>> teach the sequencer to do rebase -i's work.\n>>\n>> Is it \"upcoming work\" as in one of the patches in this series?\n>> If so, which patch?\n> \n> I left this a little vague, didn't I? ;-)\n> \n> The problem is that the `git-rebase-todo` most definitely does *not* want\n> to be restricted to a single command.\n> \n> So if you must have a patch that disagrees with this overzealous check,\n> the \"revamp todo parsing\" one is probably the first. But it is better to\n> think of this at a higher level than just patches: it is wrong to limit\n> the todo script to contain only identical commands.\n\nI see.  Right.\n\nI wonder: would 'git cherry-pick --continue' be able to finish\n'git revert', and vice versa, then?  Or 'git sequencer --continue'?\n\n>>> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n>>> index 7b7a89d..6465edf 100755\n>>> --- a/t/t3510-cherry-pick-sequence.sh\n>>> +++ b/t/t3510-cherry-pick-sequence.sh\n>>> @@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n>>>  \ttest_expect_code 128 git cherry-pick --continue\n>>>  '\n>>>  \n>>> -test_expect_success 'malformed instruction sheet 2' '\n>>\n>> Hmmm... the description is somewhat lacking (especially compared to\n>> the rest of test), anyway.\n>>\n>> BTW. we should probably rename 'malformed instruction sheet 2'\n>> to 'malformed instruction sheet' if there are no further such\n>> tests after this removal, isn't it?\n> \n> No, we cannot rename it after this patch because the patch removes it ;-)\n> (It is not a file name but really a label for a test case.)\n\nOoops.  What I wanted to say that after removing the test case named\n'malformed instruction sheet 2' we should also rename *earlier* test\ncase from 'malformed instruction sheet 1' to 'malformed instruction sheet',\nas it is now the only 'malformed instruction sheet *' test case.\n\n"},{"id":"300719","messageId":"xmqqd1ko225w.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1608311706400.129229@virtualbox","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T19:01:31Z","receivedAt":"2016-08-31T19:03:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> The problem is that the `git-rebase-todo` most definitely does *not* want\n> to be restricted to a single command.\n\nLooking at the test in question, it is about what happens when \"git\ncherry-pick A..B\" runs, and the test assumes it gets a sequence of\n\"pick\".  It would be a bug to see any \"revert\" in there if you are\ndoing a multi cherry-pick.\n\nAnd what is checked is if \"cherry-pick --continue\" notices a\nmalformed instruction that has something other than \"pick\".\n\nIf the final invocation were \"sequencer --continue\", then I\nperfectly well understand why it is not a good idea to limit the set\nof instructions only to \"pick\" (or \"revert\").  But I do not think\nthe test performed here is for that general case.  The user knows\nGit stopped in the middle of cherry-pick and expects cherry-pick to\ncontinue.\n\n> So if you must have a patch that disagrees with this overzealous check,\n> the \"revamp todo parsing\" one is probably the first. But it is better to\n> think of this at a higher level than just patches: it is wrong to limit\n> the todo script to contain only identical commands.\n\nSo if you think of this at even higher level, the check done in\nparse_insn_line() that _assumes_ that opts->action must match the\nactions on each line is _WRONG_, but what this test expects to see\nis perfectly reasonable, I would think.\n\nIt is a different matter if it makes sense to _verify_ that the user\ndidn't make nonsensical change to the generated insn and error out\nwhen s/he did.  I tend to think it is pointless, and I wouldn't object\nif this test is removed due to that reason.\n\n"},{"id":"300720","messageId":"xmqq8tvc21re.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"52d61bef-668b-fdc4-30b3-a34c11b39f81@gmail.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T19:10:13Z","receivedAt":"2016-08-31T19:10:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n>> diff --git a/sequencer.c b/sequencer.c\n>> index 06759d4..3398774 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\n>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>>  struct todo_item {\n>>  \tenum todo_command command;\n>>  \tstruct commit *commit;\n>> +\tconst char *arg;\n>> +\tint arg_len;\n>\n> Why 'arg', and not 'oneline', or 'subject'?\n> I'm not saying it is bad name.\n\nI am not sure what the \"commit\" field of type \"struct commit *\" is\nfor.  It is not needed until it is the commit's turn to be picked or\nreverted; if we end up stopping in the middle, parsing the commit\nobject for later steps will end up being wasted effort.\n\nAlso, when the sequencer becomes one sequencer to rule them all, the\ncommand set may contain something that does not even mention any\ncommit at all (think: exec).\n\nSo I am not sure if we want a parsed commit there (I would not\nobject if we kept the texual object name read from the file,\nthough).  The \"one sequencer to rule them all\" may even have to say\n\"now give name ':1' to the result of the previous operation\" in one\nstep and in another later step have an instruction \"merge ':1'\".\nWhen that happens, you cannot even pre-populate the commit object\nwhen the sequencer reads the file, as the commit has not yet been\ncreated at that point.\n\n\n"},{"id":"300721","messageId":"a9831d93-f5b4-d729-eae0-1f7c1123a6a6@gmail.com","threadId":"43954","inReplyTo":"xmqq8tvc21re.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T19:24:25Z","receivedAt":"2016-08-31T19:24:38Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 21:10, Junio C Hamano pisze:\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n>>> diff --git a/sequencer.c b/sequencer.c\n>>> index 06759d4..3398774 100644\n>>> --- a/sequencer.c\n>>> +++ b/sequencer.c\n>>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>>>  struct todo_item {\n>>>  \tenum todo_command command;\n>>>  \tstruct commit *commit;\n>>> +\tconst char *arg;\n>>> +\tint arg_len;\n \n> I am not sure what the \"commit\" field of type \"struct commit *\" is\n> for.  It is not needed until it is the commit's turn to be picked or\n> reverted; if we end up stopping in the middle, parsing the commit\n> object for later steps will end up being wasted effort.\n\nFrom what I understand this was what sequencer did before this\nseries, so it is not a regression (I think; the commit parsing\nwas in different function, but I think at the same place in\nthe callchain).\n\n> \n> Also, when the sequencer becomes one sequencer to rule them all, the\n> command set may contain something that does not even mention any\n> commit at all (think: exec).\n\nThe \"exec\" line is a bit of exception, all other rebase -i commands\ntake commit as parameter.  It could always use NULL.\n\n>\n> So I am not sure if we want a parsed commit there (I would not\n> object if we kept the texual object name read from the file,\n> though).  The \"one sequencer to rule them all\" may even have to say\n> \"now give name ':1' to the result of the previous operation\" in one\n> step and in another later step have an instruction \"merge ':1'\".\n> When that happens, you cannot even pre-populate the commit object\n> when the sequencer reads the file, as the commit has not yet been\n> created at that point.\n\nTrue, --preserve-merges rebase is well, different.\n\nBest,\n-- \nJakub Narebski\n\n"},{"id":"300724","messageId":"xmqqzinszpww.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"a9831d93-f5b4-d729-eae0-1f7c1123a6a6@gmail.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T19:42:07Z","receivedAt":"2016-08-31T19:42:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n>>>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>>>>  struct todo_item {\n>>>>  \tenum todo_command command;\n>>>>  \tstruct commit *commit;\n>>>> +\tconst char *arg;\n>>>> +\tint arg_len;\n>  \n>> I am not sure what the \"commit\" field of type \"struct commit *\" is\n>> for.  It is not needed until it is the commit's turn to be picked or\n>> reverted; if we end up stopping in the middle, parsing the commit\n>> object for later steps will end up being wasted effort.\n>\n> From what I understand this was what sequencer did before this\n> series, so it is not a regression (I think; the commit parsing\n> was in different function, but I think at the same place in\n> the callchain).\n\nYes, I agree with you and I didn't mean \"this is a new bug\" at all.\nIt just is an indication that further refactoring after this step is\nneeded, and it is likely to involve removal or modification of this\nfield.\n\n"},{"id":"300728","messageId":"104de15c-77e8-9474-9579-4934ca8a4323@gmail.com","threadId":"43954","inReplyTo":"c6a37af958f59390c00429a5b38b34d34c9a5b95.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T20:10:38Z","receivedAt":"2016-08-31T20:10:50Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> The rebase command sports a `--gpg-sign` option that is heeded by the\n> interactive rebase.\n\nShould it be \"sports\" or \"supports\"?\n\n> \n> This patch teaches the sequencer that trick, as part of the bigger\n> effort to make the sequencer the work horse of the interactive rebase.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 48 +++++++++++++++++++++++++++++++++++++++++++-----\n>  1 file changed, 43 insertions(+), 5 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 4204cc8..e094ac2 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -15,6 +15,7 @@\n>  #include \"merge-recursive.h\"\n>  #include \"refs.h\"\n>  #include \"argv-array.h\"\n> +#include \"quote.h\"\n>  \n>  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>  \n> @@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n>   * being rebased.\n>   */\n>  static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n> +/*\n> + * The following files are written by git-rebase just after parsing the\n> + * command-line (and are only consumed, not modified, by the sequencer).\n> + */\n\nIt is good to have this comment here.\n\n> +static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n\nI know it is not your fault, but I wonder why this file uses\nsnake_case_name, while all other use kebab-case-names.  That is,\nwhy it is gpg_sign_opt and not gpg-sign-opt.\n\n>  \n>  /* We will introduce the 'interactive rebase' mode later */\n>  #define IS_REBASE_I() 0\n> @@ -129,6 +135,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n>  \treturn 1;\n>  }\n>  \n> +static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n> +{\n> +\tstatic struct strbuf buf = STRBUF_INIT;\n> +\n> +\tstrbuf_reset(&buf);\n> +\tif (opts->gpg_sign)\n> +\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n> +\treturn buf.buf;\n> +}\n\nAll right, this function is quite clear.\n\nSidenote: it's a pity api-quote.txt is just a placeholder for proper\ndocumentation (including sq_quotef()).  I also wonder why it is not\nnamed sq_quotef_buf() or strbuf_addf_sq().\n\n> +\n>  void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n>  {\n>  \tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n> @@ -471,17 +487,20 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \n>  \tif (IS_REBASE_I()) {\n>  \t\tenv = read_author_script();\n> -\t\tif (!env)\n> +\t\tif (!env) {\n> +\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n> +\n>  \t\t\treturn error(\"You have staged changes in your working \"\n>  \t\t\t\t\"tree. If these changes are meant to be\\n\"\n>  \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n> -\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n\nHow did this get expanded by error(), and why we want to replace\nit if it works?\n\n> +\t\t\t\t\"  git commit --amend %s\\n\\n\"\n>  \t\t\t\t\"If they are meant to go into a new commit, \"\n>  \t\t\t\t\"run:\\n\\n\"\n> -\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n> +\t\t\t\t\"  git commit %s\\n\\n\"\n>  \t\t\t\t\"In both case, once you're done, continue \"\n>  \t\t\t\t\"with:\\n\\n\"\n> -\t\t\t\t\"  git rebase --continue\\n\");\n> +\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n\nInstead of passing option twice, why not make use of %1$s (arg reordering),\nthat is\n\n  +\t\t\t\t\"  git commit --amend %1$s\\n\\n\"\n[...]\n  +\t\t\t\t\"  git commit %1$s\\n\\n\"\n\n\n> +\t\t}\n\nSo shell quoting is required only for error output.\n\n>  \t}\n>  \n>  \targv_array_init(&array);\n> @@ -955,8 +974,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  \n>  static int read_populate_opts(struct replay_opts *opts)\n>  {\n> -\tif (IS_REBASE_I())\n> +\tif (IS_REBASE_I()) {\n> +\t\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n> +\t\t\tif (buf.len && buf.buf[buf.len - 1] == '\\n') {\n> +\t\t\t\tif (--buf.len &&\n> +\t\t\t\t    buf.buf[buf.len - 1] == '\\r')\n> +\t\t\t\t\tbuf.len--;\n> +\t\t\t\tbuf.buf[buf.len] = '\\0';\n> +\t\t\t}\n\nIsn't there some strbuf_chomp() / strbuf_strip_eof() function?\nThough as strbuf_getline() uses something similar...\n\n> +\n> +\t\t\tif (!starts_with(buf.buf, \"-S\"))\n> +\t\t\t\tstrbuf_reset(&buf);\n\nShould we signal that there was problem with a file contents?\n\n> +\t\t\telse {\n> +\t\t\t\topts->gpg_sign = buf.buf + 2;\n> +\t\t\t\tstrbuf_detach(&buf, NULL);\n\nWouldn't we leak 2 characters that got skipped?  Maybe xstrdup would\nbe better (if it is leaked, and not reattached)?\n\n> +\t\t\t}\n> +\t\t}\n> +\n>  \t\treturn 0;\n> +\t}\n>  \n>  \tif (!file_exists(git_path_opts_file()))\n>  \t\treturn 0;\n> \n\n-- \nJakub Narębski\n\n"},{"id":"300729","messageId":"xmqqmvjszoia.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"104de15c-77e8-9474-9579-4934ca8a4323@gmail.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T20:12:29Z","receivedAt":"2016-08-31T20:12:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n>> +\t\t\telse {\n>> +\t\t\t\topts->gpg_sign = buf.buf + 2;\n>> +\t\t\t\tstrbuf_detach(&buf, NULL);\n>\n> Wouldn't we leak 2 characters that got skipped?  Maybe xstrdup would\n> be better (if it is leaked, and not reattached)?\n\nAn attempt to avoid leaking by calling free(opts->gpg_sign) would\nmake it crash, which would be even worse ;-).\n"},{"id":"300731","messageId":"a948ad4f-2145-bacb-0ec6-7edac14c4d4c@gmail.com","threadId":"43954","inReplyTo":"xmqqmvjszoia.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T20:29:48Z","receivedAt":"2016-08-31T20:29:59Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 31.08.2016 o 22:12, Junio C Hamano pisze:\n> Jakub Narębski <jnareb@gmail.com> writes:\n>> Johannes Schindelin wrote:\n\n>>> +\t\t\telse {\n>>> +\t\t\t\topts->gpg_sign = buf.buf + 2;\n>>> +\t\t\t\tstrbuf_detach(&buf, NULL);\n>>\n>> Wouldn't we leak 2 characters that got skipped?  Maybe xstrdup would\n>> be better (if it is leaked, and not reattached)?\n> \n> An attempt to avoid leaking by calling free(opts->gpg_sign) would\n> make it crash, which would be even worse ;-).\n \nActually, from C standard:\n\n\"If ptr [in free(ptr)] does not point to a block of memory allocated\n with the above functions [malloc(), etc.], it causes undefined behavior.\"\n                                                      ^^^^^^^^^\n\nWhich is even worse if it does not lead to crash.\n\n\nNote that if the last line was\n\n    +\t\t\t\tsequencer_entrust(opts, strbuf_detach(&buf, NULL));\n\nwe can make it not leak.  A bit tricksy, though.\n\n\nThough xstrdup(buf.buf + 2) followed by strbuf_release(&buf) would\nmake free(opts->gpg_sign) possible without crash.  That is we can\nwork without *_entrust() mechanism at the cost of strdups.\n\n-- \nJakub Narębski\n\n"},{"id":"300733","messageId":"xmqqeg54znip.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"a948ad4f-2145-bacb-0ec6-7edac14c4d4c@gmail.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-31T20:33:50Z","receivedAt":"2016-08-31T20:33:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> Though xstrdup(buf.buf + 2) followed by strbuf_release(&buf) would\n> make free(opts->gpg_sign) possible without crash.  That is we can\n> work without *_entrust() mechanism at the cost of strdups.\n\nAbsolutely.\n\nIt is not like entrust() thing is free of allocation cost (it needs\nto allocate an array of pointers to keep track of what to free) or\nprogrammer's mental burden (you need to be careful what to entrust()\nand what not to), so \"at the cost of strdup(3)\" is reasonable cost\nof doing business in the way normal people expect the code to work.\n\n"},{"id":"300738","messageId":"fa2a0783-afaa-0aa5-877c-24b3513d4bae@gmail.com","threadId":"43954","inReplyTo":"96adba0eee05a7b2b46b726f7e231b6732e80882.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 17/22] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T20:56:15Z","receivedAt":"2016-08-31T20:56:29Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> In the upcoming commits, we will implement more and more of rebase\n> -i's functionality. One particular feature of the commands to come is\n> that some of them allow editing the commit message while others don't,\n> i.e. we cannot define in the replay_opts whether the commit message\n> should be edited or not.\n\nIt's a nice, pretty and self contained refactoring step.  Small\nenough that it is easy to review.\n\nI would like to have in the commit message that it is sequencer_commit()\nfunction that needs to rely on new parameter, instead of on a property\nof command (of its replay_opts).  And that currently it simply passes\nthe buck to caller, which uses opts->edit, but in the future the\ncaller that is rebase -i would use todo_item and replay_opts based\nexpression.\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 +++---\n>  sequencer.h | 2 +-\n>  2 files changed, 4 insertions(+), 4 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index e094ac2..7e17d14 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -478,7 +478,7 @@ static char **read_author_script(void)\n>   * (except, of course, while running an interactive rebase).\n>   */\n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty)\n> +\t\t\t  int allow_empty, int edit)\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -513,7 +513,7 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\targv_array_push(&array, \"-s\");\n>  \tif (defmsg)\n>  \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n> -\tif (opts->edit)\n> +\tif (edit)\n>  \t\targv_array_push(&array, \"-e\");\n>  \telse if (!opts->signoff && !opts->record_origin &&\n>  \t\t git_config_get_value(\"commit.cleanup\", &value))\n> @@ -779,7 +779,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\topts, allow);\n> +\t\t\topts, allow, opts->edit);\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n> diff --git a/sequencer.h b/sequencer.h\n> index 9f63c31..fd02baf 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -50,7 +50,7 @@ int sequencer_rollback(struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty);\n> +\t\t\t  int allow_empty, int edit);\n>  \n>  extern const char sign_off_header[];\n>  \n> \n\n"},{"id":"300739","messageId":"dd7e4c82-cedb-6cde-a186-8b52bac3a5b8@gmail.com","threadId":"43954","inReplyTo":"c4e474af8e6237522f4c452ca90c2e2670059e60.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 18/22] sequencer: support amending commits","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-08-31T21:08:56Z","receivedAt":"2016-08-31T21:09:27Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> This teaches the sequencer_commit() function to take an argument that\n> will allow us to implement \"todo\" commands that need to amend the commit\n> messages (\"fixup\", \"squash\" and \"reword\").\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 ++++--\n>  sequencer.h | 2 +-\n>  2 files changed, 5 insertions(+), 3 deletions(-)\n\nNice and small addition of a new feature, a scaffolding for implementing\nrebase -i using the sequencer.\n\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 7e17d14..20f7590 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -478,7 +478,7 @@ static char **read_author_script(void)\n>   * (except, of course, while running an interactive rebase).\n>   */\n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit)\n> +\t\t\t  int allow_empty, int edit, int amend)\n\nI guess we won't get much more parameters; it would get unwieldy\n(and hard to remember).  Five is all right.\n\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -507,6 +507,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \targv_array_push(&array, \"commit\");\n>  \targv_array_push(&array, \"-n\");\n>  \n> +\tif (amend)\n> +\t\targv_array_push(&array, \"--amend\");\n>  \tif (opts->gpg_sign)\n>  \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n>  \tif (opts->signoff)\n> @@ -779,7 +781,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\topts, allow, opts->edit);\n> +\t\t\topts, allow, opts->edit, 0);\n\n... even of this makes one need to check the calling convention,\nwhat does this 0 mean.\n\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n> diff --git a/sequencer.h b/sequencer.h\n> index fd02baf..2106c0d 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -50,7 +50,7 @@ int sequencer_rollback(struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit);\n> +\t\t\t  int allow_empty, int edit, int amend);\n>  \n>  extern const char sign_off_header[];\n>  \n> \n\n"},{"id":"300752","messageId":"CAGZ79kYP6jYyuEOwQPC6pcOxCMVNNQ24pVLoQVrv6nNrGsDTKA@mail.gmail.com","threadId":"43954","inReplyTo":"135c9ac7-49a6-8aa1-fc10-02c2a1fd0b1a@gmail.com","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-08-31T23:03:40Z","receivedAt":"2016-08-31T23:03:46Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Aug 31, 2016 at 10:29 AM, Jakub Narębski <jnareb@gmail.com> wrote:\n\n>\n> BTW. perhaps we would be able to continue with 'git continue', regardless\n> of what we have started with, I wonder...\n>\n\ngit continue as a shorthand for `git <relevant-cmd> --continue` sounds great.\n\nIf we were to introduce that, I think we would need to unify the rest\nas well then, e.g.\nBoth revert as well as cherry-pick have --quit as well as --abort,\nbut rebase doesn't have --quit documented, but instead an additional\n--skip  and --edit-todo\n\nWould we pull these all up as a top level command? (That sounds not so\ngreat to me)\n"},{"id":"300769","messageId":"alpine.DEB.2.20.1609010830110.129229@virtualbox","threadId":"43954","inReplyTo":"CAGZ79kYP6jYyuEOwQPC6pcOxCMVNNQ24pVLoQVrv6nNrGsDTKA@mail.gmail.com","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T06:35:50Z","receivedAt":"2016-09-01T06:36:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba and Stefan,\n\nOn Wed, 31 Aug 2016, Stefan Beller wrote:\n\n> On Wed, Aug 31, 2016 at 10:29 AM, Jakub Narębski <jnareb@gmail.com> wrote:\n> \n> >\n> > BTW. perhaps we would be able to continue with 'git continue', regardless\n> > of what we have started with, I wonder...\n> >\n> \n> git continue as a shorthand for `git <relevant-cmd> --continue` sounds great.\n\nBefore we get ahead of ourselves:\n\n1) this has nothing to do with the patch series at hand, and\n\n2) if we were to introduce `git continue`, we would need to think long and\n   hard about the following issues:\n\n\tI) are there potentially ambiguous <relevant-cmd>s that the user\n\t   may want to continue?\n\n\tII) what about options? You can say `git rebase --continue\n\t    --no-ff`, for example, but not `git cherry-pick --continue\n\t    --no-ff`...\n\n\tIII) Would it not be confusing to have a subcommand `continue`\n\t     that does *not* serve a *single* purpose? It's kinda flying\n\t     into the face of the Unix philosophy.\n\nCiao,\nDscho"},{"id":"300773","messageId":"alpine.DEB.2.20.1609010836010.129229@virtualbox","threadId":"43954","inReplyTo":"135c9ac7-49a6-8aa1-fc10-02c2a1fd0b1a@gmail.com","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T07:49:52Z","receivedAt":"2016-09-01T07:50:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n> \n> > When we came up with the \"sequencer\" idea, we really wanted to have\n> > kind of a plumbing equivalent of the interactive rebase. Hence the\n> > choice of words: the \"todo\" script, a \"pick\", etc.\n> > \n> > However, when it came time to implement the entire shebang, somehow this\n> > idea got lost and the sequencer was used as working horse for\n> > cherry-pick and revert instead. So as not to interfere with the\n> > interactive rebase, it even uses a separate directory to store its\n> > state.\n> > \n> > Furthermore, it also is stupidly strict about the \"todo\" script it\n> > accepts: while it parses commands in a way that was *designed* to be\n> > similar to the interactive rebase, it then goes on to *error out* if the\n> > commands disagree with the overall action (cherry-pick or revert).\n> \n> Does this mean that after the change you would be able to continue\n> \"git revert\" with \"git cherry-pick --continue\", and vice versa?  Or that\n> it would be possible for git-cherry-pick to do reverts (e.g. with ^<rev>)?\n\nI guess that I allow that now. Is it harmful? I dunno.\n\n> > Let's just bite the bullet and rewrite the entire parser; the code now\n> > becomes not only more elegant: it allows us to go on and teach the\n> > sequencer how to parse *true* \"todo\" scripts as used by the interactive\n> > rebase itself. In a way, the sequencer is about to grow up to do its\n> > older brother's job. Better.\n> \n> Sidenote: this is not your fault, but Git doesn't do a good job on\n> changes which are mostly rewrites, trying to match stray '}' and the\n> like in generated diff.  I wonder if existing diff heuristic options\n> could help here.\n\nI guess --patience would have helped. Or Michael's upcoming\ndiff-heuristics.\n\n> > While at it, do not stop at the first problem, but list *all* of the\n> > problems. This helps the user by allowing to address all issues in\n> > one go rather than going back and forth until the todo list is valid.\n> \n> That is also a good change, though I wonder how often users need\n> to worry about this outside interactive rebase case.  If it is\n> preparation for rebase -i, where instruction list is written by\n> prone to errors human, it would be nice to have this information\n> in the commit message.\n\nOkay.\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 982b6e9..cbdce6d 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -473,7 +473,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n> >  \t\treturn 1;\n> >  }\n> >  \n> > -static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n> > +enum todo_command {\n> > +\tTODO_PICK,\n> > +\tTODO_REVERT\n> > +};\n> \n> Do we have a naming convention for enums elements?  Or are we explicitly\n> making enums and #defines interchangeable?  I wonder...\n> \n> ...uh, I see we don't have naming convention, but all caps snake-case\n> names dominate:\n> \n>   $ git grep -A2 'enum .* {'\n>   [...]\n>   diff.h:enum color_diff {\n>   diff.h- DIFF_RESET = 0,\n>   diff.h- DIFF_CONTEXT = 1,\n>   --\n>   dir.c:enum path_treatment {\n>   dir.c-  path_none = 0,\n>   dir.c-  path_recurse,\n>   --\n> \n> Shouldn't we say 'TODO_PICK = 0' explicitly, though?\n\nSure.\n\n> > +static const char *todo_command_strings[] = {\n> > +\t\"pick\",\n> > +\t\"revert\"\n> > +};\n> \n> It's a bit pity that we cannot use designated inits, and hanging comma,\n> (from ISO C99 standard).  That is:\n> \n>   +static const char *todo_command_strings[] = {\n>   +\t[TODO_PICK]   = \"pick\",\n>   +\t[TODO_REVERT] = \"revert\",\n>   +};\n\nI agree, it is a pity. I could do something like I did in fsck.c:\n\n\t#define FOREACH_TODO_COMMAND(FUNC) \\\n\t\tFUNC(PICK, \"pick\") \\\n\t\tFUNC(REVERT, \"revert\")\n\n\t#define COMMAND_ID(id, string) TODO_##id,\n\tenum todo_command {\n\t\tFOREACH_TODO_COMMAND(COMMAND_ID)\n\t\tTODO_END\n\t};\n\t#undef COMMAND_ID\n\n\t#define COMMAND_ID(id, string) string,\n\tstatic const char *todo_command_string[] = {\n\t\tFOREACH_TODO_COMMAND(COMMAND_ID)\n\t\tNULL\n\t};\n\t#undef COMMAND_ID\n\nHowever, this is not even readable, let alone any other type of an\nimprovement. So I won't.\n\n> > @@ -548,7 +568,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n> \n> From here on changes are about\n> \n>   s/opts->action == REPLAY_\\(PICK\\|REVERT\\)/command == TODO_\\1/\n> \n> Do we still need opts->action, or it is just needed less,\n> and it is 'todo' instruction that decides about command\n> (as it should)?\n\nWe need opts->action. For example, the state directory changes depending\non it: REPLAY_INTERACTIVE_REBASE stores its stuff in\ngit_path(\"rebase-merge\").\n\nThere is lots more behavior that also changes depending on opts->action.\n\n> > [...]\n> >  \tif (res) {\n> > -\t\terror(opts->action == REPLAY_REVERT\n> > +\t\terror(command == TODO_REVERT\n> >  \t\t      ? _(\"could not revert %s... %s\")\n> >  \t\t      : _(\"could not apply %s... %s\"),\n> >  \t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n> \n> And here those changes end.\n> \n>   s/opts->action == REPLAY_\\(PICK\\|REVERT\\)/command == TODO_\\1/\n> \n> I wonder if Coccinelle / Undebt would help here; or would simple\n> sed or query-and-replace-regexp be enough...\n\nI did this by hand, to verify that I did nothing idiotic.\n\n> > @@ -683,116 +703,107 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >  \treturn 0;\n> >  }\n> >  \n> > -static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n> > -\t\tstruct replay_opts *opts)\n> > +struct todo_item {\n> > +\tenum todo_command command;\n> > +\tstruct commit *commit;\n> > +\tsize_t offset_in_buf;\n> > +};\n> > +\n> > +struct todo_list {\n> > +\tstruct strbuf buf;\n> > +\tstruct todo_item *items;\n> > +\tint nr, alloc, current;\n> > +};\n> \n> So there should be s/commit_list [*]{1,2}todo_list/todo_list *todo_list/\n> from here on?\n\nAlmost, but not quite.\n\n> Hmmm... commit_list is, as defined in commit.h, a linked list.\n\nThat is the most prominent reason why the rest is not a mindless\nconversion from commit_list to todo_list.\n\nAnd we need todo_list as an array, because we need to be able to peek, or\neven move, backwards from the current command.\n\n> Here todo_list uses growable array implementation of list.  Which\n> is I guess better on current CPU architecture, with slow memory,\n> limited-size caches, and adjacency prefetching.\n\nThat is not the reason that an array is used here. The array allows us\nmuch more flexibility.\n\nOne of the major performance improvements will come at the very end, for\nexample: the reordering of the fixup!/squash! lines. And that would be a\n*major* pain to do if the todo_list were still a linked list.\n\n> > +#define TODO_LIST_INIT { STRBUF_INIT, NULL, 0, 0, 0 }\n> \n> Same as with other patches in this series, it would be enough to\n> \n>   +#define TODO_LIST_INIT { STRBUF_INIT }\n\nAs it happens, after Hannes' comment about REPLAY_OPTIONS_INIT, I already\nhad changed TODO_LIST_INIT as indicated. I just had no time to send out\nanother iteration (besides, I wanted to give the sequencer-i patch series\nmore visibility).\n\n> You are consistent.\n\nThank you!\n\n> > -\tstruct commit_list *cur = NULL;\n> > -\tconst char *sha1_abbrev = NULL;\n> > -\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n> > -\tconst char *subject;\n> > -\tint subject_len;\n> > +\tstrbuf_release(&todo_list->buf);\n> > +\tfree(todo_list->items);\n> > +\ttodo_list->items = NULL;\n> > +\ttodo_list->nr = todo_list->alloc = 0;\n> > +}\n> >  \n> > -\tfor (cur = todo_list; cur; cur = cur->next) {\n> > -\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n> > -\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n> > -\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> > -\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n> > -\t\t\tsubject_len, subject);\n> > -\t\tunuse_commit_buffer(cur->item, commit_buffer);\n> > -\t}\n> > -\treturn 0;\n> > +struct todo_item *append_todo(struct todo_list *todo_list)\n> \n> Errr... I don't quite understand the name of this function.\n> What are you appending here to the todo_list?\n\nA new item.\n\n> Compare string_list_append() and string_list_append_nodup(),\n> where the second parameter is item to append.\n\nYes, that is correct. In the case of a todo_item, things are a lot more\ncomplicated, though. Some of the values have to be determined tediously\n(such as the offset and length of the oneline after the \"pick <oid>\"\ncommand). I just put those values directly into the newly allocated item,\nis all.\n\n> > +\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n> > +\treturn todo_list->items + todo_list->nr++;\n> >  }\n> >  \n> > -static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n> > +static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n> \n> Why the change of return type?  \n\nBecause it makes no sense to return a commit here because not all commands\nare about commits (think rebase -i's `exec`). It makes tons of sense to\nreturn an error condition, though.\n\n> Why now struct todo_item is first when struct replay_opts was last?\n\nThose play very, very different roles.\n\nThe opts parameter used to provide parse_insn_line() with enough\ninformation to complain loudly when the overall command was not identical\nto the parsed command.\n\nThe item parameter is a receptacle for the parsed data. It will contain\nthe pointer to the commit that was previously returned, if any. But it\nwill also contain much more information, such as the command, the oneline,\nthe offset in the buffer, etc etc\n\nSo \"opts\" was an \"in\" parameter while \"item\" is an \"out\" one. Apples and\noranges.\n\n> > +\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n> > +\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n> \n> skip_prefix() is such a nice abstraction...\n> \n> > +\t\t\titem->command = i;\n> > +\t\t\tbreak;\n> > +\t\t}\n> \n> Nice.  Replacing if-elsif chain with loop.  \n> \n> I guess any hashmap would be serious overkill, as there are and would be\n> only a few actions possible.\n\nIf at all, we should use a trie here. But as you said: overkill to the\nmax.\n\n> > +\tif (i >= ARRAY_SIZE(todo_command_strings))\n> > +\t\treturn -1;\n> >  \n> >  \t/* Eat up extra spaces/ tabs before object name */\n> >  \tpadding = strspn(bol, \" \\t\");\n> >  \tif (!padding)\n> > -\t\treturn NULL;\n> > +\t\treturn -1;\n> >  \tbol += padding;\n> >  \n> > -\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n> > +\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n> \n> Why is this cast needed?\n\nBecause bol is a \"const char *\" and we need to put \"NUL\" temporarily to\n*end_of_object_name:\n\n> >  \tsaved = *end_of_object_name;\n> >  \t*end_of_object_name = '\\0';\n> >  \tstatus = get_sha1(bol, commit_sha1);\n> >  \t*end_of_object_name = saved;\n\nTechnically, this would have made a fine excuse to teach get_sha1() a mode\nwhere it expects a length parameter instead of relying on a NUL-terminated\nstring.\n\nPractically, such fine excuses cost me months in this rebase--helper\nproject already, and I need to protect my time better.\n\n> > -\t/*\n> > -\t * Verify that the action matches up with the one in\n> > -\t * opts; we don't support arbitrary instructions\n> > -\t */\n> > -\tif (action != opts->action) {\n> > -\t\tif (action == REPLAY_REVERT)\n> > -\t\t      error((opts->action == REPLAY_REVERT)\n> > -\t\t\t    ? _(\"Cannot revert during another revert.\")\n> \n> Errr... could the above ever happen?  Namely\n> \n>   action != opts->action && action == REPLAY_REVERT && opts->action == REPLAY_REVERT\n> \n> Surely not.\n\nYour reply pointed to the very circumstance when this may happen: `git\ncherry-pick --continue` after an interrupted `git revert`.\n\nBut then, I remove that code here, so I should not try to defend it.\n\n> > -\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n> > -\t\telse\n> > -\t\t      error((opts->action == REPLAY_REVERT)\n> > -\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n> > -\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n> > -\t\treturn NULL;\n> > -\t}\n> \n> Anyway, while it is / would be a good idea to prevent starting any\n> sequencer-based command (cherry-pick, revert, soon rebase -i) when\n> other command is in progress (cherry-pick, revert, soon rebase -i).\n> That is, if cherry-pick / revert waits for user action, you cannot\n> run another cherry-pick or revert.\n> \n> Which I guess the above code was not about...\n\nIt was about that, though.\n\nIt went about it in a pretty round-about way: opts->action comes from the\nname of the command (\"was I called as `git revert` or `git cherry-pick`?\")\nand action comes from the todo script, which was assumed to be written by\na previous run of the sequencer, using the then-current value of\nopts->action.\n\nSo it wrote that command into *every single line* of the todo script, *for\nthe sole purpose* of verifying that it was the same action when running\nvia --continue.\n\nAs I said earlier, I would not complain at all if an interrupted `git\nrevert` could be continued via `git cherry-pick --continue`.\n\nIf that is not desirable, I can reintroduce that overzealous check, but\nthat will have to wait until after v2.10.0. And it would require an\nargument that convinces me.\n\n> > +\t\titem = append_todo(todo_list);\n> \n> A better name, in my personal option, would be\n> \n>   +\t\titem = todo_list_next(todo_list);\n> \n> Or todo_next(todo_list).\n\nThat sounds more like a function that performs the next command in the\ntodo_list.\n\nWhile I agree that naming is hard, I still think that `append_todo()` with\nthe todo_list as single parameter and returning a todo_item is pretty much\nself-explanatory: it appends a new item to the todo_list and returns a\npointer to it.\n\n> > +\t\titem->offset_in_buf = p - todo_list->buf.buf;\n> > +\t\tif (parse_insn_line(item, p, eol)) {\n> > +\t\t\terror(\"Invalid line: %.*s\", (int)(eol - p), p);\n> \n> This error message should, I think, be also translatable:\n> \n>   +\t\t\terror(_(\"Invalid line: %.*s\"), (int)(eol - p), p);\n> \n> > +\t\t\tres |= error(_(\"Could not parse line %d.\"), i);\n\nSure. In the meantime, I consolidated those two error()s into one, and now\nI also marked it translatable.\n\n> BTW. would be we able to show where exactly there was problem parsing,\n> that is at which character in line?  Or is it something for the future?\n\nMaybe for the future.\n\n> > -static int read_populate_todo(struct commit_list **todo_list,\n> > +static int read_populate_todo(struct todo_list *todo_list,\n> >  \t\t\tstruct replay_opts *opts)\n> >  {\n> >  \tconst char *todo_file = get_todo_path(opts);\n> \n> If I understand it correctly, replay_opts is used only to find out\n> correct todo_file, isn't it?\n\nProbably. Maybe also to make certain code paths conditional on rebase -i\nmode. Maybe also to figure out whether we run in verbose mode in the\nfuture. Or something.\n\nThink of this `read_populate_todo()` function more as if it were a method\nof the \"replay class\", and the \"opts\" parameter is kind of \"self\" or\n\"this\" or whatever it is called in your favorite object-oriented language.\n\n\n> > -\tif (strbuf_read(&buf, fd, 0) < 0) {\n> > +\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n> >  \t\tclose(fd);\n> > -\t\tstrbuf_release(&buf);\n> \n> A question: when is todo_list->buf released?\n\nWhy, I am glad you asked! It is released in todo_list_release(), called at\nthe end e.g. of sequencer_continue().\n\n> > -static int walk_revs_populate_todo(struct commit_list **todo_list,\n> > +static int walk_revs_populate_todo(struct todo_list *todo_list,\n> >  \t\t\t\tstruct replay_opts *opts)\n> >  {\n> > +\tenum todo_command command = opts->action == REPLAY_PICK ?\n> > +\t\tTODO_PICK : TODO_REVERT;\n> >  \tstruct commit *commit;\n> > -\tstruct commit_list **next;\n> >  \n> >  \tif (prepare_revs(opts))\n> >  \t\treturn -1;\n> >  \n> > -\tnext = todo_list;\n> > -\twhile ((commit = get_revision(opts->revs)))\n> > -\t\tnext = commit_list_append(commit, next);\n> > +\twhile ((commit = get_revision(opts->revs))) {\n> > +\t\tstruct todo_item *item = append_todo(todo_list);\n> > +\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n> \n> I see that you are creating todo file contents while walking revision list,\n> something that was left for later in current / previous implementation\n> of the sequencer...\n\nNot really. This function was always about generating a todo_list. It just\ndid not format it yet.\n\nWith the change of keeping the original formatting of the todo script\ninstead of re-formatting it in save_todo(), this function now has to\nformat the todo_list itself.\n\n> > +\t\tconst char *subject;\n> > +\t\tint subject_len;\n> > +\n> > +\t\titem->command = command;\n> > +\t\titem->commit = commit;\n> > +\t\titem->offset_in_buf = todo_list->buf.len;\n> > +\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> > +\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n> > +\t\t\topts->action == REPLAY_PICK ?  \"pick\" : \"revert\",\n> \n> Wouldn't it be simpler to use\n> \n>   +\t\t\ttodo_command_strings[command],\n> \n> Also, this string does not change during the loop, though I guess\n> compiler should be able to optimize it.\n\nSure!\n\n> > +\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n> > +\t\t\t\tDEFAULT_ABBREV),\n> > +\t\t\tsubject_len, subject);\n> \n> ...Did format of the 'todo' file changed?  And if yes, was it in backward\n> compatible way, so that \"git revert\" or \"git cherry-pick\" started with\n> old version of Git can be continued with new version, and what is also\n> important (for somebody who sometimes uses system-installed Git, and\n> sometimes user-compiled one) the reverse: started with new, continued\n> with old?\n\nThe old format and the new format are compatible. In fact, sequencer's\nformat was based on rebase -i's format (which makes it all the more\nsurprising how much the processing deviated).\n\n> > @@ -964,30 +990,24 @@ static int sequencer_rollback(struct replay_opts *opts)\n> >  \treturn -1;\n> >  }\n> >  \n> > -static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n> > +static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n> >  {\n> >  \tstatic struct lock_file todo_lock;\n> > -\tstruct strbuf buf = STRBUF_INIT;\n> > -\tint fd;\n> > +\tconst char *todo_path = get_todo_path(opts);\n> > +\tint next = todo_list->current, offset, fd;\n> \n> The \"next = todo_list->current\" looks a bit strange.\n\nDepending whether we need rebase -i processing or revert/cherry-pick's\nslightly different one, the \"current\" position points to the next one\nalready...\n\n> Also, we do not change todo_list->current, we use it in one place, so it\n> can be used directly without help of temporary / helper variable.  But\n> that is just my personal opinion.\n\nNo, it has nothing to do with opinion. It prepares the code to keep it\nreadable even when REPLAY_INTERACTIVE_REBASE is introduced.\n\n> Also, from 'next', 'offset' and 'fd', all those are different uses of\n> int: the index (int, rarely size_t), the offset in string (formally\n> ptrdiff_t, or size_t, but usually int), and the file descriptor.  I\n> think from those the file descriptor could be kept in separate line; it\n> would help diff to be more readable.  But this is fairly marginal\n> nitpicking, and a matter of personal opinion.\n\nRight. At this point, I am really much more concerned about correctness of\ncode than discussing personal preferences.\n\n> > -\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n> > +\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n> >  \tif (fd < 0)\n> >  \t\treturn error_errno(_(\"Could not lock '%s'\"),\n> >  \t\t\t\t   git_path_todo_file());\n> \n> We should use 'todo_path' here...\n\nTrue.\n\n> and this should be done in one of earlier patches, isn't it?\n\nNo. I deliberately skipped save_todo() from \"future-proofing\" as I planned\nto rewrite it anyway. There is no point in future-proofing something you\nare going to toss in a minute.\n\n> > -\tif (format_todo(&buf, todo_list, opts) < 0) {\n> > -\t\tstrbuf_release(&buf);\n> > -\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n> \n> Can we still get this error?  Could we get this error anyway,\n> and under what conditions?\n\nNo. We keep the original formatting. Keeping it cannot possibly result in\na formatting error.\n\n> > -\t}\n> > -\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n> > -\t\tstrbuf_release(&buf);\n> > -\t\treturn error_errno(_(\"Could not write to %s\"),\n> > -\t\t\t\t   git_path_todo_file());\n> > -\t}\n> > +\toffset = next < todo_list->nr ?\n> > +\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n> > +\tif (write_in_full(fd, todo_list->buf.buf + offset,\n> > +\t\t\ttodo_list->buf.len - offset) < 0)\n> > +\t\treturn error(_(\"Could not write to %s (%s)\"),\n> > +\t\t\ttodo_path, strerror(errno));\n> \n> Ah, so it saves the remaining todo_items on todo_list, not the\n> whole todo_list... the name does not fully show it.\n\nThe name also does not fully show that it will write a \"done\" file after\nthe sequencer-i patch series.\n\n> \n> > -\tif (commit_lock_file(&todo_lock) < 0) {\n> > -\t\tstrbuf_release(&buf);\n> > -\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n> > -\t}\n> > -\tstrbuf_release(&buf);\n> > +\tif (commit_lock_file(&todo_lock) < 0)\n> > +\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n> \n> Note: this is unrelated change, but we usually put paths in quotes, like this\n> \n>   +\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n> \n> (in this and earlier error message), so that paths containing spaces show\n> correctly and readably to the user.  Though this possibly is not a problem\n> for this path.\n\nRight.\n\n> Also, how user is to understand \"wrapping up\"?\n\nThe same as before: the removed lines already had the error message,\nmissing the quotes, too.\n\nDon't get me wrong: I am a big fan of consistency, and I wish that Git's\nsource code had more of it. So I would love to see a patch series that\nmakes all error messages consistently reporting paths enclosed in single\nquotes.\n\nI am also a big fan of the separation of concerns, though. And this patch\nseries' concern is consistency *with the existing code*.\n\nSo I won't change the error message that I inherited at this point.\n\n> >  static int single_pick(struct commit *cmit, struct replay_opts *opts)\n> >  {\n> >  \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n> > -\treturn do_pick_commit(cmit, opts);\n> > +\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n> > +\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n> \n> The ternary conditional operator here translates one enum to other enum,\n> isn't it?\n\nWell, almost. Please note that the enum will receive a new value in the\nsequencer-i patch series. And there is no equivalent todo_command for\nREPLAY_INTERACTIVE_REBASE.\n\nThanks for the review!\nJohannes"},{"id":"300774","messageId":"alpine.DEB.2.20.1609010950150.129229@virtualbox","threadId":"43954","inReplyTo":"30b04497-dfb8-914b-42c4-8bc66347d347@gmail.com","subject":"Re: [PATCH 10/22] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T07:52:18Z","receivedAt":"2016-09-01T07:52:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> CC-ed to Jiang Xin, L10N coordinator.\n> \n> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n> \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 7 ++-----\n> >  1 file changed, 2 insertions(+), 5 deletions(-)\n> > \n> > diff --git a/sequencer.c b/sequencer.c\n> > index cbdce6d..1b65202 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -232,11 +232,8 @@ static int error_dirty_index(struct replay_opts *opts)\n> >  \tif (read_cache_unmerged())\n> >  \t\treturn error_resolve_conflict(action_name(opts));\n> >  \n> > -\t/* Different translation strings for cherry-pick and revert */\n> > -\tif (opts->action == REPLAY_PICK)\n> > -\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n> > -\telse\n> > -\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n> > +\terror(_(\"Your local changes would be overwritten by %s.\"),\n> > +\t\taction_name(opts));\n> \n> If I understand it correctly, it would make \"revert\" or \"cherry-pick\"\n> untranslated part of error message.  You would need to use translation\n> on the result with \"_(action_name(opts))\", you would have to mark\n> todo_command_strings elements for gettext lexicon with N_(...).\n> \n> I am rather against this change (see also below).\n\nOkay.\n\nUnfortunately, I have to focus on the correctness of the code at the\nmoment (and Git for Windows does ship *without* translations for the time\nbeing anyway, mostly to save on space, but also because users complained).\n\nSo I will take care of this after v2.10.0.\n\nFor the record, how is this supposed to be handled, in particular when I\nintroduce a new action whose action_name(opts) will be \"rebase -i\"? Do I\nreally need to repeat myself three times?\n\nCiao,\nDscho"},{"id":"300775","messageId":"alpine.DEB.2.20.1609010953080.129229@virtualbox","threadId":"43954","inReplyTo":"2ba846cc-0e0f-fc7a-27d1-3b8ad66ea72b@gmail.com","subject":"Re: [PATCH 11/22] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T07:55:25Z","receivedAt":"2016-09-01T07:55:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n> \n> > While at it, ensure that the subcommands return an error code so that\n> > they do not have to die() all over the place (bad practice for library\n> > functions...).\n> \n> This perhaps should be moved to a separate patch, but I guess\n> there is a reason behind \"while at it\".\n\nYes. It seemed like the logical thing to do: I already introduce a new\nfunction, why should I shlep over a paradigm I do not want in the end?\n\n> Also subcommand functions no longer are local to sequencer.c\n\nThey never were. All you had to do was to set a field and run the global\nfunction.\n\nThe real problem there was that the different local functions needed\ndifferent parameters, and the round-about way to set those parameters as\nfields in a struct and then call a global function with that struct just\nmakes it impossible to have compile-time safety.\n\nCiao,\nDscho"},{"id":"300777","messageId":"alpine.DEB.2.20.1609010957300.129229@virtualbox","threadId":"43954","inReplyTo":"18293d15-0a83-d7aa-78fb-14891efd6ea4@gmail.com","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T08:01:16Z","receivedAt":"2016-09-01T08:02:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 31.08.2016 o 20:36, Johannes Schindelin pisze:\n> \n> I wonder: would 'git cherry-pick --continue' be able to finish\n> 'git revert', and vice versa, then?  Or 'git sequencer --continue'?\n\nI just tested this, via\n\n\tdiff --git a/t/t3510-cherry-pick-sequence.sh\n\tb/t/t3510-cherry-pick-sequence.sh\n\tindex 96c7640..085d8bc 100755\n\t--- a/t/t3510-cherry-pick-sequence.sh\n\t+++ b/t/t3510-cherry-pick-sequence.sh\n\t@@ -55,7 +55,7 @@ test_expect_success 'cherry-pick\n\tmid-cherry-pick-sequence' '\n\t\tgit checkout HEAD foo &&\n\t\tgit cherry-pick base &&\n\t\tgit cherry-pick picked &&\n\t-       git cherry-pick --continue &&\n\t+       git revert --continue &&\n\t\tgit diff --exit-code anotherpick\n\n(Danger! Whitespace corrupted!!!)\n\nIt appears that this passes now.\n\nProbably `git sequencer --continue` would work, too, if there was a `git\nsequencer`. :0)\n\n> > On Wed, 31 Aug 2016, Jakub Narębski wrote: \n> >> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n>  \n> >>> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> >>> index 7b7a89d..6465edf 100755\n> >>> --- a/t/t3510-cherry-pick-sequence.sh\n> >>> +++ b/t/t3510-cherry-pick-sequence.sh\n> >>> @@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n> >>>  \ttest_expect_code 128 git cherry-pick --continue\n> >>>  '\n> >>>  \n> >>> -test_expect_success 'malformed instruction sheet 2' '\n> >>\n> >> Hmmm... the description is somewhat lacking (especially compared to\n> >> the rest of test), anyway.\n> >>\n> >> BTW. we should probably rename 'malformed instruction sheet 2'\n> >> to 'malformed instruction sheet' if there are no further such\n> >> tests after this removal, isn't it?\n> > \n> > No, we cannot rename it after this patch because the patch removes it ;-)\n> > (It is not a file name but really a label for a test case.)\n> \n> Ooops.  What I wanted to say that after removing the test case named\n> 'malformed instruction sheet 2' we should also rename *earlier* test\n> case from 'malformed instruction sheet 1' to 'malformed instruction sheet',\n> as it is now the only 'malformed instruction sheet *' test case.\n\nActually, you know, I completely missed the fact that there was a\n\"malformed instruction sheet 3\". I renumbered it.\n\nThanks,\nDscho"},{"id":"300779","messageId":"alpine.DEB.2.20.1609011002160.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqd1ko225w.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T08:02:53Z","receivedAt":"2016-09-01T08:04:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 31 Aug 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > So if you must have a patch that disagrees with this overzealous\n> > check, the \"revamp todo parsing\" one is probably the first. But it is\n> > better to think of this at a higher level than just patches: it is\n> > wrong to limit the todo script to contain only identical commands.\n> \n> So if you think of this at even higher level, the check done in\n> parse_insn_line() that _assumes_ that opts->action must match the\n> actions on each line is _WRONG_, but what this test expects to see is\n> perfectly reasonable, I would think.\n> \n> It is a different matter if it makes sense to _verify_ that the user\n> didn't make nonsensical change to the generated insn and error out when\n> s/he did.  I tend to think it is pointless, and I wouldn't object if\n> this test is removed due to that reason.\n\nFine. I will reintroduce that check. I guess I have the time ;-)\n\nCiao,\nDscho\n"},{"id":"300786","messageId":"alpine.DEB.2.20.1609011038430.129229@virtualbox","threadId":"43954","inReplyTo":"52d61bef-668b-fdc4-30b3-a34c11b39f81@gmail.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T08:45:51Z","receivedAt":"2016-09-01T08:46:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n> \n> > The `git-rebase-todo` file contains a list of commands. Most of those\n> > commands have the form\n> > \n> > \t<verb> <sha1> <oneline>\n> > \n> > The <oneline> is displayed primarily for the user's convenience, as\n> > rebase -i really interprets only the <verb> <sha1> part. However, there\n> > are *some* places in interactive rebase where the <oneline> is used to\n> > display messages, e.g. for reporting at which commit we stopped.\n> > \n> > So let's just remember it when parsing the todo file; we keep a copy of\n> > the entire todo file anyway (to write out the new `done` and\n> > `git-rebase-todo` file just before processing each command), so all we\n> > need to do is remember the begin and end offsets.\n> \n> Actually what we remember is pointer and length, or begin offset and length,\n> not offset and offset.\n\nRight. Fixed.\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 06759d4..3398774 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >  struct todo_item {\n> >  \tenum todo_command command;\n> >  \tstruct commit *commit;\n> > +\tconst char *arg;\n> > +\tint arg_len;\n> \n> Why 'arg', and not 'oneline', or 'subject'?\n> I'm not saying it is bad name.\n\nBecause we will use it for `exec` commands' args, too. Clarified in the\ncommit message.\n\n> > @@ -760,6 +762,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n> >  \tstatus = get_sha1(bol, commit_sha1);\n> >  \t*end_of_object_name = saved;\n> >  \n> > +\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n> > +\titem->arg_len = (int)(eol - item->arg);\n> > +\n> \n> Does it work correctly for line without <oneline>, that is\n> \n>   \t<verb> <sha1>\n> \n> I think it does, but I not entirely sure.\n\nIt does work correctly: in the example, *end_of_object_name would be '\\n',\nand strspn(end_of_object_name, \" \\t\") would return 0.\n\nThanks for the review!\nDscho"},{"id":"300788","messageId":"alpine.DEB.2.20.1609011052260.129229@virtualbox","threadId":"43954","inReplyTo":"xmqq8tvc21re.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T09:37:43Z","receivedAt":"2016-09-01T10:27:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 31 Aug 2016, Junio C Hamano wrote:\n\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n> >> diff --git a/sequencer.c b/sequencer.c\n> >> index 06759d4..3398774 100644\n> >> --- a/sequencer.c\n> >> +++ b/sequencer.c\n> >> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >>  struct todo_item {\n> >>  \tenum todo_command command;\n> >>  \tstruct commit *commit;\n> >> +\tconst char *arg;\n> >> +\tint arg_len;\n> >\n> > Why 'arg', and not 'oneline', or 'subject'?\n> > I'm not saying it is bad name.\n> \n> I am not sure what the \"commit\" field of type \"struct commit *\" is\n> for.  It is not needed until it is the commit's turn to be picked or\n> reverted; if we end up stopping in the middle, parsing the commit\n> object for later steps will end up being wasted effort.\n\nNo, it won't be wasted effort, as we *validate* the todo script this way.\nAnd since we may very well need the info later (most rebases do not fail\nin the middle), we store it, too.\n\n> Also, when the sequencer becomes one sequencer to rule them all, the\n> command set may contain something that does not even mention any\n> commit at all (think: exec).\n\nRight, in which case the \"commit\" field will have the value... *drum\nroll*... NULL!\n\n> So I am not sure if we want a parsed commit there (I would not\n> object if we kept the texual object name read from the file,\n> though).  The \"one sequencer to rule them all\" may even have to say\n> \"now give name ':1' to the result of the previous operation\" in one\n> step and in another later step have an instruction \"merge ':1'\".\n> When that happens, you cannot even pre-populate the commit object\n> when the sequencer reads the file, as the commit has not yet been\n> created at that point.\n\nThese considerations are pretty hypothetical. I would even place a bet\nthat we will *never* have \":1\" as names, not if I have anything to say...\n;-)\n\nWhat is not so hypothetical is that after parsing the todo_list, we will\nhave to act on the information contained therein. For example we will have\nto cherry-pick some of the indicated commits (requiring a struct commit *\nfor use in do_pick_commit()). Another example: we may need to determine\nthe oneline for use in fixup!/squash! reordering.\n\nSo: keeping *that* aspect of the previous todo_list parsing, i.e. store a\npointer to the already-parsed commit, is the right thing to do.\n\nCiao,\nDscho"},{"id":"300789","messageId":"9f2cbc74-3e4d-e7f1-d2dd-e85e0b9168b1@gmail.com","threadId":"43954","inReplyTo":"eeb3d11d235a0220a9a125a21d1b09a73d2c61dc.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 19/22] sequencer: support cleaning up commit messages","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T10:31:18Z","receivedAt":"2016-09-01T10:31:39Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> The sequencer_commit() function already knows how to amend commits, and\n> with this new option, it can also clean up commit messages (i.e. strip\n> out commented lines). This is needed to implement rebase -i's 'fixup'\n> and 'squash' commands as sequencer commands.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 10 +++++++---\n>  sequencer.h |  3 ++-\n>  2 files changed, 9 insertions(+), 4 deletions(-)\n\nThis looks like nice little piece of enhancement, building scaffolding\nfor sequencer-izing interactive rebase bit by bit.\n\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 20f7590..5ec956f 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -478,7 +478,8 @@ static char **read_author_script(void)\n>   * (except, of course, while running an interactive rebase).\n>   */\n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit, int amend)\n> +\t\t\t  int allow_empty, int edit, int amend,\n> +\t\t\t  int cleanup_commit_message)\n\nAll right, though it slowly begins coming close to the threshold\nwhere using bitfield flags would be sensible.\n\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -515,9 +516,12 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\targv_array_push(&array, \"-s\");\n>  \tif (defmsg)\n>  \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n> +\tif (cleanup_commit_message)\n> +\t\targv_array_push(&array, \"--cleanup=strip\");\n\nGood.\n\n>  \tif (edit)\n>  \t\targv_array_push(&array, \"-e\");\n> -\telse if (!opts->signoff && !opts->record_origin &&\n> +\telse if (!cleanup_commit_message &&\n\nAll right, explicit cleanup=strip overrides \"commit.cleanup\" config,\nand turns off passing commit verbatim (incompatible with stripping)...\n\n> +\t\t !opts->signoff && !opts->record_origin &&\n\n...adding signoff and recording origin requires not passing commit\nverbatim,...\n\n>  \t\t git_config_get_value(\"commit.cleanup\", &value))\n\n..., and in other cases are check the \"commit.cleanup\"...\n\n>  \t\targv_array_push(&array, \"--cleanup=verbatim\");\n\n... and pass commit verbatim if it is not set.\n\n\nAh, well, the change you made looks good.\n\n>  \n> @@ -781,7 +785,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\topts, allow, opts->edit, 0);\n> +\t\t\topts, allow, opts->edit, 0, 0);\n\nThe calling convention begins to look unwieldy, but we have only\na single such callsite, and there are quite a bit callsites in\nGit code that have similar API (\"git grep ', 0, 0' -- '*.c'\").\nSo we don't need to think about alternatives.  Yet.\n\nIt's a pity that emulation of named parameters in C requires\nrelying on designated inits from C99\n\n  typedef struct {\n    double pressure, moles, temp;\n  } ideal_struct;\n\n  #define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1,   \\\n                                        .moles=1, .temp=273.15, __VA_ARGS__})\n\n  double ideal_pressure_base(ideal_struct in)\n  {\n    return 8.314 * in.moles*in.temp/in.pressure;\n  }\n\n  ... ideal_pressure(.moles=2, .temp=373.15) ...\n\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n> diff --git a/sequencer.h b/sequencer.h\n> index 2106c0d..e272549 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -50,7 +50,8 @@ int sequencer_rollback(struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit, int amend);\n> +\t\t\t  int allow_empty, int edit, int amend,\n> +\t\t\t  int cleanup_commit_message);\n>  \n>  extern const char sign_off_header[];\n>  \n> \n\n"},{"id":"300790","messageId":"7996a963-52b5-5f3c-f686-f5cf22573573@gmail.com","threadId":"43954","inReplyTo":"8c30113a920e075e5ecd68ba31b4007de3e2dbc2.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T10:50:30Z","receivedAt":"2016-09-01T10:50:43Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\nSubject: [PATCH 21/22] sequencer: left-trim the lines read from the script\n\nIn the subject, it should probably be without \"the\", as \"lines\"\nare plural.\n\ns/left-trim the lines/left-trim lines/\n\n> Interactive rebase's scripts may be indented; We need to handle this\n> case, too, now that we prepare the sequencer to process interactive\n> rebases.\n\ns/; We need/; we need/\n\nNice little bit of scaffolding for sequencer-izing rebase -i.\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 3 +++\n>  1 file changed, 3 insertions(+)\n\nSmall change, easy to review.\n\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 0614b90..5efed2e 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -864,6 +864,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n>  \tchar *end_of_object_name;\n>  \tint i, saved, status, padding;\n>  \n> +\t/* left-trim */\n> +\tbol += strspn(bol, \" \\t\");\n> +\n\nNice.  Thanks for the comment.  \"left-trim\" is better than \"de-indent\".\n\n'bol' is beginning-of-line, isn't it (a complement to eol)?\n\n>  \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n>  \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n>  \t\t\titem->command = i;\n> \n\n-- \nJakub Narębski\n\n"},{"id":"300791","messageId":"4c0ee8f6-1302-1dcc-602d-7a84150ec39d@gmail.com","threadId":"43954","inReplyTo":"cb4253698ae3eca066c031e0aec4e83ede1fa3e5.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T11:10:23Z","receivedAt":"2016-09-01T11:10:43Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n> The write_message() function safely writes an strbuf to a file.\n> Sometimes this is inconvenient, though: the text to be written may not\n> be stored in a strbuf, or the strbuf should not be released after\n> writing.\n\nBy \"this\" you mean \"using strbuf\", isn't it?  It is not very obvious,\nand I think it would be better to say it explicitly.\n\n>\n> Let's allow for such use cases by refactoring write_message() to allow\n> for a convenience function write_file_gently(). As some of the upcoming\n> callers of that new function will want to append a newline character,\n> let's just add a flag for that, too.\n\nThis paragraph feels a bit convoluted.\n\nAs I understand it, you refactor \"safely writing string to a file\"\ninto write_with_lock_file(), and make write_message() use it.  The\nnew function makes it easy to create new convenience function \nwrite_file_gently(); as some of the upcoming callers of this new\nfunction would want to append a newline character, add a flag for\nit in write_file_gently(), and thus in write_with_lock_file().\n\nIsn't it better / easier to understand?\n\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 21 ++++++++++++++++++---\n>  1 file changed, 18 insertions(+), 3 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 5efed2e..f5b5e5e 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -239,22 +239,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n>  \t}\n>  }\n>  \n> -static int write_message(struct strbuf *msgbuf, const char *filename)\n> +static int write_with_lock_file(const char *filename,\n> +\t\t\t\tconst void *buf, size_t len, int append_eol)\n>  {\n>  \tstatic struct lock_file msg_file;\n>  \n>  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n>  \tif (msg_fd < 0)\n>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n> -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n> +\tif (write_in_full(msg_fd, buf, len) < 0)\n>  \t\treturn error_errno(_(\"Could not write to %s\"), filename);\n\nYou could have, for consistency, add quotes around filename (see previous\nerror_errno callsite), *while at it*:\n\n  \t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n\n\n> -\tstrbuf_release(msgbuf);\n> +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n> +\t\treturn error_errno(_(\"Could not write eol to %s\"), filename);\n\nSame here, and it wouldn't even be 'while at it'\n\n  +\t\treturn error_errno(_(\"Could not write eol to '%s'\"), filename);\n\n\n>  \tif (commit_lock_file(&msg_file) < 0)\n>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n\nAnother \"while at it\"... though the one that can be safely postponed\n(well, the make message easier to understand part, not the quote\nfilename part):\n\n  \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n\n\n>  \n>  \treturn 0;\n>  }\n>  \n> +static int write_message(struct strbuf *msgbuf, const char *filename)\n> +{\n> +\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n> +\tstrbuf_release(msgbuf);\n> +\treturn res;\n> +}\n\nNice.\n\n> +\n> +static int write_file_gently(const char *filename,\n> +\t\t\t     const char *text, int append_eol)\n> +{\n> +\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n> +}\n\nNice.  And it is static function, so we don't need to come up\nwith a better function name (to describe its function better).\n\n> +\n>  /*\n>   * Reads a file that was presumably written by a shell script, i.e.\n>   * with an end-of-line marker that needs to be stripped.\n> \n\nAnd thus we got to the last patch in this series.  I have skipped\npatches that already got reviewed; are there some that you would\nlike to have second review of?  Is there patch series that needs\nto be applied earlier that needs a review?\n\nP.S. I'll try to respond to your comments later today.\n\nRegards,\n-- \nJakub Narębski\n\n"},{"id":"300795","messageId":"alpine.DEB.2.20.1609011507130.129229@virtualbox","threadId":"43954","inReplyTo":"a9831d93-f5b4-d729-eae0-1f7c1123a6a6@gmail.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:12:15Z","receivedAt":"2016-09-01T13:13:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba & Junio,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 31.08.2016 o 21:10, Junio C Hamano pisze:\n> > Jakub Narębski <jnareb@gmail.com> writes:\n> > \n> >>> diff --git a/sequencer.c b/sequencer.c\n> >>> index 06759d4..3398774 100644\n> >>> --- a/sequencer.c\n> >>> +++ b/sequencer.c\n> >>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >>>  struct todo_item {\n> >>>  \tenum todo_command command;\n> >>>  \tstruct commit *commit;\n> >>> +\tconst char *arg;\n> >>> +\tint arg_len;\n>  \n> > I am not sure what the \"commit\" field of type \"struct commit *\" is\n> > for.  It is not needed until it is the commit's turn to be picked or\n> > reverted; if we end up stopping in the middle, parsing the commit\n> > object for later steps will end up being wasted effort.\n> \n> From what I understand this was what sequencer did before this\n> series, so it is not a regression (I think; the commit parsing\n> was in different function, but I think at the same place in\n> the callchain).\n\nExactly.\n\n> > Also, when the sequencer becomes one sequencer to rule them all, the\n> > command set may contain something that does not even mention any\n> > commit at all (think: exec).\n> \n> The \"exec\" line is a bit of exception, all other rebase -i commands\n> take commit as parameter.  It could always use NULL.\n\nThere is also \"noop\".\n\n> > So I am not sure if we want a parsed commit there (I would not\n> > object if we kept the texual object name read from the file,\n> > though).  The \"one sequencer to rule them all\" may even have to say\n> > \"now give name ':1' to the result of the previous operation\" in one\n> > step and in another later step have an instruction \"merge ':1'\".\n> > When that happens, you cannot even pre-populate the commit object\n> > when the sequencer reads the file, as the commit has not yet been\n> > created at that point.\n> \n> True, --preserve-merges rebase is well, different.\n\nIt is mis-designed. And I can be that harsh because it was my design.\n\nIn the meantime I came up with a much better design, and implemented it as\na shell script on top of rebase -i. Since shell scripts run like slow\nmolasses, even more so on Windows, I have a loose plan to implement its\nfunctionality as a new --recreate-merges option, and to deprecate\n--preserve-merges when that new option works.\n\nIt needs to be a new option (not a --preserve-merges=v2) because it is a\ntotally different beast. For starters, it does not need its own code path\nthat overrides pick_one, as --preserve-merges does.\n\nBut I get way ahead of myself. First we need to get these last few bits\nand pieces in place to accelerate (non --preserve-merges) rebase -i.\n\nCiao,\nDscho"},{"id":"300796","messageId":"alpine.DEB.2.20.1609011512200.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqzinszpww.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:14:02Z","receivedAt":"2016-09-01T13:21:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 31 Aug 2016, Junio C Hamano wrote:\n\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n> >>>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >>>>  struct todo_item {\n> >>>>  \tenum todo_command command;\n> >>>>  \tstruct commit *commit;\n> >>>> +\tconst char *arg;\n> >>>> +\tint arg_len;\n> >  \n> >> I am not sure what the \"commit\" field of type \"struct commit *\" is\n> >> for.  It is not needed until it is the commit's turn to be picked or\n> >> reverted; if we end up stopping in the middle, parsing the commit\n> >> object for later steps will end up being wasted effort.\n> >\n> > From what I understand this was what sequencer did before this\n> > series, so it is not a regression (I think; the commit parsing\n> > was in different function, but I think at the same place in\n> > the callchain).\n> \n> Yes, I agree with you and I didn't mean \"this is a new bug\" at all.\n> It just is an indication that further refactoring after this step is\n> needed, and it is likely to involve removal or modification of this\n> field.\n\nNot so. After you review the sequencer-i patches, you will see that it\nmakes tons of sense to have that \"commit\" field: \"pick\" is by far the most\ncommon case, and it would not make sense at all to validate the todo\nscript, only to throw away the information we got, only to re-gain it\nlater in the sequencer.\n\nRead: I strongly disagree with your cursory verdict that the \"commit\"\nfield should go.\n\nCiao,\nDscho"},{"id":"300797","messageId":"alpine.DEB.2.20.1609011516080.129229@virtualbox","threadId":"43954","inReplyTo":"104de15c-77e8-9474-9579-4934ca8a4323@gmail.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:33:08Z","receivedAt":"2016-09-01T13:33:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> > The rebase command sports a `--gpg-sign` option that is heeded by the\n> > interactive rebase.\n> \n> Should it be \"sports\" or \"supports\"?\n\nFunny. I got a PR last week that wanted to fix a similar expression.\n\nI really meant \"to sport\", as in \"To display; to have as a notable\nfeature.\". See https://en.wiktionary.org/wiki/sport#Verb\n\n> > +static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n> \n> I know it is not your fault, but I wonder why this file uses\n> snake_case_name, while all other use kebab-case-names.  That is,\n> why it is gpg_sign_opt and not gpg-sign-opt.\n\nYes, you are correct: it is not my fault ;-)\n\n> Sidenote: it's a pity api-quote.txt is just a placeholder for proper\n> documentation (including sq_quotef()).  I also wonder why it is not\n> named sq_quotef_buf() or strbuf_addf_sq().\n\nHeh. I did not even bother to check the documentation, it is my long-time\nhabit to dive right into the code.\n\n> > @@ -471,17 +487,20 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> >  \n> >  \tif (IS_REBASE_I()) {\n> >  \t\tenv = read_author_script();\n> > -\t\tif (!env)\n> > +\t\tif (!env) {\n> > +\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n> > +\n> >  \t\t\treturn error(\"You have staged changes in your working \"\n> >  \t\t\t\t\"tree. If these changes are meant to be\\n\"\n> >  \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n> > -\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n> \n> How did this get expanded by error(), and why we want to replace\n> it if it works?\n\nIt did not work. It was a place-holder waiting for this patch ;-)\n\n> \n> > +\t\t\t\t\"  git commit --amend %s\\n\\n\"\n> >  \t\t\t\t\"If they are meant to go into a new commit, \"\n> >  \t\t\t\t\"run:\\n\\n\"\n> > -\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n> > +\t\t\t\t\"  git commit %s\\n\\n\"\n> >  \t\t\t\t\"In both case, once you're done, continue \"\n> >  \t\t\t\t\"with:\\n\\n\"\n> > -\t\t\t\t\"  git rebase --continue\\n\");\n> > +\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n> \n> Instead of passing option twice, why not make use of %1$s (arg reordering),\n> that is\n> \n>   +\t\t\t\t\"  git commit --amend %1$s\\n\\n\"\n> [...]\n>   +\t\t\t\t\"  git commit %1$s\\n\\n\"\n\nCute. But would this not drive the l10ners insane?\n\n> So shell quoting is required only for error output.\n\nIndeed.\n\n> > @@ -955,8 +974,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n> >  \n> >  static int read_populate_opts(struct replay_opts *opts)\n> >  {\n> > -\tif (IS_REBASE_I())\n> > +\tif (IS_REBASE_I()) {\n> > +\t\tstruct strbuf buf = STRBUF_INIT;\n> > +\n> > +\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n> > +\t\t\tif (buf.len && buf.buf[buf.len - 1] == '\\n') {\n> > +\t\t\t\tif (--buf.len &&\n> > +\t\t\t\t    buf.buf[buf.len - 1] == '\\r')\n> > +\t\t\t\t\tbuf.len--;\n> > +\t\t\t\tbuf.buf[buf.len] = '\\0';\n> > +\t\t\t}\n> \n> Isn't there some strbuf_chomp() / strbuf_strip_eof() function?\n> Though as strbuf_getline() uses something similar...\n\nEven worse. read_oneliner() *already* does that. I just forgot to delete\nthis code when I introduced and used read_oneliner().\n\nThanks.\n\n> > +\t\t\tif (!starts_with(buf.buf, \"-S\"))\n> > +\t\t\t\tstrbuf_reset(&buf);\n> \n> Should we signal that there was problem with a file contents?\n\nMaybe. But probably not: this file is written by git-rebase itself. I\nmerely safe-guarded against empty files here.\n\n> > +\t\t\telse {\n> > +\t\t\t\topts->gpg_sign = buf.buf + 2;\n> > +\t\t\t\tstrbuf_detach(&buf, NULL);\n> \n> Wouldn't we leak 2 characters that got skipped?  Maybe xstrdup would\n> be better (if it is leaked, and not reattached)?\n\nWe do not leak anything because I changed the code locally already to use\nsequencer_entrust() (I guess in response to an earlier of your comments).\n\nCiao,\nDscho"},{"id":"300798","messageId":"alpine.DEB.2.20.1609011533190.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqmvjszoia.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:33:53Z","receivedAt":"2016-09-01T13:34:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 31 Aug 2016, Junio C Hamano wrote:\n\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n> >> +\t\t\telse {\n> >> +\t\t\t\topts->gpg_sign = buf.buf + 2;\n> >> +\t\t\t\tstrbuf_detach(&buf, NULL);\n> >\n> > Wouldn't we leak 2 characters that got skipped?  Maybe xstrdup would\n> > be better (if it is leaked, and not reattached)?\n> \n> An attempt to avoid leaking by calling free(opts->gpg_sign) would\n> make it crash, which would be even worse ;-).\n\nAs I pointed out in a couple of replies yesterday: we cannot assume that\ngpg_sign is free()able. That's the entire reason behind the\nsequencer_entrust() dance.\n\nCiao,\nDscho"},{"id":"300799","messageId":"alpine.DEB.2.20.1609011534300.129229@virtualbox","threadId":"43954","inReplyTo":"a948ad4f-2145-bacb-0ec6-7edac14c4d4c@gmail.com","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:35:09Z","receivedAt":"2016-09-01T13:35:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> Note that if the last line was\n> \n>     +\t\t\t\tsequencer_entrust(opts, strbuf_detach(&buf, NULL));\n> \n> we can make it not leak.  A bit tricksy, though.\n\nHeh... I made it that tricksy, then.\n\nCiao,\nDscho"},{"id":"300800","messageId":"alpine.DEB.2.20.1609011540050.129229@virtualbox","threadId":"43954","inReplyTo":"fa2a0783-afaa-0aa5-877c-24b3513d4bae@gmail.com","subject":"Re: [PATCH 17/22] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:40:19Z","receivedAt":"2016-09-01T13:40:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> > In the upcoming commits, we will implement more and more of rebase\n> > -i's functionality. One particular feature of the commands to come is\n> > that some of them allow editing the commit message while others don't,\n> > i.e. we cannot define in the replay_opts whether the commit message\n> > should be edited or not.\n> \n> It's a nice, pretty and self contained refactoring step.  Small\n> enough that it is easy to review.\n> \n> I would like to have in the commit message that it is sequencer_commit()\n> function that needs to rely on new parameter, instead of on a property\n> of command (of its replay_opts).  And that currently it simply passes\n> the buck to caller, which uses opts->edit, but in the future the\n> caller that is rebase -i would use todo_item and replay_opts based\n> expression.\n\nI enhanced the commit message.\n\nThanks for the review,\nDscho"},{"id":"300801","messageId":"alpine.DEB.2.20.1609011540550.129229@virtualbox","threadId":"43954","inReplyTo":"dd7e4c82-cedb-6cde-a186-8b52bac3a5b8@gmail.com","subject":"Re: [PATCH 18/22] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:42:30Z","receivedAt":"2016-09-01T13:42:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 31 Aug 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> > diff --git a/sequencer.c b/sequencer.c\n> > index 7e17d14..20f7590 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -478,7 +478,7 @@ static char **read_author_script(void)\n> >   * (except, of course, while running an interactive rebase).\n> >   */\n> >  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> > -\t\t\t  int allow_empty, int edit)\n> > +\t\t\t  int allow_empty, int edit, int amend)\n> \n> I guess we won't get much more parameters; it would get unwieldy\n> (and hard to remember).  Five is all right.\n\nIt will eventually get a sixth, cleanup_commit_message.\n\n> >  {\n> >  \tchar **env = NULL;\n> >  \tstruct argv_array array;\n> > @@ -507,6 +507,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> >  \targv_array_push(&array, \"commit\");\n> >  \targv_array_push(&array, \"-n\");\n> >  \n> > +\tif (amend)\n> > +\t\targv_array_push(&array, \"--amend\");\n> >  \tif (opts->gpg_sign)\n> >  \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n> >  \tif (opts->signoff)\n> > @@ -779,7 +781,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n> >  \t}\n> >  \tif (!opts->no_commit)\n> >  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> > -\t\t\topts, allow, opts->edit);\n> > +\t\t\topts, allow, opts->edit, 0);\n> \n> ... even of this makes one need to check the calling convention,\n> what does this 0 mean.\n\nYeah, but it will not remain \"0\", but be replaced by a variable named\n\"amend\"...\n\nThanks for the review,\nDscho"},{"id":"300802","messageId":"alpine.DEB.2.20.1609011543290.129229@virtualbox","threadId":"43954","inReplyTo":"9f2cbc74-3e4d-e7f1-d2dd-e85e0b9168b1@gmail.com","subject":"Re: [PATCH 19/22] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T13:56:05Z","receivedAt":"2016-09-01T13:56:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Thu, 1 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> > @@ -781,7 +785,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n> >  \t}\n> >  \tif (!opts->no_commit)\n> >  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> > -\t\t\topts, allow, opts->edit, 0);\n> > +\t\t\topts, allow, opts->edit, 0, 0);\n> \n> The calling convention begins to look unwieldy, but we have only\n> a single such callsite, and there are quite a bit callsites in\n> Git code that have similar API (\"git grep ', 0, 0' -- '*.c'\").\n> So we don't need to think about alternatives.  Yet.\n\nRight.\n\nPlease note that it will make much more sense in the end, too, as the 0s\nwill be replaced by appropriate variables.\n\n> It's a pity that emulation of named parameters in C requires\n> relying on designated inits from C99\n> \n>   typedef struct {\n>     double pressure, moles, temp;\n>   } ideal_struct;\n> \n>   #define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1,   \\\n>                                         .moles=1, .temp=273.15, __VA_ARGS__})\n> \n>   double ideal_pressure_base(ideal_struct in)\n>   {\n>     return 8.314 * in.moles*in.temp/in.pressure;\n>   }\n> \n>   ... ideal_pressure(.moles=2, .temp=373.15) ...\n\nYeah, that looks unwieldy ;-)\n\nThanks for the review,\nDscho"},{"id":"300803","messageId":"alpine.DEB.2.20.1609011608440.129229@virtualbox","threadId":"43954","inReplyTo":"7996a963-52b5-5f3c-f686-f5cf22573573@gmail.com","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T14:13:57Z","receivedAt":"2016-09-01T14:14:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Thu, 1 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> Subject: [PATCH 21/22] sequencer: left-trim the lines read from the script\n> \n> In the subject, it should probably be without \"the\", as \"lines\"\n> are plural.\n> \n> s/left-trim the lines/left-trim lines/\n\nI am happy that we stepped outside of the \"code correctness\" land into\n\"grammar fix\" land, as it surely means that you are convinced the code is\ncorrect? ;-)\n\nFixed.\n\n> > Interactive rebase's scripts may be indented; We need to handle this\n> > case, too, now that we prepare the sequencer to process interactive\n> > rebases.\n> \n> s/; We need/; we need/\n\nHrmpf. From http://grammar.ccc.commnet.edu/grammar/marks/colon.htm:\n\n\tThere is some disagreement among writing reference manuals about\n\twhen you should capitalize an independent clause following a\n\tcolon. Most of the manuals advise that when you have more than one\n\tsentence in your explanation or when your sentence(s) is a formal\n\tquotation, a capital is a good idea. The NYPL Writer's Guide urges\n\tconsistency within a document; the Chicago Manual of Style says\n\tyou may begin an independent clause with a lowercase letter unless it's\n\tone of those two things (a quotation or more than one sentence).\n\tThe APA Publication Manual is the most extreme: it advises us to\n\talways capitalize an independent clause following a colon. The advice\n\tgiven above is consistent with the Gregg Reference Manual.\n\nBased on that, I think that a capital is the correct case here.\n\n> 'bol' is beginning-of-line, isn't it (a complement to eol)?\n\nYep. How did you guess? :-)\n\nCiao,\nDscho"},{"id":"300804","messageId":"alpine.DEB.2.20.1609011619220.129229@virtualbox","threadId":"43954","inReplyTo":"4c0ee8f6-1302-1dcc-602d-7a84150ec39d@gmail.com","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-01T14:20:49Z","receivedAt":"2016-09-01T14:21:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Thu, 1 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> > The write_message() function safely writes an strbuf to a file.\n> > Sometimes this is inconvenient, though: the text to be written may not\n> > be stored in a strbuf, or the strbuf should not be released after\n> > writing.\n> \n> By \"this\" you mean \"using strbuf\", isn't it?  It is not very obvious,\n> and I think it would be better to say it explicitly.\n\nRephrased.\n\n> > Let's allow for such use cases by refactoring write_message() to allow\n> > for a convenience function write_file_gently(). As some of the\n> > upcoming callers of that new function will want to append a newline\n> > character, let's just add a flag for that, too.\n> \n> This paragraph feels a bit convoluted.\n> \n> As I understand it, you refactor \"safely writing string to a file\"\n> into write_with_lock_file(), and make write_message() use it.  The\n> new function makes it easy to create new convenience function \n> write_file_gently(); as some of the upcoming callers of this new\n> function would want to append a newline character, add a flag for\n> it in write_file_gently(), and thus in write_with_lock_file().\n> \n> Isn't it better / easier to understand?\n\nI don't know, but I took it.\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 5efed2e..f5b5e5e 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -239,22 +239,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n> >  \t}\n> >  }\n> >  \n> > -static int write_message(struct strbuf *msgbuf, const char *filename)\n> > +static int write_with_lock_file(const char *filename,\n> > +\t\t\t\tconst void *buf, size_t len, int append_eol)\n> >  {\n> >  \tstatic struct lock_file msg_file;\n> >  \n> >  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n> >  \tif (msg_fd < 0)\n> >  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n> > -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n> > +\tif (write_in_full(msg_fd, buf, len) < 0)\n> >  \t\treturn error_errno(_(\"Could not write to %s\"), filename);\n> \n> You could have, for consistency, add quotes around filename (see previous\n> error_errno callsite), *while at it*:\n> \n>   \t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n\nDone.\n\n> > -\tstrbuf_release(msgbuf);\n> > +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n> > +\t\treturn error_errno(_(\"Could not write eol to %s\"), filename);\n> \n> Same here, and it wouldn't even be 'while at it'\n\nDone.\n\n>   +\t\treturn error_errno(_(\"Could not write eol to '%s'\"), filename);\n> \n> \n> >  \tif (commit_lock_file(&msg_file) < 0)\n> >  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n> \n> Another \"while at it\"... though the one that can be safely postponed\n> (well, the make message easier to understand part, not the quote\n> filename part):\n> \n>   \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n\nAs I inherited this message, I'll keep it.\n\n> And thus we got to the last patch in this series.  I have skipped\n> patches that already got reviewed; are there some that you would\n> like to have second review of?  Is there patch series that needs\n> to be applied earlier that needs a review?\n\nThank you for your review!\nDscho"},{"id":"300818","messageId":"xmqqinufwjou.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609010830110.129229@virtualbox","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-01T18:37:05Z","receivedAt":"2016-09-01T20:55:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> git continue as a shorthand for `git <relevant-cmd> --continue` sounds great.\n>\n> Before we get ahead of ourselves:\n>\n> 1) this has nothing to do with the patch series at hand, and\n>\n> 2) if we were to introduce `git continue`, we would need to think long and\n>    hard about the following issues:\n>\n> \tI) are there potentially ambiguous <relevant-cmd>s that the user\n> \t   may want to continue?\n>\n> \tII) what about options? You can say `git rebase --continue\n> \t    --no-ff`, for example, but not `git cherry-pick --continue\n> \t    --no-ff`...\n>\n> \tIII) Would it not be confusing to have a subcommand `continue`\n> \t     that does *not* serve a *single* purpose? It's kinda flying\n> \t     into the face of the Unix philosophy.\n\nThe above reasoning applies equally to \"git abort\".  I do not think\n\"git continue\" would help.\n\nIf it were that anything you can do with Git can be --continue'ed\nthe same way (e.g. all uses one sequencer to rule them all), it\nmight be achievable, but I do not think it isn't, and will never be.\n\n\"git commit\" may say \"You haven't added anything yet\" and refuse to\ndo anything.  Should \"git continue\" do \"git commit -a\" by noticing\nthat the last thing you tried to do was \"git commit\" and guess that\nit is likely you wanted to commit all changes?  I think not.\n"},{"id":"300820","messageId":"xmqqvayfwlgu.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011608440.129229@virtualbox","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-01T17:58:41Z","receivedAt":"2016-09-01T20:55:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > Interactive rebase's scripts may be indented; We need to handle this\n>> > case, too, now that we prepare the sequencer to process interactive\n>> > rebases.\n>> \n>> s/; We need/; we need/\n>\n> Hrmpf. From http://grammar.ccc.commnet.edu/grammar/marks/colon.htm:\n>\n> \tThere is some disagreement among writing reference manuals about\n> \twhen you should capitalize an independent clause following a\n> \tcolon. Most of the manuals advise that when you have more than one\n> \tsentence in your explanation or when your sentence(s) is a formal\n> \tquotation, a capital is a good idea. The NYPL Writer's Guide urges\n> \tconsistency within a document; the Chicago Manual of Style says\n> \tyou may begin an independent clause with a lowercase letter unless it's\n> \tone of those two things (a quotation or more than one sentence).\n> \tThe APA Publication Manual is the most extreme: it advises us to\n> \talways capitalize an independent clause following a colon. The advice\n> \tgiven above is consistent with the Gregg Reference Manual.\n>\n> Based on that, I think that a capital is the correct case here.\n\nDoes that manual have anything to say about semicolons, which is a\ndifferent thing?\n"},{"id":"300823","messageId":"486c22a4-9334-4c83-746e-7ff6663ce4ab@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609010957300.129229@virtualbox","subject":"Re: [PATCH 08/22] sequencer: remove overzealous assumption","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T20:00:40Z","receivedAt":"2016-09-01T20:56:45Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 10:01, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote:\n>> W dniu 31.08.2016 o 20:36, Johannes Schindelin pisze:\n>>\n>> I wonder: would 'git cherry-pick --continue' be able to finish\n>> 'git revert', and vice versa, then?  Or 'git sequencer --continue'?\n> \n> I just tested this, via\n> \n> \tdiff --git a/t/t3510-cherry-pick-sequence.sh\n> \tb/t/t3510-cherry-pick-sequence.sh\n> \tindex 96c7640..085d8bc 100755\n> \t--- a/t/t3510-cherry-pick-sequence.sh\n> \t+++ b/t/t3510-cherry-pick-sequence.sh\n> \t@@ -55,7 +55,7 @@ test_expect_success 'cherry-pick\n> \tmid-cherry-pick-sequence' '\n> \t\tgit checkout HEAD foo &&\n> \t\tgit cherry-pick base &&\n> \t\tgit cherry-pick picked &&\n> \t-       git cherry-pick --continue &&\n> \t+       git revert --continue &&\n> \t\tgit diff --exit-code anotherpick\n> \n> (Danger! Whitespace corrupted!!!)\n> \n> It appears that this passes now.\n\nI'm now not sure if it is such a great idea.  As was said somewhere else\nin this thread, different sequencer-based commands sports different\noptions, and you can add options to the \"git <command> --continue\".\nFor example you can say \"git cherry-pick --continue -x\", but you\ncannot say \"git revert --continue -x\", as '-x' is a cherry-pick only\noption.  Or you can, theoretically, use \"git am --continue --no-3way\".\n\nOne option is to temporarily relax the test (test_expect_failure),\nthen fix it at the end.\n\n\nBTW. how git-am uses sequencer?  I have seen \"revert\" etc., and \"pick\"\netc., but no git-am related constants or strings...\n\n> Probably `git sequencer --continue` would work, too, if there was a `git\n> sequencer`. :0)\n\nRight.\n\n> \n>>> On Wed, 31 Aug 2016, Jakub Narębski wrote: \n>>>> W dniu 29.08.2016 o 10:04, Johannes Schindelin pisze:\n>>  \n>>>>> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n>>>>> index 7b7a89d..6465edf 100755\n>>>>> --- a/t/t3510-cherry-pick-sequence.sh\n>>>>> +++ b/t/t3510-cherry-pick-sequence.sh\n>>>>> @@ -459,17 +459,6 @@ test_expect_success 'malformed instruction sheet 1' '\n>>>>>  \ttest_expect_code 128 git cherry-pick --continue\n>>>>>  '\n>>>>>  \n>>>>> -test_expect_success 'malformed instruction sheet 2' '\n>>>>\n>>>> Hmmm... the description is somewhat lacking (especially compared to\n>>>> the rest of test), anyway.\n>>>>\n>>>> BTW. we should probably rename 'malformed instruction sheet 2'\n>>>> to 'malformed instruction sheet' if there are no further such\n>>>> tests after this removal, isn't it?\n>>>\n>>> No, we cannot rename it after this patch because the patch removes it ;-)\n>>> (It is not a file name but really a label for a test case.)\n>>\n>> Ooops.  What I wanted to say that after removing the test case named\n>> 'malformed instruction sheet 2' we should also rename *earlier* test\n>> case from 'malformed instruction sheet 1' to 'malformed instruction sheet',\n>> as it is now the only 'malformed instruction sheet *' test case.\n> \n> Actually, you know, I completely missed the fact that there was a\n> \"malformed instruction sheet 3\". I renumbered it.\n\nOoops.  I have missed it too, having looked only at the test after the\none removed (which is not about malformed instruction sheet).\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"300830","messageId":"xmqqeg53wj7a.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011052260.129229@virtualbox","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-01T18:47:37Z","receivedAt":"2016-09-01T21:05:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> though).  The \"one sequencer to rule them all\" may even have to say\n>> \"now give name ':1' to the result of the previous operation\" in one\n>> step and in another later step have an instruction \"merge ':1'\".\n>> When that happens, you cannot even pre-populate the commit object\n>> when the sequencer reads the file, as the commit has not yet been\n>> created at that point.\n>\n> These considerations are pretty hypothetical. I would even place a bet\n> that we will *never* have \":1\" as names, not if I have anything to say...\n> ;-)\n\nIf you can always work with pre-existing commit, then you can\nvalidate all object references that appear in the instructions\nupfront.\n\nI was sort of expecting that, when you do the preserve-merges mode\nof \"rebase -i\", you would need to jump around, doing \"we have\nreconstructed the side branch on a new 'onto', let's give the result\nthis temporary name ':1', and then switch to the trunk (which would\ncall for 'reset <commit>' instruction) and merge that thing (which\nwould be 'merge :1' or perhaps called 'pick :1')\", and at that point\nyou no longer validate the object references upfront.\n\nIf you do not have to have such a \"mark this point\" and a \"refer to\nthat point we previously marked\", then I agree that you should be\nable to pre-validate and keep the result in the structure.\n"},{"id":"300843","messageId":"d8112b27-8de3-0860-e902-fb271b80a0e7@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609010836010.129229@virtualbox","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T22:05:14Z","receivedAt":"2016-09-01T22:05:29Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 09:49, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote: \n>> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n[...]\n\n>> Hmmm... commit_list is, as defined in commit.h, a linked list.\n> \n> That is the most prominent reason why the rest is not a mindless\n> conversion from commit_list to todo_list.\n> \n> And we need todo_list as an array, because we need to be able to peek, or\n> even move, backwards from the current command.\n> \n>> Here todo_list uses growable array implementation of list.  Which\n>> is I guess better on current CPU architecture, with slow memory,\n>> limited-size caches, and adjacency prefetching.\n> \n> That is not the reason that an array is used here. The array allows us\n> much more flexibility.\n\nIt would be nice if this reasoning (behind the change from linked list\nto growable array) was mentioned in appropriate commit message, and\nperhaps also in the cover letter for the series.  It is IMVHO quite\nimportant information (that you thought obvious).\n\n> \n> One of the major performance improvements will come at the very end, for\n> example: the reordering of the fixup!/squash! lines. And that would be a\n> *major* pain to do if the todo_list were still a linked list.\n\nActually deletion from and insertion into single linked list are\nnot that hard, and O(1) after finding place, O(N) with finding\nincluded.  Moving elements in array is O(N),... and arguably a bit\nsimpler - but at high level, with appropriate primitives, they are\nabout the same.\n\nYes, array is easier for permutation and reordering.\n\n>>> +struct todo_item *append_todo(struct todo_list *todo_list)\n>>\n>> Errr... I don't quite understand the name of this function.\n>> What are you appending here to the todo_list?\n> \n> A new item.\n> \n>> Compare string_list_append() and string_list_append_nodup(),\n>> where the second parameter is item to append.\n> \n> Yes, that is correct. In the case of a todo_item, things are a lot more\n> complicated, though. Some of the values have to be determined tediously\n> (such as the offset and length of the oneline after the \"pick <oid>\"\n> command). I just put those values directly into the newly allocated item,\n> is all.\n\nI would expect sth_append command to take a list (or other collection),\nan element, and return [modified] collection with the new element added.\nSuch API would require temporary variable in caller and memcopy in the\nsth_append() function.\n\nThis is not it.  It creates a new element, expanding a list (a collection),\nand then expose this element.  Which spares us memcopy... on non-critical\npath.\n\nI don't know how to name operation \"grow list and return new element\".\nBut \"append\" it is not.\n \n>>> +\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n>>> +\treturn todo_list->items + todo_list->nr++;\n>>>  }\n>>>  \n>>> -static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n>>> +static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n>>\n>> Why the change of return type?  \n> \n> Because it makes no sense to return a commit here because not all commands\n> are about commits (think rebase -i's `exec`). It makes tons of sense to\n> return an error condition, though.\n\nAll right.\n\nI have not checked / not remember what caller of parse_insn_line() used\nit's return value for.  I guess that we save it into todo_item, moving\nthat operation from caller to callee.\n\n>> Why now struct todo_item is first when struct replay_opts was last?\n> \n> Those play very, very different roles.\n> \n> The opts parameter used to provide parse_insn_line() with enough\n> information to complain loudly when the overall command was not identical\n> to the parsed command.\n> \n> The item parameter is a receptacle for the parsed data. It will contain\n> the pointer to the commit that was previously returned, if any. But it\n> will also contain much more information, such as the command, the oneline,\n> the offset in the buffer, etc etc\n> \n> So \"opts\" was an \"in\" parameter while \"item\" is an \"out\" one. Apples and\n> oranges.\n\nAll right.  Good explanation.  And the one that is too low-level\ndetail to put in the commit message, I think.\n\n>>> -\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n>>> +\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n>>\n>> Why is this cast needed?\n> \n> Because bol is a \"const char *\" and we need to put \"NUL\" temporarily to\n> *end_of_object_name:\n\nWould compiler complain without this const'ness-stripping cast?\n\n> \n>>>  \tsaved = *end_of_object_name;\n>>>  \t*end_of_object_name = '\\0';\n>>>  \tstatus = get_sha1(bol, commit_sha1);\n>>>  \t*end_of_object_name = saved;\n> \n> Technically, this would have made a fine excuse to teach get_sha1() a mode\n> where it expects a length parameter instead of relying on a NUL-terminated\n> string.\n> \n> Practically, such fine excuses cost me months in this rebase--helper\n> project already, and I need to protect my time better.\n\nPut it in TODO list (and perhaps add a TODO comment) ;-).\n\nBTW. open-source produces better software, and development bandwidth\nis good, but the latency :-(((( \n\n> \n>>> -\t/*\n>>> -\t * Verify that the action matches up with the one in\n>>> -\t * opts; we don't support arbitrary instructions\n>>> -\t */\n>>> -\tif (action != opts->action) {\n>>> -\t\tif (action == REPLAY_REVERT)\n>>> -\t\t      error((opts->action == REPLAY_REVERT)\n>>> -\t\t\t    ? _(\"Cannot revert during another revert.\")\n>>\n>> Errr... could the above ever happen?  Namely\n>>\n>>   action != opts->action && action == REPLAY_REVERT && opts->action == REPLAY_REVERT\n>>\n>> Surely not.\n> \n> Your reply pointed to the very circumstance when this may happen: `git\n> cherry-pick --continue` after an interrupted `git revert`.\n\nI was talking about \"Cannot revert during another revert.\" and\n\"Cannot cherry-pick during another cherry-pick.\" errors, which can\nnever happen because of the outermost if.\n\n   x == A && y == A && x != Y\n\ncan never happen, because equality is transitive^*\n\n   x == A && y == A  =>  x == y\n\n*) except NaN (NaN != NaN), but we don't deal with floating point here.\n\n\nFrom those error messages it looks like they were originally intended\nto prevent from starting another revert or cherry-pick if sequencer\nbased operation is already in progress (to not stomp on the latter\ninternal state).  But for that it would need to examine the\nopts->subcommand if it is REPLAY_NONE (or equivalent), check that\nsequencer file already exists, and read it to fond which operation\nis in progress.\n\nThis is about checking that command in todo-list agrees with\nthe git command used (we probably checked that it is --continue,\nor maybe --skip).  But the error message does not spell that;\nit is misleading.\n\n[Nb. git-blame shows Vasco Almeida as author of those lines]\n\n> \n> But then, I remove that code here, so I should not try to defend it.\n> \n\nBut that was / is another reason for removing code: it is slightly\nwrong.\n\n>>> -\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n>>> -\t\telse\n>>> -\t\t      error((opts->action == REPLAY_REVERT)\n>>> -\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n>>> -\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n>>> -\t\treturn NULL;\n>>> -\t}\n>>\n>> Anyway, while it is / would be a good idea to prevent starting any\n>> sequencer-based command (cherry-pick, revert, soon rebase -i) when\n>> other command is in progress (cherry-pick, revert, soon rebase -i).\n>> That is, if cherry-pick / revert waits for user action, you cannot\n>> run another cherry-pick or revert.\n>>\n>> Which I guess the above code was not about...\n> \n> It was about that, though.\n\nNo it was not, see the reasoning above.\n\n> \n> It went about it in a pretty round-about way: opts->action comes from the\n> name of the command (\"was I called as `git revert` or `git cherry-pick`?\")\n> and action comes from the todo script, which was assumed to be written by\n> a previous run of the sequencer, using the then-current value of\n> opts->action.\n\nIt did different check, that we continue with the same command\nas we began with.\n\n> \n> So it wrote that command into *every single line* of the todo script, *for\n> the sole purpose* of verifying that it was the same action when running\n> via --continue.\n> \n> As I said earlier, I would not complain at all if an interrupted `git\n> revert` could be continued via `git cherry-pick --continue`.\n> \n> If that is not desirable, I can reintroduce that overzealous check, but\n> that will have to wait until after v2.10.0. And it would require an\n> argument that convinces me.\n\nOne argument is that you can add options to --continue, and among\noptions for cherry-pick, revert and rebase -i, there are options\nthat apply only to some of them.  So we need at least decide what\nto do if we started rebase, and try to continue with cherry-pick:\ndo we accept rebase-only options?  What we do with cherry-pick-only\noptions, that rebase does not understand?\n\nIt is easier to just check that revert is continued with revert\n(by checking command in todo file), cherry-pick with cherry-pick\n(same), rebase -i with rebase (by checking another file), and\nam with am.\n\n> \n>>> +\t\titem = append_todo(todo_list);\n>>\n>> A better name, in my personal option, would be\n>>\n>>   +\t\titem = todo_list_next(todo_list);\n>>\n>> Or todo_next(todo_list).\n> \n> That sounds more like a function that performs the next command in the\n> todo_list.\n> \n> While I agree that naming is hard, I still think that `append_todo()` with\n> the todo_list as single parameter and returning a todo_item is pretty much\n> self-explanatory: it appends a new item to the todo_list and returns a\n> pointer to it.\n\nIt creates new item in the todo_list at the end, or it grows todo_list,\nbut the function does not append anything...\n\n[...]\n>>> -\tif (strbuf_read(&buf, fd, 0) < 0) {\n>>> +\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n>>>  \t\tclose(fd);\n>>> -\t\tstrbuf_release(&buf);\n>>\n>> A question: when is todo_list->buf released?\n> \n> Why, I am glad you asked! It is released in todo_list_release(), called at\n> the end e.g. of sequencer_continue().\n\nAll right.  I could have guessed that.\n\n>>> -static int walk_revs_populate_todo(struct commit_list **todo_list,\n>>> +static int walk_revs_populate_todo(struct todo_list *todo_list,\n>>>  \t\t\t\tstruct replay_opts *opts)\n>>>  {\n>>> +\tenum todo_command command = opts->action == REPLAY_PICK ?\n>>> +\t\tTODO_PICK : TODO_REVERT;\n>>>  \tstruct commit *commit;\n>>> -\tstruct commit_list **next;\n>>>  \n>>>  \tif (prepare_revs(opts))\n>>>  \t\treturn -1;\n>>>  \n>>> -\tnext = todo_list;\n>>> -\twhile ((commit = get_revision(opts->revs)))\n>>> -\t\tnext = commit_list_append(commit, next);\n>>> +\twhile ((commit = get_revision(opts->revs))) {\n>>> +\t\tstruct todo_item *item = append_todo(todo_list);\n>>> +\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n>>\n>> I see that you are creating todo file contents while walking revision list,\n>> something that was left for later in current / previous implementation\n>> of the sequencer...\n> \n> Not really. This function was always about generating a todo_list. It just\n> did not format it yet.\n> \n> With the change of keeping the original formatting of the todo script\n> instead of re-formatting it in save_todo(), this function now has to\n> format the todo_list itself.\n\nSo the commit parsing was moved from save_todo(), which contrary to\nthe name also re-generated todo list, to walk_revs_populate_todo().\nI guess it is the same callchain.\n\nAdditional question, answer to which should address Junio's complaint\nabout early/eager commit parsing (if I understand it correctly):\ndo information from parsing commit is needed for creating a new\ncommit, i.e. doing a pick or revert?  If not, then perhaps parsing\nonly those commits that are left, at the time of saving todo file\n(with probably less commit that what we have started with), would\nbe better?\n\n[...]\n>>> -static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n>>> +static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>>>  {\n>>>  \tstatic struct lock_file todo_lock;\n>>> -\tstruct strbuf buf = STRBUF_INIT;\n>>> -\tint fd;\n>>> +\tconst char *todo_path = get_todo_path(opts);\n>>> +\tint next = todo_list->current, offset, fd;\n>>\n>> The \"next = todo_list->current\" looks a bit strange.\n> \n> Depending whether we need rebase -i processing or revert/cherry-pick's\n> slightly different one, the \"current\" position points to the next one\n> already...\n> \n>> Also, we do not change todo_list->current, we use it in one place, so it\n>> can be used directly without help of temporary / helper variable.  But\n>> that is just my personal opinion.\n> \n> No, it has nothing to do with opinion. It prepares the code to keep it\n> readable even when REPLAY_INTERACTIVE_REBASE is introduced.\n\nAh, all right.\n\n[...]\n>> and this should be done in one of earlier patches, isn't it?\n> \n> No. I deliberately skipped save_todo() from \"future-proofing\" as I planned\n> to rewrite it anyway. There is no point in future-proofing something you\n> are going to toss in a minute.\n> \n\nAll right.  Though I wonder if it should not be mentioned in\nthe commit message of said previous patch (though I have missed\nthat not all sites were \"future-proofed\" in review; I'm sorry).\n\n>>> -\tif (commit_lock_file(&todo_lock) < 0) {\n>>> -\t\tstrbuf_release(&buf);\n>>> -\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n>>> -\t}\n>>> -\tstrbuf_release(&buf);\n>>> +\tif (commit_lock_file(&todo_lock) < 0)\n>>> +\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n>>\n>> Note: this is unrelated change, but we usually put paths in quotes, like this\n>>\n>>   +\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n>>\n>> (in this and earlier error message), so that paths containing spaces show\n>> correctly and readably to the user.  Though this possibly is not a problem\n>> for this path.\n> \n> Right.\n> \n>> Also, how user is to understand \"wrapping up\"?\n> \n> The same as before: the removed lines already had the error message,\n> missing the quotes, too.\n> \n> Don't get me wrong: I am a big fan of consistency, and I wish that Git's\n> source code had more of it. So I would love to see a patch series that\n> makes all error messages consistently reporting paths enclosed in single\n> quotes.\n> \n> I am also a big fan of the separation of concerns, though. And this patch\n> series' concern is consistency *with the existing code*.\n> \n> So I won't change the error message that I inherited at this point.\n\nAll right, I can understand that.  But I think it won't cost\nmuch to do _while at it_ adding of quotes around pathnames in\nerror messages, where you notice this problem.\n \n>>>  static int single_pick(struct commit *cmit, struct replay_opts *opts)\n>>>  {\n>>>  \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n>>> -\treturn do_pick_commit(cmit, opts);\n>>> +\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n>>> +\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n>>\n>> The ternary conditional operator here translates one enum to other enum,\n>> isn't it?\n> \n> Well, almost. Please note that the enum will receive a new value in the\n> sequencer-i patch series. And there is no equivalent todo_command for\n> REPLAY_INTERACTIVE_REBASE.\n\nAll right.  And casting one enum to other, relying on the same\norder, is tricky to the extreme and brittle.\n\n> \n> Thanks for the review!\n\nYou are welcome.\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"300850","messageId":"198780d4-dbef-c0cc-fb4c-fc8986a33002@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609010950150.129229@virtualbox","subject":"Re: [PATCH 10/22] sequencer: avoid completely different messages for different actions","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T22:33:29Z","receivedAt":"2016-09-01T22:33:52Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes\n\nW dniu 01.09.2016 o 09:52, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote:\n>> CC-ed to Jiang Xin, L10N coordinator.\n>> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n\n[...]\n>>> -\t/* Different translation strings for cherry-pick and revert */\n>>> -\tif (opts->action == REPLAY_PICK)\n>>> -\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n>>> -\telse\n>>> -\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n>>> +\terror(_(\"Your local changes would be overwritten by %s.\"),\n>>> +\t\taction_name(opts));\n>>\n>> If I understand it correctly, it would make \"revert\" or \"cherry-pick\"\n>> untranslated part of error message.  You would need to use translation\n>> on the result with \"_(action_name(opts))\", you would have to mark\n>> todo_command_strings elements for gettext lexicon with N_(...).\n>>\n>> I am rather against this change (see also below).\n> \n> Okay.\n> \n> Unfortunately, I have to focus on the correctness of the code at the\n> moment (and Git for Windows does ship *without* translations for the time\n> being anyway, mostly to save on space, but also because users complained).\n\nUsers complained about having translations, or not having easy way to\nswitch them or switch them off?\n\n> \n> So I will take care of this after v2.10.0.\n> \n> For the record, how is this supposed to be handled, in particular when I\n> introduce a new action whose action_name(opts) will be \"rebase -i\"? Do I\n> really need to repeat myself three times?\n\nI think you should be able to mark strings to be translated,\nwithout translating them at the time of definition,\n\n  static const char *todo_command_strings[] = {\n  \tN_(\"pick\"),\n  \tN_(\"revert\")\n  };\n\nthen translate at the point of use\n\n  \terror(_(\"Your local changes would be overwritten by %s.\"),\n\t\t_(action_name(opts)));\n\nI assume that action_name(opts) returns one of todo_command_strings.\nIf not, there should be array with possible actions.\n\n\nAssuming that such lego l10n is preferable to multiple translations,\nmore free-formt.\n\n-- \nJakub Narębski\n\n"},{"id":"300852","messageId":"63004be3-04de-00c5-a94d-1b600201bc6f@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011052260.129229@virtualbox","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T22:46:19Z","receivedAt":"2016-09-01T22:46:32Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 01.09.2016 o 11:37, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Junio C Hamano wrote:\n>> Jakub Narębski <jnareb@gmail.com> writes:\n>>\n>>>> diff --git a/sequencer.c b/sequencer.c\n>>>> index 06759d4..3398774 100644\n>>>> --- a/sequencer.c\n>>>> +++ b/sequencer.c\n>>>> @@ -709,6 +709,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>>>>  struct todo_item {\n>>>>  \tenum todo_command command;\n>>>>  \tstruct commit *commit;\n>>>> +\tconst char *arg;\n>>>> +\tint arg_len;\n>>>\n>>> Why 'arg', and not 'oneline', or 'subject'?\n>>> I'm not saying it is bad name.\n>>\n>> I am not sure what the \"commit\" field of type \"struct commit *\" is\n>> for.  It is not needed until it is the commit's turn to be picked or\n>> reverted; if we end up stopping in the middle, parsing the commit\n>> object for later steps will end up being wasted effort.\n> \n> No, it won't be wasted effort, as we *validate* the todo script this way.\n> And since we may very well need the info later (most rebases do not fail\n> in the middle), we store it, too.\n\nThe question was (I think) whether we should do eager parsing of\ncommits, or whether we can do lazy parsing by postponing full parsing\n\"until it is the commit's turn to be picked or reverted\", and possibly\nwhen saving todo file.\n\nI wonder how probable is situation where we save instruction sheet\nfor interactive rebase, with shortened SHA-1, and during rebase\nshortened SHA-1 stops being unambiguous...\n\n>                                [...] after parsing the todo_list, we will\n> have to act on the information contained therein. For example we will have\n> to cherry-pick some of the indicated commits (requiring a struct commit *\n> for use in do_pick_commit()). Another example: we may need to determine\n> the oneline for use in fixup!/squash! reordering.\n> \n> So: keeping *that* aspect of the previous todo_list parsing, i.e. store a\n> pointer to the already-parsed commit, is the right thing to do.\n\nThe above probably means that eager eval is better\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"300854","messageId":"58587e4a-a326-2676-6d32-4a570b27dbf8@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011507130.129229@virtualbox","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T22:52:55Z","receivedAt":"2016-09-01T22:53:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello,\n\nW dniu 01.09.2016 o 15:12, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote:\n>> W dniu 31.08.2016 o 21:10, Junio C Hamano pisze:\n\n>>> So I am not sure if we want a parsed commit there (I would not\n>>> object if we kept the texual object name read from the file,\n>>> though).  The \"one sequencer to rule them all\" may even have to say\n>>> \"now give name ':1' to the result of the previous operation\" in one\n>>> step and in another later step have an instruction \"merge ':1'\".\n>>> When that happens, you cannot even pre-populate the commit object\n>>> when the sequencer reads the file, as the commit has not yet been\n>>> created at that point.\n>>\n>> True, --preserve-merges rebase is well, different.\n> \n> It is mis-designed. And I can be that harsh because it was my design.\n> \n> In the meantime I came up with a much better design, and implemented it as\n> a shell script on top of rebase -i. Since shell scripts run like slow\n> molasses, even more so on Windows, I have a loose plan to implement its\n> functionality as a new --recreate-merges option, and to deprecate\n> --preserve-merges when that new option works.\n> \n> It needs to be a new option (not a --preserve-merges=v2) because it is a\n> totally different beast. For starters, it does not need its own code path\n> that overrides pick_one, as --preserve-merges does.\n\nBetter preserving for merges (with cleanly defined sematics)\nwould be certainly nice to have.\n\n> But I get way ahead of myself. First we need to get these last few bits\n> and pieces in place to accelerate (non --preserve-merges) rebase -i.\n\nBut it can wait, right.\n\n-- \nJakub Narębski\n\n"},{"id":"300855","messageId":"xmqqvayftefc.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"63004be3-04de-00c5-a94d-1b600201bc6f@gmail.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-01T22:59:03Z","receivedAt":"2016-09-01T22:59:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> I wonder how probable is situation where we save instruction sheet\n> for interactive rebase, with shortened SHA-1, and during rebase\n> shortened SHA-1 stops being unambiguous...\n\nIt is my understanding that the shortened ones are only for end-user\nconsumption.  The insn sheet internally uses fully expanded form for\nthis exact reason, and then abbreviated back at each step before the\nupdated one is presented to the end-user.  Uniqueness guarantee is\nenforced with new objects created during each step taken into\naccount by doing it this way.\n\n\n"},{"id":"300857","messageId":"528839ae-a0dc-e40f-a9a5-e1f25e8b3cc4@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011516080.129229@virtualbox","subject":"Re: [PATCH 16/22] sequencer: prepare for rebase -i's GPG settings","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T23:21:52Z","receivedAt":"2016-09-01T23:22:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 15:33, Johannes Schindelin pisze:\n> On Wed, 31 Aug 2016, Jakub Narębski wrote:\n>> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n>>> @@ -471,17 +487,20 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>>>  \n>>>  \tif (IS_REBASE_I()) {\n>>>  \t\tenv = read_author_script();\n>>> -\t\tif (!env)\n>>> +\t\tif (!env) {\n>>> +\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n>>> +\n>>>  \t\t\treturn error(\"You have staged changes in your working \"\n>>>  \t\t\t\t\"tree. If these changes are meant to be\\n\"\n>>>  \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n>>> -\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n>>\n>> How did this get expanded by error(), and why we want to replace\n>> it if it works?\n\nAfter writing this email, I got an idea on how it could work:\ngit-rebase script calls some C helper, which outputs above, and\noutput of this helper is eval'ed by script (with gpg_sign_opt_quoted\nvariable present in the environment)...\n\n> \n> It did not work. It was a place-holder waiting for this patch ;-)\n> \n\n... but it might have been simply copy'n'pasted from shell script\nto C, literally.\n\n>>\n>>> +\t\t\t\t\"  git commit --amend %s\\n\\n\"\n>>>  \t\t\t\t\"If they are meant to go into a new commit, \"\n>>>  \t\t\t\t\"run:\\n\\n\"\n>>> -\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n>>> +\t\t\t\t\"  git commit %s\\n\\n\"\n>>>  \t\t\t\t\"In both case, once you're done, continue \"\n>>>  \t\t\t\t\"with:\\n\\n\"\n>>> -\t\t\t\t\"  git rebase --continue\\n\");\n>>> +\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n>>\n>> Instead of passing option twice, why not make use of %1$s (arg reordering),\n>> that is\n>>\n>>   +\t\t\t\t\"  git commit --amend %1$s\\n\\n\"\n>> [...]\n>>   +\t\t\t\t\"  git commit %1$s\\n\\n\"\n> \n> Cute. But would this not drive the l10ners insane?\n> \n\nShouldn't, as l10ners need to deal with arg reordering, because in different\nlanguages the order of words might be different: %s %s in English may be\n%2$s %1$s in other language, see example in\n  https://www.gnu.org/software/gettext/manual/gettext.html#c_002dformat-Flag\n\nBest,\n-- \nJakub Narębski\n"},{"id":"300858","messageId":"80a779a5-70d3-64dc-d206-41c47e1c69f5@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011543290.129229@virtualbox","subject":"Re: [PATCH 19/22] sequencer: support cleaning up commit messages","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T23:31:48Z","receivedAt":"2016-09-01T23:32:00Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 15:56, Johannes Schindelin pisze: \n> On Thu, 1 Sep 2016, Jakub Narębski wrote:\n\n>> It's a pity that emulation of named parameters in C requires\n>> relying on designated inits from C99\n>>\n>>   typedef struct {\n>>     double pressure, moles, temp;\n>>   } ideal_struct;\n>>\n>>   #define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1,   \\\n>>                                         .moles=1, .temp=273.15, __VA_ARGS__})\n>>\n>>   double ideal_pressure_base(ideal_struct in)\n>>   {\n>>     return 8.314 * in.moles*in.temp/in.pressure;\n>>   }\n>>\n>>   ... ideal_pressure(.moles=2, .temp=373.15) ...\n\nForgot to add citation:\n\n[1] Ben Klemens \"21st Century C: C Tips from the New School\", 2nd Ed. (2014),\n    O'Reilly Media, chapter 10. \"Better Structures\", subsection\n    \"Optional and Named Arguments\"\n\n> \n> Yeah, that looks unwieldy ;-)\n>\n\nDeclaration needs some trickery, but use is much, much more readable\n(if we cannot use sensibly named variables for passing arguments):\n\n  ideal_pressure()\n  ideal_pressure(.temp=373.15)\n  ideal_pressure(.moles=2)\n  ideal_pressure(.moles=2, .temp=373.15) \n\nIt is even better if there are large amount of parameters:\n\n  res = amortization(.amount=200000, .inflation=3,\n                     .show_table=0, .extra_payoff=100)\n\nvs\n\n  double amortize(double amt, double rate, double inflation, int months,\n            int selloff_month, double extra_payoff, int verbose,\n            double *interest_pv, double *duration, double *monthly_payment);\n\n \nBut we can't use it in Git, anyway\n-- \nJakub Narębski\n\n"},{"id":"300859","messageId":"54cc3d11-6384-b666-3103-4e56a399ba6d@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011608440.129229@virtualbox","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T23:33:32Z","receivedAt":"2016-09-01T23:33:43Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 16:13, Johannes Schindelin pisze: \n> On Thu, 1 Sep 2016, Jakub Narębski wrote:\n \n>> 'bol' is beginning-of-line, isn't it (a complement to eol)?\n> \n> Yep. How did you guess? :-)\n\nWouldn't 'beg' and 'end' instead of 'bol' and 'eol' be easier\nto understand, thus more readable?\n\n-- \nJakub Narębski\n\n"},{"id":"300860","messageId":"dbc1b08c-a151-29ab-a5a2-45343ca556d6@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609011619220.129229@virtualbox","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-01T23:35:36Z","receivedAt":"2016-09-01T23:35:50Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 01.09.2016 o 16:20, Johannes Schindelin pisze:\n> On Thu, 1 Sep 2016, Jakub Narębski wrote: \n>> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n\n>>>  \tif (commit_lock_file(&msg_file) < 0)\n>>>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>>\n>> Another \"while at it\"... though the one that can be safely postponed\n>> (well, the make message easier to understand part, not the quote\n>> filename part):\n>>\n>>   \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n> \n> As I inherited this message, I'll keep it.\n\nWell, please then add quotes while at it, at least, for consistency\n\n  \t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n\nBest,\n-- \nJakub Narębski\n\n"},{"id":"300880","messageId":"ced4a190-6a79-e608-ca0b-3815267c5f93@gmail.com","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 00/22] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-02T11:41:02Z","receivedAt":"2016-09-02T11:41:16Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 29.08.2016 o 10:03, Johannes Schindelin pisze:\n\n> This patch series marks the  '4' in the countdown to speed up rebase -i\n> by implementing large parts in C. It is based on the `libify-sequencer`\n> patch series that I submitted last week.\n\nWhich of those got reviewed (and perhaps accepted), and which of those\nneeds review still?  What is subject of their cover letter?\n\n> \n> The patches in this series merely prepare the sequencer code for the\n> next patch series that actually teaches the sequencer to run an\n> interactive rebase.\n> \n> The reason to split these two patch series is simple: to keep them at a\n> sensible size.\n\nThat's good.\n\n> \n> The two patch series after that are much smaller: a two-patch \"series\"\n> that switches rebase -i to use the sequencer (except with --root or\n> --preserve-merges), and a couple of patches to move several pretty\n> expensive script processing steps to C (think: autosquash).\n\nI can understand --preserve-merges, but what is the problem with --root?\n\n> \n> The end game of this patch series is a git-rebase--helper that makes\n> rebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\n> that even MacOSX and Linux benefit (4x and 3x, respectively).\n\nSo do I understand correctly that end goal for *this* series is to move\nmost of processing to git-rebase--helper, but full builtin-ification\n(and retiring git-rebase.sh to contrib/examples/) would have to wait\nfor later?\n\n[...]\n\nI'd like here to summarize the discussion (my review, Dennis review,\nJohannes Sixt and Junio comments).\n\nIf there are no comments, it means no problems or minor changes.\n\n> Johannes Schindelin (22):\n>   sequencer: use static initializers for replay_opts\nThere is no need for putting zeros in static initializer.  Commit\nmessage expanded.\n\n>   sequencer: use memoized sequencer directory path\n>   sequencer: avoid unnecessary indirection\n>   sequencer: future-proof remove_sequencer_state()\nLeftover unrelated chunk removed.\n\n>   sequencer: allow the sequencer to take custody of malloc()ed data\nIs introducing new *_entrust() mechanism (which needs docs, at least\nas comments) worth it, instead of just strdup everything and free?\nIf it is: naming of function parameter + example in commit message.\n\n>   sequencer: release memory that was allocated when reading options\nSee above.\n\n>   sequencer: future-proof read_populate_todo()\nPossibly mention which functions were not future-proofed because\nof planned for the subsequent patch full rewrite.\n\n>   sequencer: remove overzealous assumption\nOverzealous assumptions, or a worthy check?  Perhaps just remove check\nfor rebase -i in future commit, and keep test.  Perhaps remove test\ntemporarily.\n\n>   sequencer: completely revamp the \"todo\" script parsing\nThis removes check; it should return if it was worthy.  Some discussion\nabout eager versus lazy parsing of commits, but IMHO it should be left\nfor later, if considered worth it.\n\n>   sequencer: avoid completely different messages for different actions\nFix l10n or drop (and not introduce lego translation).\n\n>   sequencer: get rid of the subcommand field\n>   sequencer: refactor the code to obtain a short commit name\nExplain reason behind this change in the commit mesage.\n\n>   sequencer: remember the onelines when parsing the todo file\nLazy or eager again; \"exec\", \"noop\" and --preserve-merges.\n\n>   sequencer: prepare for rebase -i's commit functionality\nAdd helper function, possibly extract helper function.  Rephrase block\ncomment.\n\n\"[PATCH] am: refactor read_author_script()\" from Junio.\n\n>   sequencer: introduce a helper to read files written by scripts\nPerhaps add why not use open + strbuf_getline to commit message...\n\n>   sequencer: prepare for rebase -i's GPG settings\nPossibly fixes bug.  Use *_entrust() or strdup to not leak memory\n(and to not crash when freeing memory).\n\n>   sequencer: allow editing the commit message on a case-by-case basis\nEnhance the commit message.\n\n>   sequencer: support amending commits\n>   sequencer: support cleaning up commit messages\n>   sequencer: remember do_recursive_merge()'s return value\n>   sequencer: left-trim the lines read from the script\n>   sequencer: refactor write_message()\nEnhance the commit message.  Quote path in messages while at it.\n\n\nHTH\n\n> \n>  builtin/commit.c                |   2 +-\n>  builtin/revert.c                |  42 ++-\n>  sequencer.c                     | 573 +++++++++++++++++++++++++++-------------\n>  sequencer.h                     |  27 +-\n>  t/t3510-cherry-pick-sequence.sh |  11 -\n>  5 files changed, 428 insertions(+), 227 deletions(-)\n> \n> Based-On: libify-sequencer at https://github.com/dscho/git\n> Fetch-Base-Via: git fetch https://github.com/dscho/git libify-sequencer\n> Published-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v1\n> Fetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v1\n\nAn unrelated question: Dscho, how are you generating above lines?\n\n-- \nJakub Narębski\n \n\n"},{"id":"300884","messageId":"alpine.DEB.2.20.1609021432070.129229@virtualbox","threadId":"43954","inReplyTo":"ced4a190-6a79-e608-ca0b-3815267c5f93@gmail.com","subject":"Re: [PATCH 00/22] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-02T13:56:27Z","receivedAt":"2016-09-02T13:56:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 2 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 29.08.2016 o 10:03, Johannes Schindelin pisze:\n> \n> > This patch series marks the  '4' in the countdown to speed up rebase -i\n> > by implementing large parts in C. It is based on the `libify-sequencer`\n> > patch series that I submitted last week.\n> \n> Which of those got reviewed (and perhaps accepted), and which of those\n> needs review still?  What is subject of their cover letter?\n\nMost of the patch series I sent before last week got accepted. Only one\ngot rejected, IIRC, and replaced by a better solution (3727318 (Merge\nbranch 'jk/test-send-sh-x-trace-elsewhere', 2016-05-17)).\n\nThe patch series I submitted as part of my rebase--helper work that were\naccepted:\n\nb232439 (Merge branch 'js/t3404-typofix', 2016-05-17)\n7b02771 (Merge branch 'js/perf-rebase-i', 2016-05-23)\n3437017 (Merge branch 'js/perf-on-apple', 2016-07-06)\n62e5e83 (Merge branch 'js/find-commit-subject-ignore-leading-blanks', 2016-07-11)\nc510926 (Merge branch 'js/sign-empty-commit-fix', 2016-07-13)\n6c35952 (Merge branch 'js/t3404-grammo-fix', 2016-07-13)\n63641fb (Merge branch 'js/log-to-diffopt-file', 2016-07-19)\n3d55eea (Merge branch 'js/am-call-theirs-theirs-in-fallback-3way', 2016-07-19)\nc97268c (Merge branch 'js/rebase-i-tests', 2016-07-28)\n1a5f1a3 (Merge branch 'js/am-3-merge-recursive-direct', 2016-08-10)\n\nYou will note that I broke out a couple of patch series that do not\nstrictly have anything to do with the rebase--helper, such as\nperf-on-apple. Nevertheless, they were part of a 99-strong patch series\nthat was my initial working rebase--helper, which I have used ever since\nto perform all of my interactive rebases.\n\nThere are still a couple of patch series in flight. Let me list them by\nthe tags created by my mail-patch-series.sh script:\n\nhttps://github.com/dscho/git/releases/tag/libify-sequencer-v2\nhttps://github.com/dscho/git/releases/tag/require-clean-work-tree-v1\nhttps://github.com/dscho/git/releases/tag/prepare-sequencer-v1\nhttps://github.com/dscho/git/releases/tag/sequencer-i-v1\nhttps://github.com/dscho/git/releases/tag/rebase--helper-v1\n\nThese tags all contain links to the cover letter as stored on\npublic-inbox.org, identified by the Message-ID.\n\nPlease note that the first four of this batch of five already saw\nsubstantial work-after-review, thanks in part to your helpful comments.\nYou may appreciate the fact that a link of the form\n\nhttps://github.com/dscho/git/compare/libify-sequencer-v2...libify-sequencer\n\nshows you where I am at, although it cannot give you a real interdiff\nbecause I rebased to a newer version of upstream/master in the meantime.\n\nFinally, there is one last patch series that I did not yet submit: the\n'rebase-i-extra' patch series. However, as I continuously update the\noverall 'interactive-rebase' branch thicket (and have done so since the\nvery beginning of my work on the rebase--helper), it is relatively easy to\nsee what is left:\n\nhttps://github.com/dscho/git/compare/rebase--helper...interactive-rebase\n\nBTW thanks for making me dig out all of this information (it did take a\nwhile to uncover it...), as I am so totally going to use that in a blog\npost.\n\n> > The reason to split these two patch series is simple: to keep them at a\n> > sensible size.\n> \n> That's good.\n\nThanks. I really try to be sensible with other people's time.\n\nEven more so after being so offended by the talk at the most recent Git\nMerge that stated that some people deliberately waste contributors' time\nbecause they value their own time so much more. I am *really* offended by\nthat.\n\nAs a maintainer of Git for Windows, I do everything in my power to strike\na sensible balance between how much time I spend on improving the software\nand how much time I ask others to do so.\n\n> > The two patch series after that are much smaller: a two-patch \"series\"\n> > that switches rebase -i to use the sequencer (except with --root or\n> > --preserve-merges), and a couple of patches to move several pretty\n> > expensive script processing steps to C (think: autosquash).\n> \n> I can understand --preserve-merges, but what is the problem with --root?\n\nThe problem with --root is that it *creates* an initial commit. It is\nempty, and will be amended. It would most likely not be a lot of work, but\nI really wanted this work to be incremental, focusing on the most\nimportant aspects first.\n\nIn fact, I do hope that somebody with the need for --root will take the\nbaton and run with it.\n\n> > The end game of this patch series is a git-rebase--helper that makes\n> > rebase -i 5x faster on Windows (according to t/perf/p3404). Travis\n> > says that even MacOSX and Linux benefit (4x and 3x, respectively).\n> \n> So do I understand correctly that end goal for *this* series is to move\n> most of processing to git-rebase--helper, but full builtin-ification\n> (and retiring git-rebase.sh to contrib/examples/) would have to wait for\n> later?\n\nOh yes!\n\nRetiring git-rebase.sh is *far, far, far* in the future. We really missed\nthe boat a *looooong* time ago to turn this from a hacky shell script into\na proper C builtin.\n\nThere is so much more to do before git-rebase.sh can be retired.\n\nFor starters, git-rebase.sh is actually just a glorified command-line\noption parser and front-end to git-rebase--am.sh,\ngit-rebase--interactive.sh and git-rebase--merge.sh.\n\nTo retire it, those three shell scripts need to be *completely* built-in\nfirst.\n\n(Actually, for the --preserve-merges case, I could imagine that we simply\nrefactor it into its own shell script and call that from a builtin\ngit-rebase, until we retire --preserve-merges, but that's a couple of\nyears down the road.)\n\nSo the first goal would be to retire git-rebase--interactive.sh. For that\nto happen, --root needs to be supported first. Then the --preserve-merges\nstuff needs to be refactored into its own shell script. And then the\ncommand-line option parsing needs to be moved to rebase--helper, too. And\n*then* git-rebase--interactive.sh can be retired.\n\nAs I stated earlier, my hope is that the rebase--helper work is only an\ninitial step, opening the door for other contributors to tackle\nindependent parts of making git-rebase a builtin.\n\n> [...]\n> \n> I'd like here to summarize the discussion (my review, Dennis review,\n> Johannes Sixt and Junio comments).\n> \n> If there are no comments, it means no problems or minor changes.\n\nPlease keep in mind that my current state (local, and pushed to my GitHub\nrepository) has advanced substantially. I am reluctant to send it out yet\nbecause I still need to send out rebase-i-extra first, so that it gets\n*some* visibility before v2.10.0.\n\n> > Johannes Schindelin (22):\n> >   sequencer: use static initializers for replay_opts\n> There is no need for putting zeros in static initializer.  Commit\n> message expanded.\n> \n> >   sequencer: use memoized sequencer directory path\n> >   sequencer: avoid unnecessary indirection\n> >   sequencer: future-proof remove_sequencer_state()\n> Leftover unrelated chunk removed.\n> \n> >   sequencer: allow the sequencer to take custody of malloc()ed data\n> Is introducing new *_entrust() mechanism (which needs docs, at least\n> as comments) worth it, instead of just strdup everything and free?\n> If it is: naming of function parameter + example in commit message.\n> \n> >   sequencer: release memory that was allocated when reading options\n> See above.\n> \n> >   sequencer: future-proof read_populate_todo()\n> Possibly mention which functions were not future-proofed because\n> of planned for the subsequent patch full rewrite.\n\nNote that this commit is about read_populate_todo(), not about\nsave_todo(). So I do not think that we should mention anything in this\ncommit's message about other functions that may be rewritten instead of\nbeing future-proofed..\n\n> >   sequencer: remove overzealous assumption\n> Overzealous assumptions, or a worthy check?  Perhaps just remove check\n> for rebase -i in future commit, and keep test.  Perhaps remove test\n> temporarily.\n\nAs mentioned earlier, I bit the bullet and reimplemented that logic.\nMostly to fend off more comments in this direction.\n\n> >   sequencer: completely revamp the \"todo\" script parsing\n> This removes check; it should return if it was worthy.  Some discussion\n> about eager versus lazy parsing of commits, but IMHO it should be left\n> for later, if considered worth it.\n\nAgain, it was reintroduced. The test to check for the overzealous\nassumption was not removed, and it passes, to prove that I did it right.\n\n> >   sequencer: avoid completely different messages for different actions\n> Fix l10n or drop (and not introduce lego translation).\n> \n> >   sequencer: get rid of the subcommand field\n> >   sequencer: refactor the code to obtain a short commit name\n> Explain reason behind this change in the commit mesage.\n> \n> >   sequencer: remember the onelines when parsing the todo file\n> Lazy or eager again; \"exec\", \"noop\" and --preserve-merges.\n> \n> >   sequencer: prepare for rebase -i's commit functionality\n> Add helper function, possibly extract helper function.  Rephrase block\n> comment.\n> \n> \"[PATCH] am: refactor read_author_script()\" from Junio.\n> \n> >   sequencer: introduce a helper to read files written by scripts\n> Perhaps add why not use open + strbuf_getline to commit message...\n> \n> >   sequencer: prepare for rebase -i's GPG settings\n> Possibly fixes bug.  Use *_entrust() or strdup to not leak memory\n> (and to not crash when freeing memory).\n> \n> >   sequencer: allow editing the commit message on a case-by-case basis\n> Enhance the commit message.\n> \n> >   sequencer: support amending commits\n> >   sequencer: support cleaning up commit messages\n> >   sequencer: remember do_recursive_merge()'s return value\n> >   sequencer: left-trim the lines read from the script\n> >   sequencer: refactor write_message()\n> Enhance the commit message.  Quote path in messages while at it.\n\nApart from the l10n issues, I think I addressed them all locally, and\npushed the result out to my GitHub repository, although I plan to send out\nadditional iterations only after releasing Git for Windows v2.10.0.\n\n> > Based-On: libify-sequencer at https://github.com/dscho/git\n> > Fetch-Base-Via: git fetch https://github.com/dscho/git libify-sequencer\n> > Published-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v1\n> > Fetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v1\n> \n> An unrelated question: Dscho, how are you generating above lines?\n\nIt's the `mail-patch-series.sh` script, in conjunction with setting the\nconfig variable mail.publishremoteto to point to my GitHub remote. You can\nfind the `mail-patch-series.sh` script here:\n\n\thttps://github.com/dscho/mail-patch-series\n\nI probably forgot to adjust the README to reflect the most recent changes\n(such as the `--basedon` feature)... PRs welcome [*1*].\n\nCiao,\nDscho\n\nFootnote *1*:\nhttps://raw.githubusercontent.com/dscho/images/master/i-can-haz-pull-request.png"},{"id":"301491","messageId":"alpine.DEB.2.20.1609091608090.129229@virtualbox","threadId":"43954","inReplyTo":"d8112b27-8de3-0860-e902-fb271b80a0e7@gmail.com","subject":"Re: [PATCH 09/22] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T14:12:10Z","receivedAt":"2016-09-09T14:12:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 2 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 01.09.2016 o 09:49, Johannes Schindelin pisze:\n> > On Wed, 31 Aug 2016, Jakub Narębski wrote: \n> \n> >> Here todo_list uses growable array implementation of list.  Which is\n> >> I guess better on current CPU architecture, with slow memory,\n> >> limited-size caches, and adjacency prefetching.\n> > \n> > That is not the reason that an array is used here. The array allows us\n> > much more flexibility.\n> \n> It would be nice if this reasoning (behind the change from linked list\n> to growable array) was mentioned in appropriate commit message, and\n> perhaps also in the cover letter for the series.  It is IMVHO quite\n> important information (that you thought obvious).\n\nAmended.\n\n> >>> +struct todo_item *append_todo(struct todo_list *todo_list)\n> >>\n> >> Errr... I don't quite understand the name of this function.\n> >> What are you appending here to the todo_list?\n> > \n> > A new item.\n> > \n> >> Compare string_list_append() and string_list_append_nodup(),\n> >> where the second parameter is item to append.\n> > \n> > Yes, that is correct. In the case of a todo_item, things are a lot more\n> > complicated, though. Some of the values have to be determined tediously\n> > (such as the offset and length of the oneline after the \"pick <oid>\"\n> > command). I just put those values directly into the newly allocated item,\n> > is all.\n> \n> I would expect sth_append command to take a list (or other collection),\n> an element, and return [modified] collection with the new element added.\n> Such API would require temporary variable in caller and memcopy in the\n> sth_append() function.\n> \n> This is not it.  It creates a new element, expanding a list (a collection),\n> and then expose this element.  Which spares us memcopy... on non-critical\n> path.\n> \n> I don't know how to name operation \"grow list and return new element\".\n> But \"append\" it is not.\n\nI renamed it to append_new_todo().\n\n> >>> -\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n> >>> +\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n> >>\n> >> Why is this cast needed?\n> > \n> > Because bol is a \"const char *\" and we need to put \"NUL\" temporarily to\n> > *end_of_object_name:\n> \n> Would compiler complain without this const'ness-stripping cast?\n\nYes. I would not have added it otherwise.\n\nPlease note that this is only necessary because I changed the parameter\nfrom \"char *\" to \"const char *\" (which was The Right Thing To Do).\n\n> >>>  \tsaved = *end_of_object_name;\n> >>>  \t*end_of_object_name = '\\0';\n> >>>  \tstatus = get_sha1(bol, commit_sha1);\n> >>>  \t*end_of_object_name = saved;\n> > \n> > Technically, this would have made a fine excuse to teach get_sha1() a\n> > mode where it expects a length parameter instead of relying on a\n> > NUL-terminated string.\n> > \n> > Practically, such fine excuses cost me months in this rebase--helper\n> > project already, and I need to protect my time better.\n> \n> Put it in TODO list (and perhaps add a TODO comment) ;-).\n\nI am also a realist: I won't be able to do anything about this. If you\ncare enough, please go right to town.\n\nThanks again,\nDscho"},{"id":"301492","messageId":"alpine.DEB.2.20.1609091613000.129229@virtualbox","threadId":"43954","inReplyTo":"198780d4-dbef-c0cc-fb4c-fc8986a33002@gmail.com","subject":"Re: [PATCH 10/22] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T14:23:16Z","receivedAt":"2016-09-09T14:23:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 2 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 01.09.2016 o 09:52, Johannes Schindelin pisze:\n> > On Wed, 31 Aug 2016, Jakub Narębski wrote:\n> >> CC-ed to Jiang Xin, L10N coordinator.\n> >> W dniu 29.08.2016 o 10:05, Johannes Schindelin pisze:\n> \n> [...]\n> >>> -\t/* Different translation strings for cherry-pick and revert */\n> >>> -\tif (opts->action == REPLAY_PICK)\n> >>> -\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n> >>> -\telse\n> >>> -\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n> >>> +\terror(_(\"Your local changes would be overwritten by %s.\"),\n> >>> +\t\taction_name(opts));\n> >>\n> >> If I understand it correctly, it would make \"revert\" or \"cherry-pick\"\n> >> untranslated part of error message.  You would need to use translation\n> >> on the result with \"_(action_name(opts))\", you would have to mark\n> >> todo_command_strings elements for gettext lexicon with N_(...).\n\nOkay, that is easy enough.\n\nCiao,\nDscho"},{"id":"301493","messageId":"alpine.DEB.2.20.1609091626120.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqvayftefc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T14:27:09Z","receivedAt":"2016-09-09T14:27:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 1 Sep 2016, Junio C Hamano wrote:\n\n> Jakub Narębski <jnareb@gmail.com> writes:\n> \n> > I wonder how probable is situation where we save instruction sheet\n> > for interactive rebase, with shortened SHA-1, and during rebase\n> > shortened SHA-1 stops being unambiguous...\n> \n> It is my understanding that the shortened ones are only for end-user\n> consumption.  The insn sheet internally uses fully expanded form for\n> this exact reason, and then abbreviated back at each step before the\n> updated one is presented to the end-user.  Uniqueness guarantee is\n> enforced with new objects created during each step taken into\n> account by doing it this way.\n\nIndeed, the rebase -i shortens the SHA-1s just before letting the user\nedit git-rebase-todo and then expands them back.\n\nCiao,\nDscho"},{"id":"301494","messageId":"alpine.DEB.2.20.1609091631070.129229@virtualbox","threadId":"43954","inReplyTo":"54cc3d11-6384-b666-3103-4e56a399ba6d@gmail.com","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T14:31:28Z","receivedAt":"2016-09-09T14:31:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 2 Sep 2016, Jakub Narębski wrote:\n\n> Hello Johannes,\n> \n> W dniu 01.09.2016 o 16:13, Johannes Schindelin pisze: \n> > On Thu, 1 Sep 2016, Jakub Narębski wrote:\n>  \n> >> 'bol' is beginning-of-line, isn't it (a complement to eol)?\n> > \n> > Yep. How did you guess? :-)\n> \n> Wouldn't 'beg' and 'end' instead of 'bol' and 'eol' be easier\n> to understand, thus more readable?\n\nIt is just consistency with the code I inherited: sequencer.c used 'bol'\nand 'eol' before.\n\nCiao,\nDscho"},{"id":"301513","messageId":"alpine.DEB.2.20.1609091639430.129229@virtualbox","threadId":"43954","inReplyTo":"dbc1b08c-a151-29ab-a5a2-45343ca556d6@gmail.com","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T14:40:31Z","receivedAt":"2016-09-09T14:40:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 2 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 01.09.2016 o 16:20, Johannes Schindelin pisze:\n> > On Thu, 1 Sep 2016, Jakub Narębski wrote: \n> >> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> \n> >>>  \tif (commit_lock_file(&msg_file) < 0)\n> >>>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n> >>\n> >> Another \"while at it\"... though the one that can be safely postponed\n> >> (well, the make message easier to understand part, not the quote\n> >> filename part):\n> >>\n> >>   \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n> > \n> > As I inherited this message, I'll keep it.\n> \n> Well, please then add quotes while at it, at least, for consistency\n> \n>   \t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n\nI may do that as a final patch, once all the other concerns are addressed.\nI really do not want to change the error message during the conversion.\n\nCiao,\nDscho"},{"id":"301514","messageId":"alpine.DEB.2.20.1609091707470.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqvayfwlgu.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 21/22] sequencer: left-trim the lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T15:08:04Z","receivedAt":"2016-09-09T15:08:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 1 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> > Interactive rebase's scripts may be indented; We need to handle this\n> >> > case, too, now that we prepare the sequencer to process interactive\n> >> > rebases.\n> >> \n> >> s/; We need/; we need/\n> >\n> > Hrmpf. From http://grammar.ccc.commnet.edu/grammar/marks/colon.htm:\n> >\n> > \tThere is some disagreement among writing reference manuals about\n> > \twhen you should capitalize an independent clause following a\n> > \tcolon. Most of the manuals advise that when you have more than one\n> > \tsentence in your explanation or when your sentence(s) is a formal\n> > \tquotation, a capital is a good idea. The NYPL Writer's Guide urges\n> > \tconsistency within a document; the Chicago Manual of Style says\n> > \tyou may begin an independent clause with a lowercase letter unless it's\n> > \tone of those two things (a quotation or more than one sentence).\n> > \tThe APA Publication Manual is the most extreme: it advises us to\n> > \talways capitalize an independent clause following a colon. The advice\n> > \tgiven above is consistent with the Gregg Reference Manual.\n> >\n> > Based on that, I think that a capital is the correct case here.\n> \n> Does that manual have anything to say about semicolons, which is a\n> different thing?\n\nYou're correct, I overlooked that.\n\nFixed,\nDscho\n"},{"id":"301516","messageId":"alpine.DEB.2.20.1609091708480.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqeg53wj7a.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-09T15:12:15Z","receivedAt":"2016-09-09T15:12:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 1 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> though).  The \"one sequencer to rule them all\" may even have to say\n> >> \"now give name ':1' to the result of the previous operation\" in one\n> >> step and in another later step have an instruction \"merge ':1'\".\n> >> When that happens, you cannot even pre-populate the commit object\n> >> when the sequencer reads the file, as the commit has not yet been\n> >> created at that point.\n> >\n> > These considerations are pretty hypothetical. I would even place a bet\n> > that we will *never* have \":1\" as names, not if I have anything to say...\n> > ;-)\n> \n> If you can always work with pre-existing commit, then you can\n> validate all object references that appear in the instructions\n> upfront.\n\nOr if *some* of the commands work with pre-existing commits, *those*\ncommands can be validated up-front.\n\nWhich is exactly what my code does.\n\n> I was sort of expecting that, when you do the preserve-merges mode\n> of \"rebase -i\", you would need to jump around, doing \"we have\n> reconstructed the side branch on a new 'onto', let's give the result\n> this temporary name ':1', and then switch to the trunk (which would\n> call for 'reset <commit>' instruction) and merge that thing (which\n> would be 'merge :1' or perhaps called 'pick :1')\", and at that point\n> you no longer validate the object references upfront.\n\nExcept that is not how --preserve-merges works: it *still* uses the SHA-1s\nas identifiers, even when the SHA-1 may have changed in the meantime.\n\nThat is part of why it was a bad design.\n\n> If you do not have to have such a \"mark this point\" and a \"refer to\n> that point we previously marked\", then I agree that you should be\n> able to pre-validate and keep the result in the structure.\n\nEven then, those markers should *still* be validated. They, too, need to\nbe created and later used, usage before creation would be an error.\n\nBut...\n\n1) this is not yet a problem, so why are we discussing it here? Do we not\n   have actual problems with these patches to discuss anymore?\n\n2) the SHA-1s that *can* be validated *should* be validated, so I find the\n   objection a little bogus.\n\nCiao,\nDscho\n"},{"id":"301542","messageId":"5b707a0d-6c10-abb5-3213-d13490e9b9de@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609091708480.129229@virtualbox","subject":"Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-09T19:06:45Z","receivedAt":"2016-09-09T19:07:07Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 09.09.2016 o 17:12, Johannes Schindelin napisał:\n> On Thu, 1 Sep 2016, Junio C Hamano wrote: \n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I was sort of expecting that, when you do the preserve-merges mode\n>> of \"rebase -i\", you would need to jump around, doing \"we have\n>> reconstructed the side branch on a new 'onto', let's give the result\n>> this temporary name ':1', and then switch to the trunk (which would\n>> call for 'reset <commit>' instruction) and merge that thing (which\n>> would be 'merge :1' or perhaps called 'pick :1')\", and at that point\n>> you no longer validate the object references upfront.\n> \n> Except that is not how --preserve-merges works: it *still* uses the SHA-1s\n> as identifiers, even when the SHA-1 may have changed in the meantime.\n> \n> That is part of why it was a bad design.\n\nWhen preserving merges, there are (as far as I understand it), two\nproblems:\n - what it means to preserve changes (which change to pick,\n   that is what is the mainline changes rebase is re-applying)\n - what are parents of the merge commit (at least one parent\n   would be usually rewritten)\n\nMaybe the internal (and perhaps also user-visible) representation\nof merge in instruction sheet could use the notation of filter-branch,\nthat is 'map(<sha-1>)'... it could also imply the mainline.\n\nThat is the instruction in the internal instruction sheet could\nlook like this:\n\n  merge -m 1 map(2fd4e1c67a2d28fced849ee1bb76e7391b93eb12) da39a3ee5e6b4b0d3255bfef95601890afd80709 \\t Merge 'foo' into master  \n\n\nNote that it has nothing to do with this series!\n\nBest regards,\n-- \nJakub Narębski\n\n"},{"id":"301543","messageId":"2e15ae99-59cf-7fac-517b-30b59d6d574d@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609091639430.129229@virtualbox","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-09T19:11:43Z","receivedAt":"2016-09-09T19:12:05Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Johannes,\n\nW dniu 09.09.2016 o 16:40, Johannes Schindelin napisał:\n> On Fri, 2 Sep 2016, Jakub Narębski wrote:\n>> W dniu 01.09.2016 o 16:20, Johannes Schindelin pisze:\n>>> On Thu, 1 Sep 2016, Jakub Narębski wrote: \n>>>> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n>>\n>>>>>  \tif (commit_lock_file(&msg_file) < 0)\n>>>>>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>>>>\n>>>> Another \"while at it\"... though the one that can be safely postponed\n>>>> (well, the make message easier to understand part, not the quote\n>>>> filename part):\n>>>>\n>>>>   \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n>>>\n>>> As I inherited this message, I'll keep it.\n>>\n>> Well, please then add quotes while at it, at least, for consistency\n>>\n>>   \t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n> \n> I may do that as a final patch, once all the other concerns are addressed.\n> I really do not want to change the error message during the conversion.\n\nIs not wanting to change error messages during conversion because of\nyour use of Scientist tool to catch errors in conversion process?, as\nyou wrote in\n  https://blogs.msdn.microsoft.com/visualstudioalm/2016/09/03/whats-new-in-git-for-windows-2-10/\n\nBTW. could you tell us what were those three regression caught by the\ncross-validation?\n\nBest,\n-- \nJakub Narębski\n"},{"id":"301623","messageId":"alpine.DEB.2.20.1609111010440.129229@virtualbox","threadId":"43954","inReplyTo":"2e15ae99-59cf-7fac-517b-30b59d6d574d@gmail.com","subject":"Re: [PATCH 22/22] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T08:26:05Z","receivedAt":"2016-09-11T08:26:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 9 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 09.09.2016 o 16:40, Johannes Schindelin napisał:\n> > On Fri, 2 Sep 2016, Jakub Narębski wrote:\n> >> W dniu 01.09.2016 o 16:20, Johannes Schindelin pisze:\n> >>> On Thu, 1 Sep 2016, Jakub Narębski wrote: \n> >>>> W dniu 29.08.2016 o 10:06, Johannes Schindelin pisze:\n> >>\n> >>>>>  \tif (commit_lock_file(&msg_file) < 0)\n> >>>>>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n> >>>>\n> >>>> Another \"while at it\"... though the one that can be safely postponed\n> >>>> (well, the make message easier to understand part, not the quote\n> >>>> filename part):\n> >>>>\n> >>>>   \t\treturn error(_(\"Error wrapping up writing to '%s'.\"), filename);\n> >>>\n> >>> As I inherited this message, I'll keep it.\n> >>\n> >> Well, please then add quotes while at it, at least, for consistency\n> >>\n> >>   \t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n> > \n> > I may do that as a final patch, once all the other concerns are addressed.\n> > I really do not want to change the error message during the conversion.\n> \n> Is not wanting to change error messages during conversion because of\n> your use of Scientist tool to catch errors in conversion process?\n\nIt is more out of an aversion to mix unrelated purposes in the same patch.\nYou will see that I inserted an extra patch with the purpose of fixing the\nstyle, that touches all the relevant error messages in sequencer.c.\n\n> BTW. could you tell us what were those three regression caught by the\n> cross-validation?\n\nSure!\n\nThe first one was that my original version of the rebase-i-extra patches\ndid not reorder patches correctly when there was more than one space after\nthe fixup!. I fixed it, and added this test:\n\ncbcd2cb (rebase -i: we allow extra spaces after fixup!/squash!, 2016-07-07)\n\nThe second one was that `git commit --fixup` unwraps the commit subject\ninto one long line and rebase -i *still* manages to find the correct\ncommit to fix up. The test is part of the rebase-i-extra patches (and\ntherefore you will find this commit only in my fork):\n\n9fc25ce (t3415: test fixup with wrapped oneline, 2016-07-24)\n\nThe third one was an obscure one: when I marked a commit as 'edit' and\nthere was a merge conflict cherry-picking that particular commit, rebase\n--continue would squash the resolved changes *into the previous* commit,\nbut with the cherry-picked commit's message. It was a simple, stupid\noversight to write the \"amend\" file in the \"edit\" code path even if the\ncherry-pick failed.\n\nAll fixed, of course.\n\nCiao,\nDscho"},{"id":"301624","messageId":"alpine.DEB.2.20.1609111027330.129229@virtualbox","threadId":"43954","inReplyTo":"5b707a0d-6c10-abb5-3213-d13490e9b9de@gmail.com","subject":"Git garden shears, was Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T08:33:36Z","receivedAt":"2016-09-11T08:33:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Fri, 9 Sep 2016, Jakub Narębski wrote:\n\n> Hello Johannes,\n> \n> W dniu 09.09.2016 o 17:12, Johannes Schindelin napisał:\n> > On Thu, 1 Sep 2016, Junio C Hamano wrote: \n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> I was sort of expecting that, when you do the preserve-merges mode\n> >> of \"rebase -i\", you would need to jump around, doing \"we have\n> >> reconstructed the side branch on a new 'onto', let's give the result\n> >> this temporary name ':1', and then switch to the trunk (which would\n> >> call for 'reset <commit>' instruction) and merge that thing (which\n> >> would be 'merge :1' or perhaps called 'pick :1')\", and at that point\n> >> you no longer validate the object references upfront.\n> > \n> > Except that is not how --preserve-merges works: it *still* uses the SHA-1s\n> > as identifiers, even when the SHA-1 may have changed in the meantime.\n> > \n> > That is part of why it was a bad design.\n> \n> When preserving merges, there are (as far as I understand it), two\n> problems:\n>  - what it means to preserve changes (which change to pick,\n>    that is what is the mainline changes rebase is re-applying)\n>  - what are parents of the merge commit (at least one parent\n>    would be usually rewritten)\n> \n> Maybe the internal (and perhaps also user-visible) representation\n> of merge in instruction sheet could use the notation of filter-branch,\n> that is 'map(<sha-1>)'... it could also imply the mainline.\n> \n> That is the instruction in the internal instruction sheet could\n> look like this:\n> \n>   merge -m 1 map(2fd4e1c67a2d28fced849ee1bb76e7391b93eb12) da39a3ee5e6b4b0d3255bfef95601890afd80709 \\t Merge 'foo' into master  \n> \n> \n> Note that it has nothing to do with this series!\n\nRight. But I did solve that already. In the Git garden shears [*1*]\n(essentially my New And Improved attempt at recreating branch structures\nwhile rebasing), I generate and process scripts like this:\n\n\tmark onto\n\n\t# Branch: super-cool-feature\n\trewind onto\n\tpick 00001 feature\n\tpick 00002 documentation\n\tmark super-cool-feature\n\n\t# Branch: typo-fix\n\trewind onto\n\tpick 0000a fix a tyop\n\n\trewind onto\n\tmerge -C cafebabe super-cool-feature\n\tmerge -C babecafe typo-fix\n\n\tcleanup super-cool-feature typo-fix\n\nOf course this will change a little, still, once I get around to implement\nthis on top of the rebase--helper.\n\nFor example, I am not so hot about the \"merge -C ...\" syntax. I'll\nprobably split that into a \"remerge <SHA-1> <mark>\" and a new \"merge\n<mark>\" command (the latter asking interactively for the merge commit\nmessage).\n\nAnd also: the cleanup stage should not be necessary, as the \"mark\"\ncommands can accumulate the known marks into a file in the state\ndirectory.\n\nBut you get the idea.\n\nNo :1 or some such. That's machine readable. But it's utter nonsense for\nuser-facing UIs.\n\nCiao,\nDscho\n\nFootnote *1*:\nhttps://github.com/git-for-windows/build-extra/blob/master/shears.sh"},{"id":"301631","messageId":"666493d3f166d839deb817042ed7d1636b11f19e.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 01/25] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:52:30Z","receivedAt":"2016-09-11T10:52:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This change is not completely faithful: instead of initializing all fields\nto 0, we choose to initialize command and subcommand to -1 (instead of\ndefaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\nit makes no difference at all, but future-proofs the code to require\nexplicit assignments for both fields.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 6 ++----\n sequencer.h      | 1 +\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4e69380..7365559 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -178,10 +178,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n@@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n \tparse_args(argc, argv, &opts);\ndiff --git a/sequencer.h b/sequencer.h\nindex 5ed5cb1..db425ad 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -47,6 +47,7 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n+#define REPLAY_OPTS_INIT { -1, -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301632","messageId":"cover.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1472457609.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 00/25] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:52:25Z","receivedAt":"2016-09-11T10:52:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series marks the  '4' in the countdown to speed up rebase -i\nby implementing large parts in C. It is based on the `libify-sequencer`\npatch series that I submitted last week.\n\nThe patches in this series merely prepare the sequencer code for the\nnext patch series that actually teaches the sequencer to run an\ninteractive rebase.\n\nThe reason to split these two patch series is simple: to keep them at a\nsensible size.\n\nThe two patch series after that are much smaller: a two-patch \"series\"\nthat switches rebase -i to use the sequencer (except with --root or\n--preserve-merges), and a couple of patches to move several pretty\nexpensive script processing steps to C (think: autosquash).\n\nThe end game of this patch series is a git-rebase--helper that makes\nrebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\nthat even MacOSX and Linux benefit (4x and 3x, respectively).\n\nI have been working on this since early February, whenever time allowed,\nand it is time to put it into the users' hands. To that end, I will most\nlikely submit the remaining three patch series in the next two days, and\nintegrate the whole shebang into Git for Windows 2.10.0.\n\nTherefore I would be most grateful for every in-depth review.\n\nChanges vs v1:\n\n- clarified why the code refactoring into the short_commit_name()\n  function is desirable.\n\n- fixed a typo in a commit message (s/se/so/).\n\n- removed a bogus call to read_and_refresh_cache(opts) that was added\n  to sequencer_rollback() by mistake.\n\n- clarified in the commit message why the TODO_LIST_INIT macro does not\n  assign all-zeroes.\n\n- converted IS_REBASE_I() into an inline function.\n\n- clarified the comment about retaining author metadata when calling\n  sequencer_commit() in rebase -i mode.\n\n- simplified TODO_LIST_INIT and REPLAY_OPTS_INIT.\n\n- added an example how to use sequencer_entrust() to the commit message\n  introducing it.\n\n- the gpg_sign option's value is now also entrusted to the sequencer\n  (i.e. it is released in sequencer_remove_state()).\n\n- renamed the \"set_me_free_after_use\" to \"to_free\". Since that is still\n  not a self-explanatory name, add a comment to the function\n  declaration.\n\n- clarified in the \"completely revamped todo parsing\" commit message\n  that the main benefit of the early parsing is for rebase -i.\n\n- start the `enum todo_command` with TODO_PICK that is explicitly\n  assigned the value 0.\n\n- an error was marked as translatable.\n\n- converted one forgotten git_path_todo_file() to use\n  get_todo_path(opts) instead.\n\n- fixed numbering of \"malformed instruction sheet\"s after removing one.\n\n- reintroduced the overzealous assumption that todo scripts can only\n  perform revert commands during `git revert` and pick commands during\n  `git cherry-pick`. This overzealous assumption is *still* disabled in\n  rebase -i mode, of course.\n\n- clarified in the commit message why we call the field \"arg\", not\n  \"oneline\", and fixed the description that claimed that we store the\n  end offset (we store the length instead).\n\n- clarified in the commit message of \"allow editing the commit message\n  on a case-by-case basis\" that we are talking about the\n  sequencer_commit() function, and how things were done previously.\n\n- some grammar touch-ups.\n\n- marked a couple of error messages for translation.\n\n- explicitly assign the first todo_command the value 0, so that we can\n  be certain that the array of command strings matches up.\n\n- removed code to skip CR/LF at the end of line after reading with\n  read_oneliner(): That function already ensures that.\n\n- ensured that the todo_list is released even when reading/parsing fails.\n\n- replaced an error(..., strerror()) call with an error_errno(...) one.\n\n- clarified in the commit message why the new todo_list maintains the\n  script as an array instead of a linked list.\n\n- renamed the append_todo() function into append_new_todo(), to explain\n  better what the function does and why it does not take the values as\n  parameters that should populate the new todo_item.\n\n- marked action_name() for translation.\n\n- surrounded all file names in error messages in sequencer.c with single\n  quotes, for consistency.\n\n- removed a bogus hint for translators that asked them to translate\n  commands of the git-rebase-todo file (or cherry-pick's equivalent).\n\n- turned capitals after semicolons to lower-case.\n\n\nJohannes Schindelin (25):\n  sequencer: use static initializers for replay_opts\n  sequencer: use memoized sequencer directory path\n  sequencer: avoid unnecessary indirection\n  sequencer: future-proof remove_sequencer_state()\n  sequencer: allow the sequencer to take custody of malloc()ed data\n  sequencer: release memory that was allocated when reading options\n  sequencer: future-proof read_populate_todo()\n  sequencer: completely revamp the \"todo\" script parsing\n  sequencer: avoid completely different messages for different actions\n  sequencer: get rid of the subcommand field\n  sequencer: refactor the code to obtain a short commit name\n  sequencer: remember the onelines when parsing the todo file\n  sequencer: prepare for rebase -i's commit functionality\n  sequencer: introduce a helper to read files written by scripts\n  sequencer: prepare for rebase -i's GPG settings\n  sequencer: allow editing the commit message on a case-by-case basis\n  sequencer: support amending commits\n  sequencer: support cleaning up commit messages\n  sequencer: remember do_recursive_merge()'s return value\n  sequencer: left-trim lines read from the script\n  sequencer: refactor write_message()\n  sequencer: remove overzealous assumption in rebase -i mode\n  sequencer: mark action_name() for translation\n  sequencer: quote filenames in error messages\n  sequencer: remove bogus hint for translators\n\n builtin/commit.c |   2 +-\n builtin/revert.c |  42 ++--\n sequencer.c      | 632 +++++++++++++++++++++++++++++++++++++------------------\n sequencer.h      |  31 +--\n 4 files changed, 468 insertions(+), 239 deletions(-)\n\nBased-On: libify-sequencer at https://github.com/dscho/git\nFetch-Base-Via: git fetch https://github.com/dscho/git libify-sequencer\nPublished-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v2\nFetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v2\n\nInterdiff vs v1:\n\n diff --git a/sequencer.c b/sequencer.c\n index 7d56676..cdff0f1 100644\n --- a/sequencer.c\n +++ b/sequencer.c\n @@ -41,7 +41,10 @@ static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n  \n  /* We will introduce the 'interactive rebase' mode later */\n -#define IS_REBASE_I() 0\n +static inline int is_rebase_i(const struct replay_opts *opts)\n +{\n +\treturn 0;\n +}\n  \n  static const char *get_dir(const struct replay_opts *opts)\n  {\n @@ -145,12 +148,12 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n  \treturn buf.buf;\n  }\n  \n -void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use)\n +void *sequencer_entrust(struct replay_opts *opts, void *to_free)\n  {\n  \tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n -\topts->owned[opts->owned_nr++] = set_me_free_after_use;\n +\topts->owned[opts->owned_nr++] = to_free;\n  \n -\treturn set_me_free_after_use;\n +\treturn to_free;\n  }\n  \n  int sequencer_remove_state(struct replay_opts *opts)\n @@ -173,7 +176,7 @@ int sequencer_remove_state(struct replay_opts *opts)\n  \n  static const char *action_name(const struct replay_opts *opts)\n  {\n -\treturn opts->action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\";\n +\treturn opts->action == REPLAY_REVERT ? N_(\"revert\") : N_(\"cherry-pick\");\n  }\n  \n  struct commit_message {\n @@ -248,11 +251,11 @@ static int write_with_lock_file(const char *filename,\n  \tif (msg_fd < 0)\n  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n  \tif (write_in_full(msg_fd, buf, len) < 0)\n -\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n +\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n  \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n -\t\treturn error_errno(_(\"Could not write eol to %s\"), filename);\n +\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n  \tif (commit_lock_file(&msg_file) < 0)\n -\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n +\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n  \n  \treturn 0;\n  }\n @@ -309,10 +312,10 @@ static struct tree *empty_tree(void)\n  static int error_dirty_index(struct replay_opts *opts)\n  {\n  \tif (read_cache_unmerged())\n -\t\treturn error_resolve_conflict(action_name(opts));\n +\t\treturn error_resolve_conflict(_(action_name(opts)));\n  \n  \terror(_(\"Your local changes would be overwritten by %s.\"),\n -\t\taction_name(opts));\n +\t\t_(action_name(opts)));\n  \n  \tif (advice_commit_before_merge)\n  \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n @@ -330,7 +333,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,\n  \tif (checkout_fast_forward(from, to, 1))\n  \t\treturn -1; /* the callee should have complained already */\n  \n -\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), action_name(opts));\n +\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), _(action_name(opts)));\n  \n  \ttransaction = ref_transaction_begin(&err);\n  \tif (!transaction ||\n @@ -406,7 +409,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  \t    write_locked_index(&the_index, &index_lock, COMMIT_LOCK))\n  \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n  \t\treturn error(_(\"%s: Unable to write new index file\"),\n -\t\t\taction_name(opts));\n +\t\t\t_(action_name(opts)));\n  \trollback_lock_file(&index_lock);\n  \n  \tif (opts->signoff)\n @@ -488,9 +491,13 @@ static char **read_author_script(void)\n   * If we are cherry-pick, and if the merge did not result in\n   * hand-editing, we will hit this commit and inherit the original\n   * author date and name.\n + *\n   * If we are revert, or if our cherry-pick results in a hand merge,\n - * we had better say that the current user is responsible for that\n - * (except, of course, while running an interactive rebase).\n + * we had better say that the current user is responsible for that.\n + *\n + * An exception is when sequencer_commit() is called during an\n + * interactive rebase: in that case, we will want to retain the\n + * author metadata.\n   */\n  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n  \t\t\t  int allow_empty, int edit, int amend,\n @@ -501,7 +508,7 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n  \tint rc;\n  \tconst char *value;\n  \n -\tif (IS_REBASE_I()) {\n +\tif (is_rebase_i(opts)) {\n  \t\tenv = read_author_script();\n  \t\tif (!env) {\n  \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n @@ -513,7 +520,7 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n  \t\t\t\t\"If they are meant to go into a new commit, \"\n  \t\t\t\t\"run:\\n\\n\"\n  \t\t\t\t\"  git commit %s\\n\\n\"\n -\t\t\t\t\"In both case, once you're done, continue \"\n +\t\t\t\t\"In both cases, once you're done, continue \"\n  \t\t\t\t\"with:\\n\\n\"\n  \t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n  \t\t}\n @@ -613,7 +620,7 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n  }\n  \n  enum todo_command {\n -\tTODO_PICK,\n +\tTODO_PICK = 0,\n  \tTODO_REVERT\n  };\n  \n @@ -690,8 +697,6 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n  \n  \tif (parent && parse_commit(parent) < 0)\n -\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n -\t\t   \"cherry-pick\", the second %s a SHA1 */\n  \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n  \t\t\tcommand_to_string(command),\n  \t\t\toid_to_hex(&parent->object.oid));\n @@ -833,14 +838,14 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n  \tif (read_index_preload(&the_index, NULL) < 0) {\n  \t\trollback_lock_file(&index_lock);\n  \t\treturn error(_(\"git %s: failed to read the index\"),\n -\t\t\taction_name(opts));\n +\t\t\t_(action_name(opts)));\n  \t}\n  \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n  \tif (the_index.cache_changed && index_fd >= 0) {\n  \t\tif (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {\n  \t\t\trollback_lock_file(&index_lock);\n  \t\t\treturn error(_(\"git %s: failed to refresh the index\"),\n -\t\t\t\taction_name(opts));\n +\t\t\t\t_(action_name(opts)));\n  \t\t}\n  \t}\n  \trollback_lock_file(&index_lock);\n @@ -861,7 +866,7 @@ struct todo_list {\n  \tint nr, alloc, current;\n  };\n  \n -#define TODO_LIST_INIT { STRBUF_INIT, NULL, 0, 0, 0 }\n +#define TODO_LIST_INIT { STRBUF_INIT }\n  \n  static void todo_list_release(struct todo_list *todo_list)\n  {\n @@ -871,7 +876,7 @@ static void todo_list_release(struct todo_list *todo_list)\n  \ttodo_list->nr = todo_list->alloc = 0;\n  }\n  \n -struct todo_item *append_todo(struct todo_list *todo_list)\n +struct todo_item *append_new_todo(struct todo_list *todo_list)\n  {\n  \tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n  \treturn todo_list->items + todo_list->nr++;\n @@ -925,11 +930,11 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n  \tfor (i = 1; *p; i++) {\n  \t\tchar *eol = strchrnul(p, '\\n');\n  \n -\t\titem = append_todo(todo_list);\n +\t\titem = append_new_todo(todo_list);\n  \t\titem->offset_in_buf = p - todo_list->buf.buf;\n  \t\tif (parse_insn_line(item, p, eol)) {\n -\t\t\terror(\"Invalid line: %.*s\", (int)(eol - p), p);\n -\t\t\tres |= error(_(\"Could not parse line %d.\"), i);\n +\t\t\tres |= error(_(\"Invalid line %d: %.*s\"),\n +\t\t\t\ti, (int)(eol - p), p);\n  \t\t\titem->command = -1;\n  \t\t}\n  \t\tp = *eol ? eol + 1 : eol;\n @@ -948,16 +953,31 @@ static int read_populate_todo(struct todo_list *todo_list,\n  \tstrbuf_reset(&todo_list->buf);\n  \tfd = open(todo_file, O_RDONLY);\n  \tif (fd < 0)\n -\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n +\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n  \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n  \t\tclose(fd);\n -\t\treturn error(_(\"Could not read %s.\"), todo_file);\n +\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n  \t}\n  \tclose(fd);\n  \n  \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n  \tif (res)\n -\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n +\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n +\n +\tif (!is_rebase_i(opts)) {\n +\t\tenum todo_command valid =\n +\t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n +\t\tint i;\n +\n +\t\tfor (i = 0; i < todo_list->nr; i++)\n +\t\t\tif (valid == todo_list->items[i].command)\n +\t\t\t\tcontinue;\n +\t\t\telse if (valid == TODO_PICK)\n +\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n +\t\t\telse\n +\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n +\t}\n +\n  \treturn 0;\n  }\n  \n @@ -1003,22 +1023,16 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n  \n  static int read_populate_opts(struct replay_opts *opts)\n  {\n -\tif (IS_REBASE_I()) {\n +\tif (is_rebase_i(opts)) {\n  \t\tstruct strbuf buf = STRBUF_INIT;\n  \n  \t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n -\t\t\tif (buf.len && buf.buf[buf.len - 1] == '\\n') {\n -\t\t\t\tif (--buf.len &&\n -\t\t\t\t    buf.buf[buf.len - 1] == '\\r')\n -\t\t\t\t\tbuf.len--;\n -\t\t\t\tbuf.buf[buf.len] = '\\0';\n -\t\t\t}\n -\n  \t\t\tif (!starts_with(buf.buf, \"-S\"))\n  \t\t\t\tstrbuf_reset(&buf);\n  \t\t\telse {\n  \t\t\t\topts->gpg_sign = buf.buf + 2;\n -\t\t\t\tstrbuf_detach(&buf, NULL);\n +\t\t\t\tsequencer_entrust(opts,\n +\t\t\t\t\tstrbuf_detach(&buf, NULL));\n  \t\t\t}\n  \t\t}\n  \n @@ -1034,7 +1048,7 @@ static int read_populate_opts(struct replay_opts *opts)\n  \t * are pretty certain that it is syntactically correct.\n  \t */\n  \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n -\t\treturn error(_(\"Malformed options sheet: %s\"),\n +\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n  \t\t\tgit_path_opts_file());\n  \treturn 0;\n  }\n @@ -1044,13 +1058,14 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n  {\n  \tenum todo_command command = opts->action == REPLAY_PICK ?\n  \t\tTODO_PICK : TODO_REVERT;\n +\tconst char *command_string = todo_command_strings[command];\n  \tstruct commit *commit;\n  \n  \tif (prepare_revs(opts))\n  \t\treturn -1;\n  \n  \twhile ((commit = get_revision(opts->revs))) {\n -\t\tstruct todo_item *item = append_todo(todo_list);\n +\t\tstruct todo_item *item = append_new_todo(todo_list);\n  \t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n  \t\tconst char *subject;\n  \t\tint subject_len;\n @@ -1061,8 +1076,7 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n  \t\titem->arg_len = 0;\n  \t\titem->offset_in_buf = todo_list->buf.len;\n  \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n -\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n -\t\t\topts->action == REPLAY_PICK ?  \"pick\" : \"revert\",\n +\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n  \t\t\tshort_commit_name(commit), subject_len, subject);\n  \t\tunuse_commit_buffer(commit, commit_buffer);\n  \t}\n @@ -1077,7 +1091,7 @@ static int create_seq_dir(void)\n  \t\treturn -1;\n  \t}\n  \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n -\t\treturn error_errno(_(\"Could not create sequencer directory %s\"),\n +\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n  \t\t\t\t   git_path_seq_dir());\n  \treturn 0;\n  }\n @@ -1096,12 +1110,12 @@ static int save_head(const char *head)\n  \tstrbuf_addf(&buf, \"%s\\n\", head);\n  \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n  \t\trollback_lock_file(&head_lock);\n -\t\treturn error_errno(_(\"Could not write to %s\"),\n +\t\treturn error_errno(_(\"Could not write to '%s'\"),\n  \t\t\t\t   git_path_head_file());\n  \t}\n  \tif (commit_lock_file(&head_lock) < 0) {\n  \t\trollback_lock_file(&head_lock);\n -\t\treturn error(_(\"Error wrapping up %s.\"), git_path_head_file());\n +\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n  \t}\n  \treturn 0;\n  }\n @@ -1136,9 +1150,6 @@ int sequencer_rollback(struct replay_opts *opts)\n  \tunsigned char sha1[20];\n  \tstruct strbuf buf = STRBUF_INIT;\n  \n -\tif (read_and_refresh_cache(opts))\n -\t\treturn -1;\n -\n  \tf = fopen(git_path_head_file(), \"r\");\n  \tif (!f && errno == ENOENT) {\n  \t\t/*\n @@ -1149,9 +1160,9 @@ int sequencer_rollback(struct replay_opts *opts)\n  \t\treturn rollback_single_pick();\n  \t}\n  \tif (!f)\n -\t\treturn error_errno(_(\"cannot open %s\"), git_path_head_file());\n +\t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n  \tif (strbuf_getline_lf(&buf, f)) {\n -\t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n +\t\terror(_(\"cannot read '%s': %s\"), git_path_head_file(),\n  \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n  \t\tfclose(f);\n  \t\tgoto fail;\n @@ -1183,16 +1194,14 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n  \n  \tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n  \tif (fd < 0)\n -\t\treturn error_errno(_(\"Could not lock '%s'\"),\n -\t\t\t\t   git_path_todo_file());\n +\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n  \toffset = next < todo_list->nr ?\n  \t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n  \tif (write_in_full(fd, todo_list->buf.buf + offset,\n  \t\t\ttodo_list->buf.len - offset) < 0)\n -\t\treturn error(_(\"Could not write to %s (%s)\"),\n -\t\t\ttodo_path, strerror(errno));\n +\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n  \tif (commit_lock_file(&todo_lock) < 0)\n -\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n +\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n  \treturn 0;\n  }\n  \n @@ -1279,21 +1288,25 @@ int sequencer_continue(struct replay_opts *opts)\n  \n  \tif (!file_exists(get_todo_path(opts)))\n  \t\treturn continue_single_pick();\n -\tif (read_populate_opts(opts) ||\n -\t\t\tread_populate_todo(&todo_list, opts))\n +\tif (read_populate_opts(opts))\n  \t\treturn -1;\n +\tif ((res = read_populate_todo(&todo_list, opts)))\n +\t\tgoto release_todo_list;\n  \n  \t/* Verify that the conflict has been resolved */\n  \tif (file_exists(git_path_cherry_pick_head()) ||\n  \t    file_exists(git_path_revert_head())) {\n -\t\tint ret = continue_single_pick();\n -\t\tif (ret)\n -\t\t\treturn ret;\n +\t\tres = continue_single_pick();\n +\t\tif (res)\n +\t\t\tgoto release_todo_list;\n +\t}\n +\tif (index_differs_from(\"HEAD\", 0)) {\n +\t\tres = error_dirty_index(opts);\n +\t\tgoto release_todo_list;\n  \t}\n -\tif (index_differs_from(\"HEAD\", 0))\n -\t\treturn error_dirty_index(opts);\n  \ttodo_list.current++;\n  \tres = pick_commits(&todo_list, opts);\n +release_todo_list:\n  \ttodo_list_release(&todo_list);\n  \treturn res;\n  }\n diff --git a/sequencer.h b/sequencer.h\n index e272549..688fff1 100644\n --- a/sequencer.h\n +++ b/sequencer.h\n @@ -40,9 +40,13 @@ struct replay_opts {\n  \tvoid **owned;\n  \tint owned_nr, owned_alloc;\n  };\n -#define REPLAY_OPTS_INIT { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0 }\n +#define REPLAY_OPTS_INIT { -1 }\n  \n -void *sequencer_entrust(struct replay_opts *opts, void *set_me_free_after_use);\n +/*\n + * Make it the duty of sequencer_remove_state() to release the memory;\n + * For ease of use, return the same pointer.\n + */\n +void *sequencer_entrust(struct replay_opts *opts, void *to_free);\n  \n  int sequencer_pick_revisions(struct replay_opts *opts);\n  int sequencer_continue(struct replay_opts *opts);\n diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n index 6465edf..7b7a89d 100755\n --- a/t/t3510-cherry-pick-sequence.sh\n +++ b/t/t3510-cherry-pick-sequence.sh\n @@ -459,6 +459,17 @@ test_expect_success 'malformed instruction sheet 1' '\n  \ttest_expect_code 128 git cherry-pick --continue\n  '\n  \n +test_expect_success 'malformed instruction sheet 2' '\n +\tpristine_detach initial &&\n +\ttest_expect_code 1 git cherry-pick base..anotherpick &&\n +\techo \"resolved\" >foo &&\n +\tgit add foo &&\n +\tgit commit &&\n +\tsed \"s/pick/revert/\" .git/sequencer/todo >new_sheet &&\n +\tcp new_sheet .git/sequencer/todo &&\n +\ttest_expect_code 128 git cherry-pick --continue\n +'\n +\n  test_expect_success 'empty commit set' '\n  \tpristine_detach initial &&\n  \ttest_expect_code 128 git cherry-pick base..base\n\n-- \n2.10.0.windows.1.10.g803177d\n\nbase-commit: 8a04d01a511ecffba8a397d26ee7fa6ca56b6e7e\n"},{"id":"301633","messageId":"5c52dcbff8b21b24a360d6f5bd2710fe1139eb4a.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 02/25] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:52:37Z","receivedAt":"2016-09-11T10:53:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/commit.c |  2 +-\n sequencer.c      | 11 ++++++-----\n sequencer.h      |  5 +----\n 3 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex bb9f79b..e79af9d 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)\n \t\twhence = FROM_MERGE;\n \telse if (file_exists(git_path_cherry_pick_head())) {\n \t\twhence = FROM_CHERRY_PICK;\n-\t\tif (file_exists(git_path(SEQ_DIR)))\n+\t\tif (file_exists(git_path_seq_dir()))\n \t\t\tsequencer_in_use = 1;\n \t}\n \telse\ndiff --git a/sequencer.c b/sequencer.c\nindex eec8a60..cb16cbd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -21,10 +21,11 @@\n const char sign_off_header[] = \"Signed-off-by: \";\n static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n \n-static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n-static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n-static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n-static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n+GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n+\n+static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n+static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n+static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n static int is_rfc2822_line(const char *buf, int len)\n {\n@@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n+\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n \tremove_dir_recursively(&seq_dir, 0);\n \tstrbuf_release(&seq_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex db425ad..dd4d33a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -1,10 +1,7 @@\n #ifndef SEQUENCER_H\n #define SEQUENCER_H\n \n-#define SEQ_DIR\t\t\"sequencer\"\n-#define SEQ_HEAD_FILE\t\"sequencer/head\"\n-#define SEQ_TODO_FILE\t\"sequencer/todo\"\n-#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n+const char *git_path_seq_dir(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301634","messageId":"2587881a45d5a81cda4b2eb40e2d7d8d55b7931c.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 03/25] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:52:57Z","receivedAt":"2016-09-11T10:53:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We really do not need the *pointer to a* pointer to the options in\nthe read_populate_opts() function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb16cbd..c2fbf6f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -813,7 +813,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static int read_populate_opts(struct replay_opts **opts)\n+static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n@@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n \t * about this case, though, because we wrote that file ourselves, so we\n \t * are pretty certain that it is syntactically correct.\n \t */\n-\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n+\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n \t\treturn error(_(\"Malformed options sheet: %s\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n@@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n \n \tif (!file_exists(git_path_todo_file()))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(&opts) ||\n+\tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n \t\treturn -1;\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301635","messageId":"942aa559a0af9b52e079c5c78fa313f49b87d50d.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:07Z","receivedAt":"2016-09-11T10:53:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\nlike a one-shot command when it reads its configuration: memory is\nallocated and released only when the command exits.\n\nThis is kind of okay for git-cherry-pick, which *is* a one-shot\ncommand. All the work to make the sequencer its work horse was\ndone to allow using the functionality as a library function, though,\nincluding proper clean-up after use.\n\nThis patch introduces an API to pass the responsibility of releasing\ncertain memory to the sequencer. Example:\n\n\tconst char *label =\n\t\tsequencer_entrust(opts, xstrfmt(\"From: %s\", email));\n\nThe entrusted memory will remain valid until sequencer_remove_state() is\ncalled, or the program exits, whichever comes first.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 13 +++++++++++++\n sequencer.h | 10 ++++++++++\n 2 files changed, 23 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d272fb..8d56a05 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -114,9 +114,22 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+void *sequencer_entrust(struct replay_opts *opts, void *to_free)\n+{\n+\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n+\topts->owned[opts->owned_nr++] = to_free;\n+\n+\treturn to_free;\n+}\n+\n static void remove_sequencer_state(const struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n+\tint i;\n+\n+\tfor (i = 0; i < opts->owned_nr; i++)\n+\t\tfree(opts->owned[i]);\n+\tfree(opts->owned);\n \n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\ndiff --git a/sequencer.h b/sequencer.h\nindex dd4d33a..04892a9 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -43,9 +43,19 @@ struct replay_opts {\n \n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n+\n+\t/* malloc()ed data entrusted to the sequencer */\n+\tvoid **owned;\n+\tint owned_nr, owned_alloc;\n };\n #define REPLAY_OPTS_INIT { -1, -1 }\n \n+/*\n+ * Make it the duty of sequencer_remove_state() to release the memory;\n+ * For ease of use, return the same pointer.\n+ */\n+void *sequencer_entrust(struct replay_opts *opts, void *to_free);\n+\n int sequencer_pick_revisions(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301636","messageId":"d6b92cd7aa56ceb515c50467a0e6030401e2e1bc.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:02Z","receivedAt":"2016-09-11T10:53:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In a couple of commits, we will teach the sequencer to handle the\nnitty gritty of the interactive rebase, which keeps its state in a\ndifferent directory.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c2fbf6f..8d272fb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,11 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+static const char *get_dir(const struct replay_opts *opts)\n+{\n+\treturn git_path_seq_dir();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -109,13 +114,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(void)\n+static void remove_sequencer_state(const struct replay_opts *opts)\n {\n-\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n-\tremove_dir_recursively(&seq_dir, 0);\n-\tstrbuf_release(&seq_dir);\n+\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -940,7 +945,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n \treturn 0;\n fail:\n@@ -1034,7 +1039,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \treturn 0;\n }\n \n@@ -1095,7 +1100,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t * one that is being continued\n \t */\n \tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(opts);\n \t\treturn 0;\n \t}\n \tif (opts->subcommand == REPLAY_ROLLBACK)\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301637","messageId":"7654513b93b7126077243b9e16538facbd35ab08.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 06/25] sequencer: release memory that was allocated when reading options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:10Z","receivedAt":"2016-09-11T10:53:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer reads options from disk and stores them in its struct\nfor use during sequencer's operations.\n\nWith this patch, the memory is released afterwards, plugging a\nmemory leak.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d56a05..3ca231f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -131,6 +131,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \t\tfree(opts->owned[i]);\n \tfree(opts->owned);\n \n+\tfree(opts->xopts);\n+\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n@@ -815,13 +817,18 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n \telse if (!strcmp(key, \"options.mainline\"))\n \t\topts->mainline = git_config_int(key, value);\n-\telse if (!strcmp(key, \"options.strategy\"))\n+\telse if (!strcmp(key, \"options.strategy\")) {\n \t\tgit_config_string(&opts->strategy, key, value);\n-\telse if (!strcmp(key, \"options.gpg-sign\"))\n+\t\tsequencer_entrust(opts, (char *) opts->strategy);\n+\t}\n+\telse if (!strcmp(key, \"options.gpg-sign\")) {\n \t\tgit_config_string(&opts->gpg_sign, key, value);\n+\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n+\t}\n \telse if (!strcmp(key, \"options.strategy-option\")) {\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n-\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n+\t\topts->xopts[opts->xopts_nr++] =\n+\t\t\tsequencer_entrust(opts, xstrdup(value));\n \t} else\n \t\treturn error(_(\"Invalid key: %s\"), key);\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301638","messageId":"19f49ce9df124871c77474386164e51defe4416b.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 07/25] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:14Z","receivedAt":"2016-09-11T10:53:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Over the next commits, we will work on improving the sequencer to the\npoint where it can process the edit script of an interactive rebase. To\nthat end, we will need to teach the sequencer to read interactive\nrebase's todo file. In preparation, we consolidate all places where\nthat todo file is needed to call a function that we will later extend.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 3ca231f..da6de22 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n \treturn git_path_seq_dir();\n }\n \n+static const char *get_todo_path(const struct replay_opts *opts)\n+{\n+\treturn git_path_todo_file();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -776,25 +781,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n static int read_populate_todo(struct commit_list **todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n+\tconst char *todo_file = get_todo_path(opts);\n \tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n-\tfd = open(git_path_todo_file(), O_RDONLY);\n+\tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"),\n-\t\t\t\t   git_path_todo_file());\n+\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n \tif (strbuf_read(&buf, fd, 0) < 0) {\n \t\tclose(fd);\n \t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n+\t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n \tstrbuf_release(&buf);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n-\t\t\tgit_path_todo_file());\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n@@ -1077,7 +1081,7 @@ static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n \n-\tif (!file_exists(git_path_todo_file()))\n+\tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301639","messageId":"82e21d92e9848f026b2bf8911ee0530e2d6d98eb.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 08/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:20Z","receivedAt":"2016-09-11T10:53:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When we came up with the \"sequencer\" idea, we really wanted to have\nkind of a plumbing equivalent of the interactive rebase. Hence the\nchoice of words: the \"todo\" script, a \"pick\", etc.\n\nHowever, when it came time to implement the entire shebang, somehow this\nidea got lost and the sequencer was used as working horse for\ncherry-pick and revert instead. So as not to interfere with the\ninteractive rebase, it even uses a separate directory to store its\nstate.\n\nFurthermore, it also is stupidly strict about the \"todo\" script it\naccepts: while it parses commands in a way that was *designed* to be\nsimilar to the interactive rebase, it then goes on to *error out* if the\ncommands disagree with the overall action (cherry-pick or revert).\n\nFinally, the sequencer code chose to deviate from the interactive rebase\ncode insofar that it *reformats* the \"todo\" script instead of just\nwriting the part of the parsed script that were not yet processed. This\nis not only unnecessary churn, but might well lose information that is\nvaluable to the user (i.e. comments after the commands).\n\nLet's just bite the bullet and rewrite the entire parser; the code now\nbecomes not only more elegant: it allows us to go on and teach the\nsequencer how to parse *true* \"todo\" scripts as used by the interactive\nrebase itself. In a way, the sequencer is about to grow up to do its\nolder brother's job. Better.\n\nIn particular, we choose to maintain the list of commands in an array\ninstead of a linked list: this is flexible enough to allow us later on to\neven implement rebase -i's reordering of fixup!/squash! commits very\neasily (and with a very nice speed bonus, at least on Windows).\n\nWhile at it, do not stop at the first problem, but list *all* of the\nproblems. This will help the user when the sequencer will do `rebase\n-i`'s work by allowing to address all issues in one go rather than going\nback and forth until the todo list is valid.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 275 +++++++++++++++++++++++++++++++++++-------------------------\n 1 file changed, 159 insertions(+), 116 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex da6de22..b971ad0 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -473,7 +473,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \t\treturn 1;\n }\n \n-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n+enum todo_command {\n+\tTODO_PICK = 0,\n+\tTODO_REVERT\n+};\n+\n+static const char *todo_command_strings[] = {\n+\t\"pick\",\n+\t\"revert\"\n+};\n+\n+static const char *command_to_string(const enum todo_command command)\n+{\n+\tif (command < ARRAY_SIZE(todo_command_strings))\n+\t\treturn todo_command_strings[command];\n+\tdie(\"Unknown command: %d\", command);\n+}\n+\n+\n+static int do_pick_commit(enum todo_command command, struct commit *commit,\n+\t\tstruct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -535,7 +554,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t/* TRANSLATORS: The first %s will be \"revert\" or\n \t\t   \"cherry-pick\", the second %s a SHA1 */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n-\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n+\t\t\tcommand_to_string(command),\n+\t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n@@ -548,7 +568,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * reverse of it if we are revert.\n \t */\n \n-\tif (opts->action == REPLAY_REVERT) {\n+\tif (command == TODO_REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -589,7 +609,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t}\n \t}\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n@@ -615,17 +635,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * However, if the merge did not even start, then we don't want to\n \t * write it at all.\n \t */\n-\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n+\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n-\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n+\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n \n \tif (res) {\n-\t\terror(opts->action == REPLAY_REVERT\n+\t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n \t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n@@ -687,116 +707,121 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n-\t\tstruct replay_opts *opts)\n+struct todo_item {\n+\tenum todo_command command;\n+\tstruct commit *commit;\n+\tsize_t offset_in_buf;\n+};\n+\n+struct todo_list {\n+\tstruct strbuf buf;\n+\tstruct todo_item *items;\n+\tint nr, alloc, current;\n+};\n+\n+#define TODO_LIST_INIT { STRBUF_INIT }\n+\n+static void todo_list_release(struct todo_list *todo_list)\n {\n-\tstruct commit_list *cur = NULL;\n-\tconst char *sha1_abbrev = NULL;\n-\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n-\tconst char *subject;\n-\tint subject_len;\n+\tstrbuf_release(&todo_list->buf);\n+\tfree(todo_list->items);\n+\ttodo_list->items = NULL;\n+\ttodo_list->nr = todo_list->alloc = 0;\n+}\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n-\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n-\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n-\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n-\t\t\tsubject_len, subject);\n-\t\tunuse_commit_buffer(cur->item, commit_buffer);\n-\t}\n-\treturn 0;\n+struct todo_item *append_new_todo(struct todo_list *todo_list)\n+{\n+\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n+\treturn todo_list->items + todo_list->nr++;\n }\n \n-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n {\n \tunsigned char commit_sha1[20];\n-\tenum replay_action action;\n \tchar *end_of_object_name;\n-\tint saved, status, padding;\n-\n-\tif (starts_with(bol, \"pick\")) {\n-\t\taction = REPLAY_PICK;\n-\t\tbol += strlen(\"pick\");\n-\t} else if (starts_with(bol, \"revert\")) {\n-\t\taction = REPLAY_REVERT;\n-\t\tbol += strlen(\"revert\");\n-\t} else\n-\t\treturn NULL;\n+\tint i, saved, status, padding;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n+\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n+\t\t\titem->command = i;\n+\t\t\tbreak;\n+\t\t}\n+\tif (i >= ARRAY_SIZE(todo_command_strings))\n+\t\treturn -1;\n \n \t/* Eat up extra spaces/ tabs before object name */\n \tpadding = strspn(bol, \" \\t\");\n \tif (!padding)\n-\t\treturn NULL;\n+\t\treturn -1;\n \tbol += padding;\n \n-\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n+\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n \tsaved = *end_of_object_name;\n \t*end_of_object_name = '\\0';\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n-\t/*\n-\t * Verify that the action matches up with the one in\n-\t * opts; we don't support arbitrary instructions\n-\t */\n-\tif (action != opts->action) {\n-\t\tif (action == REPLAY_REVERT)\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot revert during another revert.\")\n-\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n-\t\telse\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n-\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n-\t\treturn NULL;\n-\t}\n-\n \tif (status < 0)\n-\t\treturn NULL;\n+\t\treturn -1;\n \n-\treturn lookup_commit_reference(commit_sha1);\n+\titem->commit = lookup_commit_reference(commit_sha1);\n+\treturn !item->commit;\n }\n \n-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n-\t\t\tstruct replay_opts *opts)\n+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n {\n-\tstruct commit_list **next = todo_list;\n-\tstruct commit *commit;\n+\tstruct todo_item *item;\n \tchar *p = buf;\n-\tint i;\n+\tint i, res = 0;\n \n \tfor (i = 1; *p; i++) {\n \t\tchar *eol = strchrnul(p, '\\n');\n-\t\tcommit = parse_insn_line(p, eol, opts);\n-\t\tif (!commit)\n-\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n-\t\tnext = commit_list_append(commit, next);\n+\n+\t\titem = append_new_todo(todo_list);\n+\t\titem->offset_in_buf = p - todo_list->buf.buf;\n+\t\tif (parse_insn_line(item, p, eol)) {\n+\t\t\tres |= error(_(\"Invalid line %d: %.*s\"),\n+\t\t\t\ti, (int)(eol - p), p);\n+\t\t\titem->command = -1;\n+\t\t}\n \t\tp = *eol ? eol + 1 : eol;\n \t}\n-\tif (!*todo_list)\n+\tif (!todo_list->nr)\n \t\treturn error(_(\"No commits parsed.\"));\n-\treturn 0;\n+\treturn res;\n }\n \n-static int read_populate_todo(struct commit_list **todo_list,\n+static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n \tconst char *todo_file = get_todo_path(opts);\n-\tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n+\tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n-\tif (strbuf_read(&buf, fd, 0) < 0) {\n+\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\tstrbuf_release(&buf);\n \t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n-\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n-\tstrbuf_release(&buf);\n+\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n+\tif (!res) {\n+\t\tenum todo_command valid =\n+\t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < todo_list->nr; i++)\n+\t\t\tif (valid == todo_list->items[i].command)\n+\t\t\t\tcontinue;\n+\t\t\telse if (valid == TODO_PICK)\n+\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\telse\n+\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t}\n+\n \tif (res)\n \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n@@ -858,18 +883,33 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int walk_revs_populate_todo(struct commit_list **todo_list,\n+static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n+\tenum todo_command command = opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT;\n+\tconst char *command_string = todo_command_strings[command];\n \tstruct commit *commit;\n-\tstruct commit_list **next;\n \n \tif (prepare_revs(opts))\n \t\treturn -1;\n \n-\tnext = todo_list;\n-\twhile ((commit = get_revision(opts->revs)))\n-\t\tnext = commit_list_append(commit, next);\n+\twhile ((commit = get_revision(opts->revs))) {\n+\t\tstruct todo_item *item = append_new_todo(todo_list);\n+\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n+\t\tconst char *subject;\n+\t\tint subject_len;\n+\n+\t\titem->command = command;\n+\t\titem->commit = commit;\n+\t\titem->offset_in_buf = todo_list->buf.len;\n+\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n+\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n+\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n+\t\t\t\tDEFAULT_ABBREV),\n+\t\t\tsubject_len, subject);\n+\t\tunuse_commit_buffer(commit, commit_buffer);\n+\t}\n \treturn 0;\n }\n \n@@ -977,30 +1017,22 @@ static int sequencer_rollback(struct replay_opts *opts)\n \treturn -1;\n }\n \n-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstatic struct lock_file todo_lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint fd;\n+\tconst char *todo_path = get_todo_path(opts);\n+\tint next = todo_list->current, offset, fd;\n \n-\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n+\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"),\n-\t\t\t\t   git_path_todo_file());\n-\tif (format_todo(&buf, todo_list, opts) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n-\t}\n-\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n-\t\t\t\t   git_path_todo_file());\n-\t}\n-\tif (commit_lock_file(&todo_lock) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n-\t}\n-\tstrbuf_release(&buf);\n+\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\toffset = next < todo_list->nr ?\n+\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n+\tif (write_in_full(fd, todo_list->buf.buf + offset,\n+\t\t\ttodo_list->buf.len - offset) < 0)\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\tif (commit_lock_file(&todo_lock) < 0)\n+\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1039,9 +1071,8 @@ static int save_opts(struct replay_opts *opts)\n \treturn res;\n }\n \n-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *cur;\n \tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n@@ -1051,10 +1082,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tif (save_todo(cur, opts))\n+\twhile (todo_list->current < todo_list->nr) {\n+\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n+\t\tif (save_todo(todo_list, opts))\n \t\t\treturn -1;\n-\t\tres = do_pick_commit(cur->item, opts);\n+\t\tres = do_pick_commit(item->command, item->commit, opts);\n+\t\ttodo_list->current++;\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -1079,38 +1112,46 @@ static int continue_single_pick(void)\n \n static int sequencer_continue(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n \n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(opts) ||\n-\t\t\tread_populate_todo(&todo_list, opts))\n+\tif (read_populate_opts(opts))\n \t\treturn -1;\n+\tif ((res = read_populate_todo(&todo_list, opts)))\n+\t\tgoto release_todo_list;\n \n \t/* Verify that the conflict has been resolved */\n \tif (file_exists(git_path_cherry_pick_head()) ||\n \t    file_exists(git_path_revert_head())) {\n-\t\tint ret = continue_single_pick();\n-\t\tif (ret)\n-\t\t\treturn ret;\n+\t\tres = continue_single_pick();\n+\t\tif (res)\n+\t\t\tgoto release_todo_list;\n \t}\n-\tif (index_differs_from(\"HEAD\", 0))\n-\t\treturn error_dirty_index(opts);\n-\ttodo_list = todo_list->next;\n-\treturn pick_commits(todo_list, opts);\n+\tif (index_differs_from(\"HEAD\", 0)) {\n+\t\tres = error_dirty_index(opts);\n+\t\tgoto release_todo_list;\n+\t}\n+\ttodo_list.current++;\n+\tres = pick_commits(&todo_list, opts);\n+release_todo_list:\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n static int single_pick(struct commit *cmit, struct replay_opts *opts)\n {\n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(cmit, opts);\n+\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n }\n \n int sequencer_pick_revisions(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n \tunsigned char sha1[20];\n-\tint i;\n+\tint i, res;\n \n \tif (opts->subcommand == REPLAY_NONE)\n \t\tassert(opts->revs);\n@@ -1185,7 +1226,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\treturn -1;\n \tif (save_opts(opts))\n \t\treturn -1;\n-\treturn pick_commits(todo_list, opts);\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301640","messageId":"a8f59af7bccdca01d34f77c1c259639175191a12.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 09/25] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:39Z","receivedAt":"2016-09-11T10:54:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b971ad0..7ba932b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -232,11 +232,8 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(action_name(opts));\n \n-\t/* Different translation strings for cherry-pick and revert */\n-\tif (opts->action == REPLAY_PICK)\n-\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n-\telse\n-\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n+\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\t\taction_name(opts));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301641","messageId":"955727a7cf5bd64f1c1106b394095d5449a4a2dc.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 10/25] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:53:59Z","receivedAt":"2016-09-11T10:54:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The subcommands are used exactly once, at the very beginning of\nsequencer_pick_revisions(), to determine what to do. This is an\nunnecessary level of indirection: we can simply call the correct\nfunction to begin with. So let's do that.\n\nWhile at it, ensure that the subcommands return an error code so that\nthey do not have to die() all over the place (bad practice for library\nfunctions...).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 36 ++++++++++++++++--------------------\n sequencer.c      | 35 +++++++++++------------------------\n sequencer.h      | 13 ++++---------\n 3 files changed, 31 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 7365559..c9ae4dc 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \t\tdie(_(\"%s: %s cannot be used with %s\"), me, this_opt, base_opt);\n }\n \n-static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n+static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tconst char *me = action_name(opts);\n@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n-\t/* Set the subcommand */\n-\tif (cmd == 'q')\n-\t\topts->subcommand = REPLAY_REMOVE_STATE;\n-\telse if (cmd == 'c')\n-\t\topts->subcommand = REPLAY_CONTINUE;\n-\telse if (cmd == 'a')\n-\t\topts->subcommand = REPLAY_ROLLBACK;\n-\telse\n-\t\topts->subcommand = REPLAY_NONE;\n-\n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\tchar *this_operation;\n-\t\tif (opts->subcommand == REPLAY_REMOVE_STATE)\n+\t\tif (cmd == 'q')\n \t\t\tthis_operation = \"--quit\";\n-\t\telse if (opts->subcommand == REPLAY_CONTINUE)\n+\t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n \t\telse {\n-\t\t\tassert(opts->subcommand == REPLAY_ROLLBACK);\n+\t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n \t\t}\n \n@@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--edit\", opts->edit,\n \t\t\t\tNULL);\n \n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\topts->revs = NULL;\n \t} else {\n \t\tstruct setup_revision_opt s_r_opt;\n@@ -174,6 +164,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n \tif (argc > 1)\n \t\tusage_with_options(usage_str, options);\n+\n+\tif (cmd == 'q')\n+\t\treturn sequencer_remove_state(opts);\n+\tif (cmd == 'c')\n+\t\treturn sequencer_continue(opts);\n+\tif (cmd == 'a')\n+\t\treturn sequencer_rollback(opts);\n+\treturn sequencer_pick_revisions(opts);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n@@ -185,8 +183,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -199,8 +196,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\ndiff --git a/sequencer.c b/sequencer.c\nindex 7ba932b..053e78c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -127,7 +127,7 @@ void *sequencer_entrust(struct replay_opts *opts, void *to_free)\n \treturn to_free;\n }\n \n-static void remove_sequencer_state(const struct replay_opts *opts)\n+int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tint i;\n@@ -141,6 +141,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n+\n+\treturn 0;\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -971,7 +973,7 @@ static int rollback_single_pick(void)\n \treturn reset_for_rollback(head_sha1);\n }\n \n-static int sequencer_rollback(struct replay_opts *opts)\n+int sequencer_rollback(struct replay_opts *opts)\n {\n \tFILE *f;\n \tunsigned char sha1[20];\n@@ -1006,9 +1008,8 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n fail:\n \tstrbuf_release(&buf);\n \treturn -1;\n@@ -1093,8 +1094,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state(opts);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n }\n \n static int continue_single_pick(void)\n@@ -1107,11 +1107,14 @@ static int continue_single_pick(void)\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n \n-static int sequencer_continue(struct replay_opts *opts)\n+int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tint res;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts))\n@@ -1150,26 +1153,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tint i, res;\n \n-\tif (opts->subcommand == REPLAY_NONE)\n-\t\tassert(opts->revs);\n-\n+\tassert(opts->revs);\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\t/*\n-\t * Decide what to do depending on the arguments; a fresh\n-\t * cherry-pick should be handled differently from an existing\n-\t * one that is being continued\n-\t */\n-\tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state(opts);\n-\t\treturn 0;\n-\t}\n-\tif (opts->subcommand == REPLAY_ROLLBACK)\n-\t\treturn sequencer_rollback(opts);\n-\tif (opts->subcommand == REPLAY_CONTINUE)\n-\t\treturn sequencer_continue(opts);\n-\n \tfor (i = 0; i < opts->revs->pending.nr; i++) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = opts->revs->pending.objects[i].name;\ndiff --git a/sequencer.h b/sequencer.h\nindex 04892a9..0b3950d 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -10,16 +10,8 @@ enum replay_action {\n \tREPLAY_PICK\n };\n \n-enum replay_subcommand {\n-\tREPLAY_NONE,\n-\tREPLAY_REMOVE_STATE,\n-\tREPLAY_CONTINUE,\n-\tREPLAY_ROLLBACK\n-};\n-\n struct replay_opts {\n \tenum replay_action action;\n-\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -48,7 +40,7 @@ struct replay_opts {\n \tvoid **owned;\n \tint owned_nr, owned_alloc;\n };\n-#define REPLAY_OPTS_INIT { -1, -1 }\n+#define REPLAY_OPTS_INIT { -1 }\n \n /*\n  * Make it the duty of sequencer_remove_state() to release the memory;\n@@ -57,6 +49,9 @@ struct replay_opts {\n void *sequencer_entrust(struct replay_opts *opts, void *to_free);\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n+int sequencer_continue(struct replay_opts *opts);\n+int sequencer_rollback(struct replay_opts *opts);\n+int sequencer_remove_state(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301642","messageId":"c825f6bce7d15c83725c99eda8926d3dfaddf71e.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 11/25] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:04Z","receivedAt":"2016-09-11T10:54:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Not only does this DRY up the code (providing a better documentation what\nthe code is about, as well as allowing to change the behavior in a single\nplace), it also makes it substantially shorter to use the same\nfunctionality in functions to be introduced when we teach the sequencer to\nprocess interactive-rebase's git-rebase-todo file.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 053e78c..0c8dec4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -157,13 +157,18 @@ struct commit_message {\n \tconst char *message;\n };\n \n+static const char *short_commit_name(struct commit *commit)\n+{\n+\treturn find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+}\n+\n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n \tint subject_len;\n \n \tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n-\tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+\tabbrev = short_commit_name(commit);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n@@ -647,8 +652,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n-\t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n-\t\t      msg.subject);\n+\t\t      short_commit_name(commit), msg.subject);\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t\tgoto leave;\n@@ -904,9 +908,7 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n-\t\t\t\tDEFAULT_ABBREV),\n-\t\t\tsubject_len, subject);\n+\t\t\tshort_commit_name(commit), subject_len, subject);\n \t\tunuse_commit_buffer(commit, commit_buffer);\n \t}\n \treturn 0;\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301643","messageId":"5ef9905112fe7b9b785bca8892a26972aca43782.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:10Z","receivedAt":"2016-09-11T10:54:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The `git-rebase-todo` file contains a list of commands. Most of those\ncommands have the form\n\n\t<verb> <sha1> <oneline>\n\nThe <oneline> is displayed primarily for the user's convenience, as\nrebase -i really interprets only the <verb> <sha1> part. However, there\nare *some* places in interactive rebase where the <oneline> is used to\ndisplay messages, e.g. for reporting at which commit we stopped.\n\nSo let's just remember it when parsing the todo file; we keep a copy of\nthe entire todo file anyway (to write out the new `done` and\n`git-rebase-todo` file just before processing each command), so all we\nneed to do is remember the begin offsets and lengths.\n\nAs we will have to parse and remember the command-line for `exec` commands\nlater, we do not call the field \"oneline\" but rather \"arg\" (and will reuse\nthat for exec's command-line).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 0c8dec4..ca1961c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -713,6 +713,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n struct todo_item {\n \tenum todo_command command;\n \tstruct commit *commit;\n+\tconst char *arg;\n+\tint arg_len;\n \tsize_t offset_in_buf;\n };\n \n@@ -764,6 +766,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n+\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n+\titem->arg_len = (int)(eol - item->arg);\n+\n \tif (status < 0)\n \t\treturn -1;\n \n@@ -905,6 +910,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \n \t\titem->command = command;\n \t\titem->commit = commit;\n+\t\titem->arg = NULL;\n+\t\titem->arg_len = 0;\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301644","messageId":"6b8be36604a78b5069eaefce3e8dcff6b7e67c78.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:16Z","receivedAt":"2016-09-11T10:54:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In interactive rebases, we commit a little bit differently than the\nsequencer did so far: we heed the \"author-script\", the \"message\" and\nthe \"amend\" files in the .git/rebase-merge/ subdirectory.\n\nLikewise, we may want to edit the commit message *even* when providing\na file containing the suggested commit message. Therefore we change the\ncode to not even provide a default message when we do not want any, and\nto call the editor explicitly.\n\nAs interactive rebase's GPG settings are configured differently from\nhow cherry-pick (and therefore sequencer) handles them, we will leave\nsupport for that to the next commit.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------\n sequencer.h |  3 ++\n 2 files changed, 89 insertions(+), 11 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ca1961c..6c35fe8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+/*\n+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n+ * GIT_AUTHOR_DATE that will be used for the commit that is currently\n+ * being rebased.\n+ */\n+static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+\n+/* We will introduce the 'interactive rebase' mode later */\n+static inline int is_rebase_i(const struct replay_opts *opts)\n+{\n+\treturn 0;\n+}\n+\n static const char *get_dir(const struct replay_opts *opts)\n {\n \treturn git_path_seq_dir();\n@@ -377,20 +390,76 @@ static int is_index_unchanged(void)\n \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n }\n \n+static char **read_author_script(void)\n+{\n+\tstruct strbuf script = STRBUF_INIT;\n+\tint i, count = 0;\n+\tchar *p, *p2, **env;\n+\tsize_t env_size;\n+\n+\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n+\t\treturn NULL;\n+\n+\tfor (p = script.buf; *p; p++)\n+\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n+\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n+\t\telse if (*p == '\\'')\n+\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n+\t\telse if (*p == '\\n') {\n+\t\t\t*p = '\\0';\n+\t\t\tcount++;\n+\t\t}\n+\n+\tenv_size = (count + 1) * sizeof(*env);\n+\tstrbuf_grow(&script, env_size);\n+\tmemmove(script.buf + env_size, script.buf, script.len);\n+\tp = script.buf + env_size;\n+\tenv = (char **)strbuf_detach(&script, NULL);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tenv[i] = p;\n+\t\tp += strlen(p) + 1;\n+\t}\n+\tenv[count] = NULL;\n+\n+\treturn env;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n  * author date and name.\n+ *\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n+ *\n+ * An exception is when sequencer_commit() is called during an\n+ * interactive rebase: in that case, we will want to retain the\n+ * author metadata.\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n+int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\t\t  int allow_empty)\n {\n+\tchar **env = NULL;\n \tstruct argv_array array;\n \tint rc;\n \tconst char *value;\n \n+\tif (is_rebase_i(opts)) {\n+\t\tenv = read_author_script();\n+\t\tif (!env)\n+\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\t\t\"tree. If these changes are meant to be\\n\"\n+\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n+\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"If they are meant to go into a new commit, \"\n+\t\t\t\t\"run:\\n\\n\"\n+\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"In both cases, once you're done, continue \"\n+\t\t\t\t\"with:\\n\\n\"\n+\t\t\t\t\"  git rebase --continue\\n\");\n+\t}\n+\n \targv_array_init(&array);\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n@@ -399,14 +468,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n \t\targv_array_push(&array, \"-s\");\n-\tif (!opts->edit) {\n-\t\targv_array_push(&array, \"-F\");\n-\t\targv_array_push(&array, defmsg);\n-\t\tif (!opts->signoff &&\n-\t\t    !opts->record_origin &&\n-\t\t    git_config_get_value(\"commit.cleanup\", &value))\n-\t\t\targv_array_push(&array, \"--cleanup=verbatim\");\n-\t}\n+\tif (defmsg)\n+\t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (opts->edit)\n+\t\targv_array_push(&array, \"-e\");\n+\telse if (!opts->signoff && !opts->record_origin &&\n+\t\t git_config_get_value(\"commit.cleanup\", &value))\n+\t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n \tif (allow_empty)\n \t\targv_array_push(&array, \"--allow-empty\");\n@@ -414,8 +482,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&array, \"--allow-empty-message\");\n \n-\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\trc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,\n+\t\t\t(const char *const *)env);\n \targv_array_clear(&array);\n+\tfree(env);\n+\n \treturn rc;\n }\n \n@@ -664,7 +735,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = run_git_commit(git_path_merge_msg(), opts, allow);\n+\t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\t\topts, allow);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -877,6 +949,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n+\tif (is_rebase_i(opts))\n+\t\treturn 0;\n+\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n \t/*\ndiff --git a/sequencer.h b/sequencer.h\nindex 0b3950d..16deb6c 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -53,6 +53,9 @@ int sequencer_continue(struct replay_opts *opts);\n int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n+int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n+\t\t\t  int allow_empty);\n+\n extern const char sign_off_header[];\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301645","messageId":"9787d4599f09e78880ee5328485c1ceb4c375cea.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:19Z","receivedAt":"2016-09-11T10:54:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As we are slowly teaching the sequencer to perform the hard work for\nthe interactive rebase, we need to read files that were written by\nshell scripts.\n\nThese files typically contain a single line and are invariably ended\nby a line feed (and possibly a carriage return before that). Let's use\na helper to read such files and to remove the line ending.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 31 +++++++++++++++++++++++++++++++\n 1 file changed, 31 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 6c35fe8..086cd0b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -242,6 +242,37 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \treturn 0;\n }\n \n+/*\n+ * Reads a file that was presumably written by a shell script, i.e.\n+ * with an end-of-line marker that needs to be stripped.\n+ *\n+ * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n+ */\n+static int read_oneliner(struct strbuf *buf,\n+\tconst char *path, int skip_if_empty)\n+{\n+\tint orig_len = buf->len;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (strbuf_read_file(buf, path, 0) < 0) {\n+\t\twarning_errno(\"could not read '%s'\", path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n+\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n+\t\t\t--buf->len;\n+\t\tbuf->buf[buf->len] = '\\0';\n+\t}\n+\n+\tif (skip_if_empty && buf->len == orig_len)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static struct tree *empty_tree(void)\n {\n \treturn lookup_tree(EMPTY_TREE_SHA1_BIN);\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301646","messageId":"fa4ea9fdacaa91454361de66a5a6cd7f94f66518.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 15/25] sequencer: prepare for rebase -i's GPG settings","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:46Z","receivedAt":"2016-09-11T10:54:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The rebase command sports a `--gpg-sign` option that is heeded by the\ninteractive rebase.\n\nThis patch teaches the sequencer that trick, as part of the bigger\neffort to make the sequencer the work horse of the interactive rebase.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 42 +++++++++++++++++++++++++++++++++++++-----\n 1 file changed, 37 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 086cd0b..bf02565 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -15,6 +15,7 @@\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n #include \"argv-array.h\"\n+#include \"quote.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n  * being rebased.\n  */\n static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+/*\n+ * The following files are written by git-rebase just after parsing the\n+ * command-line (and are only consumed, not modified, by the sequencer).\n+ */\n+static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n \n /* We will introduce the 'interactive rebase' mode later */\n static inline int is_rebase_i(const struct replay_opts *opts)\n@@ -132,6 +138,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n+{\n+\tstatic struct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_reset(&buf);\n+\tif (opts->gpg_sign)\n+\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n+\treturn buf.buf;\n+}\n+\n void *sequencer_entrust(struct replay_opts *opts, void *to_free)\n {\n \tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n@@ -478,17 +494,20 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \n \tif (is_rebase_i(opts)) {\n \t\tenv = read_author_script();\n-\t\tif (!env)\n+\t\tif (!env) {\n+\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\n \t\t\treturn error(\"You have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit --amend %s\\n\\n\"\n \t\t\t\t\"If they are meant to go into a new commit, \"\n \t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit %s\\n\\n\"\n \t\t\t\t\"In both cases, once you're done, continue \"\n \t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\");\n+\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t}\n \t}\n \n \targv_array_init(&array);\n@@ -980,8 +999,21 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n-\tif (is_rebase_i(opts))\n+\tif (is_rebase_i(opts)) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n+\t\t\tif (!starts_with(buf.buf, \"-S\"))\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\telse {\n+\t\t\t\topts->gpg_sign = buf.buf + 2;\n+\t\t\t\tsequencer_entrust(opts,\n+\t\t\t\t\tstrbuf_detach(&buf, NULL));\n+\t\t\t}\n+\t\t}\n+\n \t\treturn 0;\n+\t}\n \n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301647","messageId":"eb2df2a784ab76dbe5c139e42c2c21f3c0484017.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 16/25] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:54:55Z","receivedAt":"2016-09-11T10:55:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In the upcoming commits, we will implement more and more of rebase\n-i's functionality. One particular feature of the commands to come is\nthat some of them allow editing the commit message while others don't,\ni.e. we cannot define in the replay_opts whether the commit message\nshould be edited or not.\n\nLet's add a new parameter to the sequencer_commit() function. Previously,\nit was the duty of the caller to ensure that the opts->edit setting\nindicates whether to let the user edit the commit message or not,\nindicating that it is an \"all or nothing\" setting, i.e. that the sequencer\nwants to let the user edit *all* commit message, or none at all. In the\nupcoming rebase -i mode, it will depend on the particular command that is\ncurrently executed, though.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n sequencer.h | 2 +-\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex bf02565..6e9732c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -485,7 +485,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty)\n+\t\t\t  int allow_empty, int edit)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -520,7 +520,7 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n-\tif (opts->edit)\n+\tif (edit)\n \t\targv_array_push(&array, \"-e\");\n \telse if (!opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n@@ -786,7 +786,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow);\n+\t\t\topts, allow, opts->edit);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex 16deb6c..7f5222f 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -54,7 +54,7 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty);\n+\t\t\t  int allow_empty, int edit);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301648","messageId":"68f995eaaad2448f5793f0030f96aa501b985ed5.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 17/25] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:02Z","receivedAt":"2016-09-11T10:55:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This teaches the sequencer_commit() function to take an argument that\nwill allow us to implement \"todo\" commands that need to amend the commit\nmessages (\"fixup\", \"squash\" and \"reword\").\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 ++++--\n sequencer.h | 2 +-\n 2 files changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 6e9732c..60b522e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -485,7 +485,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit)\n+\t\t\t  int allow_empty, int edit, int amend)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -514,6 +514,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n \n+\tif (amend)\n+\t\targv_array_push(&array, \"--amend\");\n \tif (opts->gpg_sign)\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n@@ -786,7 +788,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow, opts->edit);\n+\t\t\topts, allow, opts->edit, 0);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex 7f5222f..c45f5c4 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -54,7 +54,7 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit);\n+\t\t\t  int allow_empty, int edit, int amend);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301649","messageId":"773ba280e64c2dfabff0d6e6a0a0808482461677.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 18/25] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:33Z","receivedAt":"2016-09-11T10:55:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer_commit() function already knows how to amend commits, and\nwith this new option, it can also clean up commit messages (i.e. strip\nout commented lines). This is needed to implement rebase -i's 'fixup'\nand 'squash' commands as sequencer commands.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n sequencer.h |  3 ++-\n 2 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 60b522e..75772b8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -485,7 +485,8 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend)\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -522,9 +523,12 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (cleanup_commit_message)\n+\t\targv_array_push(&array, \"--cleanup=strip\");\n \tif (edit)\n \t\targv_array_push(&array, \"-e\");\n-\telse if (!opts->signoff && !opts->record_origin &&\n+\telse if (!cleanup_commit_message &&\n+\t\t !opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n \t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n@@ -788,7 +792,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\topts, allow, opts->edit, 0);\n+\t\t\topts, allow, opts->edit, 0, 0);\n \n leave:\n \tfree_message(commit, &msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex c45f5c4..688fff1 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -54,7 +54,8 @@ int sequencer_rollback(struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend);\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301650","messageId":"44c455710fd9c420a3f759d021c4864f3a83c97a.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 19/25] sequencer: remember do_recursive_merge()'s return value","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:41Z","receivedAt":"2016-09-11T10:55:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The return value of do_recursive_merge() may be positive (indicating merge\nconflicts), so let's OR later error conditions so as not to overwrite them\nwith 0.\n\nThis is not yet a problem, but preparing for the patches to come: we will\nteach the sequencer to do rebase -i's job.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 75772b8..7953a05 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -630,7 +630,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \tconst char *base_label, *next_label;\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n-\tint res, unborn = 0, allow;\n+\tint res = 0, unborn = 0, allow;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -741,7 +741,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \n \tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n-\t\tres = do_recursive_merge(base, next, base_label, next_label,\n+\t\tres |= do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n \t\t\treturn res;\n@@ -750,7 +750,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tstruct commit_list *common = NULL;\n \t\tstruct commit_list *remotes = NULL;\n \n-\t\tres = write_message(&msgbuf, git_path_merge_msg());\n+\t\tres |= write_message(&msgbuf, git_path_merge_msg());\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n@@ -787,11 +787,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \n \tallow = allow_empty(opts, commit);\n \tif (allow < 0) {\n-\t\tres = allow;\n+\t\tres |= allow;\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\tres |= sequencer_commit(opts->edit ?\n+\t\t\t\tNULL : git_path_merge_msg(),\n \t\t\topts, allow, opts->edit, 0, 0);\n \n leave:\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301651","messageId":"09e05e7ac23164625f2076ff06d2b034101878da.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:45Z","receivedAt":"2016-09-11T10:55:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Interactive rebase's scripts may be indented; we need to handle this\ncase, too, now that we prepare the sequencer to process interactive\nrebases.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 7953a05..5e5d113 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -875,6 +875,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tchar *end_of_object_name;\n \tint i, saved, status, padding;\n \n+\t/* left-trim */\n+\tbol += strspn(bol, \" \\t\");\n+\n \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n \t\t\titem->command = i;\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301652","messageId":"da2293aee439da2274e30304e2d1f097b9644e64.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 21/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:48Z","receivedAt":"2016-09-11T10:56:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The write_message() function safely writes an strbuf to a file.\nSometimes it is inconvenient to require an strbuf, though: the text to\nbe written may not be stored in a strbuf, or the strbuf should not be\nreleased after writing.\n\nLet's refactor \"safely writing string to a file\" into\nwrite_with_lock_file(), and make write_message() use it. The new\nfunction makes it easy to create new convenience function\nwrite_file_gently(); as some of the upcoming callers of this new\nfunction would want to append a newline character, add a flag for it in\nwrite_file_gently(), and thus in write_with_lock_file().\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 23 +++++++++++++++++++----\n 1 file changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5e5d113..aa949d4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -242,22 +242,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(struct strbuf *msgbuf, const char *filename)\n+static int write_with_lock_file(const char *filename,\n+\t\t\t\tconst void *buf, size_t len, int append_eol)\n {\n \tstatic struct lock_file msg_file;\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n-\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tstrbuf_release(msgbuf);\n+\tif (write_in_full(msg_fd, buf, len) < 0)\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n+\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n \tif (commit_lock_file(&msg_file) < 0)\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n \n \treturn 0;\n }\n \n+static int write_message(struct strbuf *msgbuf, const char *filename)\n+{\n+\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n+\tstrbuf_release(msgbuf);\n+\treturn res;\n+}\n+\n+static int write_file_gently(const char *filename,\n+\t\t\t     const char *text, int append_eol)\n+{\n+\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n+}\n+\n /*\n  * Reads a file that was presumably written by a shell script, i.e.\n  * with an end-of-line marker that needs to be stripped.\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301653","messageId":"d0066b1a8dc6d8d6d45161203cd5c08ef8f2216f.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 22/25] sequencer: remove overzealous assumption in rebase -i mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:51Z","receivedAt":"2016-09-11T10:56:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer was introduced to make the cherry-pick and revert\nfunctionality available as library function, with the original idea\nbeing to extend the sequencer to also implement the rebase -i\nfunctionality.\n\nThe test to ensure that all of the commands in the script are identical\nto the overall operation does not mesh well with that.\n\nTherefore let's disable the test in rebase -i mode.\n\nWhile at it, error out early if the \"instruction sheet\" (i.e. the todo\nscript) could not be parsed.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex aa949d4..5144245 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -963,7 +963,10 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n-\tif (!res) {\n+\tif (res)\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\n+\tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n \t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n \t\tint i;\n@@ -977,8 +980,6 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n \t}\n \n-\tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301654","messageId":"379463a47285b3e59fc4b0894fd74b939c399483.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 23/25] sequencer: mark action_name() for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:54Z","receivedAt":"2016-09-11T10:56:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The definition of this function goes back all the way to 043a449\n(sequencer: factor code out of revert builtin, 2012-01-11), long before a\nserious effort was made to translate all the error messages.\n\nIt is slightly out of the context of the current patch series (whose\npurpose it is to re-implement the performance critical parts of the\ninteractive rebase in C) to make the error messages in the sequencer\ntranslatable, but what the heck. We'll just do it while we're looking at\nthis part of the code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5144245..1e7f29e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -176,7 +176,7 @@ int sequencer_remove_state(struct replay_opts *opts)\n \n static const char *action_name(const struct replay_opts *opts)\n {\n-\treturn opts->action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\";\n+\treturn opts->action == REPLAY_REVERT ? N_(\"revert\") : N_(\"cherry-pick\");\n }\n \n struct commit_message {\n@@ -312,10 +312,10 @@ static struct tree *empty_tree(void)\n static int error_dirty_index(struct replay_opts *opts)\n {\n \tif (read_cache_unmerged())\n-\t\treturn error_resolve_conflict(action_name(opts));\n+\t\treturn error_resolve_conflict(_(action_name(opts)));\n \n \terror(_(\"Your local changes would be overwritten by %s.\"),\n-\t\taction_name(opts));\n+\t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n@@ -333,7 +333,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,\n \tif (checkout_fast_forward(from, to, 1))\n \t\treturn -1; /* the callee should have complained already */\n \n-\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), action_name(opts));\n+\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), _(action_name(opts)));\n \n \ttransaction = ref_transaction_begin(&err);\n \tif (!transaction ||\n@@ -409,7 +409,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \t    write_locked_index(&the_index, &index_lock, COMMIT_LOCK))\n \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n \t\treturn error(_(\"%s: Unable to write new index file\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \trollback_lock_file(&index_lock);\n \n \tif (opts->signoff)\n@@ -840,14 +840,14 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \tif (read_index_preload(&the_index, NULL) < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn error(_(\"git %s: failed to read the index\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \t}\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n \tif (the_index.cache_changed && index_fd >= 0) {\n \t\tif (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {\n \t\t\trollback_lock_file(&index_lock);\n \t\t\treturn error(_(\"git %s: failed to refresh the index\"),\n-\t\t\t\taction_name(opts));\n+\t\t\t\t_(action_name(opts)));\n \t\t}\n \t}\n \trollback_lock_file(&index_lock);\n-- \n2.10.0.windows.1.10.g803177d\n\n\n"},{"id":"301655","messageId":"db1816339ba9e259e929a45d644c33160f57c5bb.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 24/25] sequencer: quote filenames in error messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:55:57Z","receivedAt":"2016-09-11T10:56:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This makes the code consistent by fixing quite a couple of error messages.\n\nSuggested by Jakub Narębski.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 1e7f29e..465e018 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -255,7 +255,7 @@ static int write_with_lock_file(const char *filename,\n \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n \t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n \tif (commit_lock_file(&msg_file) < 0)\n-\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n \n \treturn 0;\n }\n@@ -955,16 +955,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n+\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read %s.\"), todo_file);\n+\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -1050,7 +1050,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: %s\"),\n+\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1093,7 +1093,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory %s\"),\n+\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1112,12 +1112,12 @@ static int save_head(const char *head)\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n+\t\treturn error_errno(_(\"Could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_head_file());\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1162,9 +1162,9 @@ int sequencer_rollback(struct replay_opts *opts)\n \t\treturn rollback_single_pick();\n \t}\n \tif (!f)\n-\t\treturn error_errno(_(\"cannot open %s\"), git_path_head_file());\n+\t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n \tif (strbuf_getline_lf(&buf, f)) {\n-\t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n+\t\terror(_(\"cannot read '%s': %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\n \t\tgoto fail;\n@@ -1203,7 +1203,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t\ttodo_list->buf.len - offset) < 0)\n \t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n \treturn 0;\n }\n \n-- \n2.10.0.windows.1.10.g803177d\n\n"},{"id":"301656","messageId":"8314699c144c258ca45094beef5953b612eb7f15.1473590966.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 25/25] sequencer: remove bogus hint for translators","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-11T10:56:00Z","receivedAt":"2016-09-11T10:56:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When translating error messages, we need to be careful *not* to translate\nthe todo commands such as \"pick\", \"reword\", etc because they are commands,\nand Git would not understand translated versions of those commands.\n\nTherefore, translating the commands in the error messages would simply be\nmisleading.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 2 --\n 1 file changed, 2 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 465e018..cdff0f1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -697,8 +697,6 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n \n \tif (parent && parse_commit(parent) < 0)\n-\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n-\t\t   \"cherry-pick\", the second %s a SHA1 */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n \t\t\tcommand_to_string(command),\n \t\t\toid_to_hex(&parent->object.oid));\n-- \n2.10.0.windows.1.10.g803177d\n"},{"id":"301677","messageId":"xmqqa8fe6mln.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"8314699c144c258ca45094beef5953b612eb7f15.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 25/25] sequencer: remove bogus hint for translators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T23:30:28Z","receivedAt":"2016-09-11T23:30:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> When translating error messages, we need to be careful *not* to translate\n> the todo commands such as \"pick\", \"reword\", etc because they are commands,\n> and Git would not understand translated versions of those commands.\n>\n> Therefore, translating the commands in the error messages would simply be\n> misleading.\n\nThis comes from b9c993e0 (\"i18n: git-revert literal \"me\" messages\",\n2011-02-22) where it said\n\nAuthor: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\n    i18n: git-revert literal \"me\" messages\n    \n    Translate messages that use the `me' variable. These are all error\n    messages referencing the command name, so the name shouldn't be\n    translated.\n    \n    Reported-by: Jonathan Nieder <jrnieder@gmail.com>\n    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nThis looks like a positive attempt to remind translators that their\ntranslation must flow with these literal command names that will not\nget translated in place, not a bogus hint at all, at least to me.\n\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 2 --\n>  1 file changed, 2 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 465e018..cdff0f1 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -697,8 +697,6 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n>  \n>  \tif (parent && parse_commit(parent) < 0)\n> -\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n> -\t\t   \"cherry-pick\", the second %s a SHA1 */\n>  \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n>  \t\t\tcommand_to_string(command),\n>  \t\t\toid_to_hex(&parent->object.oid));\n"},{"id":"301678","messageId":"xmqq60q26mfw.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"db1816339ba9e259e929a45d644c33160f57c5bb.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 24/25] sequencer: quote filenames in error messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T23:33:55Z","receivedAt":"2016-09-11T23:34:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This makes the code consistent by fixing quite a couple of error messages.\n\nLooks OK.  While at it, we may want another one to downcase the\nfirst word, perhaps?\n\nThese may not be messages added by your series and can be left\noutside this series, but I have to point out that\n\n    if (commit_lock_file(&msg_file) < 0)\n        return error(_(\"Error wrapping up '%s'.\"), filename);\n\nresults in \"error: Error wrapping up\", which sounds quite funny.\n\n\"failed to finalize\" or something would flow a bit better, I'd say.\n\n> diff --git a/sequencer.c b/sequencer.c\n> index 1e7f29e..465e018 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -255,7 +255,7 @@ static int write_with_lock_file(const char *filename,\n>  \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n>  \t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n>  \tif (commit_lock_file(&msg_file) < 0)\n> -\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n> +\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n>  \n>  \treturn 0;\n>  }\n"},{"id":"301679","messageId":"xmqq1t0q6mds.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"d0066b1a8dc6d8d6d45161203cd5c08ef8f2216f.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 22/25] sequencer: remove overzealous assumption in rebase -i mode","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T23:35:11Z","receivedAt":"2016-09-11T23:35:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> While at it, error out early if the \"instruction sheet\" (i.e. the todo\n> script) could not be parsed.\n\nSounds good.\n"},{"id":"301680","messageId":"xmqqwpii57oe.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"da2293aee439da2274e30304e2d1f097b9644e64.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 21/25] sequencer: refactor write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T23:38:09Z","receivedAt":"2016-09-11T23:38:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The write_message() function safely writes an strbuf to a file.\n> Sometimes it is inconvenient to require an strbuf, though: the text to\n> be written may not be stored in a strbuf, or the strbuf should not be\n> released after writing.\n>\n> Let's refactor \"safely writing string to a file\" into\n> write_with_lock_file(), and make write_message() use it. The new\n> function makes it easy to create new convenience function\n> write_file_gently(); as some of the upcoming callers of this new\n> function would want to append a newline character, add a flag for it in\n> write_file_gently(), and thus in write_with_lock_file().\n\nMakes sense.  As an abstraction, \"give me strbuf for my sole use,\nand I'll trash its contents when I am done\" feels like a horrible\nhelper interface; perhaps that was overly aggressively refactored by\nnoticing that then-current callers all released the strbuf, but\nstill feels wrong.\n\nAnd this makes the underlying helper a lot more useful.\n\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 23 +++++++++++++++++++----\n>  1 file changed, 19 insertions(+), 4 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 5e5d113..aa949d4 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -242,22 +242,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n>  \t}\n>  }\n>  \n> -static int write_message(struct strbuf *msgbuf, const char *filename)\n> +static int write_with_lock_file(const char *filename,\n> +\t\t\t\tconst void *buf, size_t len, int append_eol)\n>  {\n>  \tstatic struct lock_file msg_file;\n>  \n>  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n>  \tif (msg_fd < 0)\n>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n> -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n> -\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n> -\tstrbuf_release(msgbuf);\n> +\tif (write_in_full(msg_fd, buf, len) < 0)\n> +\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n> +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n> +\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n>  \tif (commit_lock_file(&msg_file) < 0)\n>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>  \n>  \treturn 0;\n>  }\n>  \n> +static int write_message(struct strbuf *msgbuf, const char *filename)\n> +{\n> +\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n> +\tstrbuf_release(msgbuf);\n> +\treturn res;\n> +}\n> +\n> +static int write_file_gently(const char *filename,\n> +\t\t\t     const char *text, int append_eol)\n> +{\n> +\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n> +}\n> +\n>  /*\n>   * Reads a file that was presumably written by a shell script, i.e.\n>   * with an end-of-line marker that needs to be stripped.\n"},{"id":"301681","messageId":"xmqqsht657ls.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"09e05e7ac23164625f2076ff06d2b034101878da.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-11T23:39:43Z","receivedAt":"2016-09-11T23:39:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Interactive rebase's scripts may be indented; we need to handle this\n> case, too, now that we prepare the sequencer to process interactive\n> rebases.\n\nHmph, have we ever given the sequencer instructions indented to the\nuser to edit?  I do not offhand see why we want to be lenient here,\nespecially only to the left.\n\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 3 +++\n>  1 file changed, 3 insertions(+)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 7953a05..5e5d113 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -875,6 +875,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n>  \tchar *end_of_object_name;\n>  \tint i, saved, status, padding;\n>  \n> +\t/* left-trim */\n> +\tbol += strspn(bol, \" \\t\");\n> +\n>  \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n>  \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n>  \t\t\titem->command = i;\n"},{"id":"301693","messageId":"alpine.DEB.2.20.1609121019290.129229@virtualbox","threadId":"43954","inReplyTo":"xmqqsht657ls.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-12T08:23:28Z","receivedAt":"2016-09-12T08:23:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 11 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Interactive rebase's scripts may be indented; we need to handle this\n> > case, too, now that we prepare the sequencer to process interactive\n> > rebases.\n> \n> Hmph, have we ever given the sequencer instructions indented to the\n> user to edit?\n\nNo.\n\nWe also never provide the user with an indented todo script in the\nsequencer. Yet we still parse it. Because Postel's Law.\n\n> I do not offhand see why we want to be lenient here,\n> especially only to the left.\n\nPostel's Law.\n\nWe do not care about the right: that's only comments (onelines, for the\nusers' pleasure).\n\nCiao,\nDscho\n"},{"id":"301694","messageId":"e21e3391-bfc3-68b8-8eaf-0e15e5a436c5@kdbg.org","threadId":"43954","inReplyTo":"da2293aee439da2274e30304e2d1f097b9644e64.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 21/25] sequencer: refactor write_message()","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-09-12T08:35:22Z","receivedAt":"2016-09-12T08:35:31Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 11.09.2016 um 12:55 schrieb Johannes Schindelin:\n> -static int write_message(struct strbuf *msgbuf, const char *filename)\n> +static int write_with_lock_file(const char *filename,\n> +\t\t\t\tconst void *buf, size_t len, int append_eol)\n>  {\n>  \tstatic struct lock_file msg_file;\n>\n>  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n>  \tif (msg_fd < 0)\n>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n> -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n> -\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n> -\tstrbuf_release(msgbuf);\n> +\tif (write_in_full(msg_fd, buf, len) < 0)\n> +\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n> +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n> +\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n>  \tif (commit_lock_file(&msg_file) < 0)\n>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>\n>  \treturn 0;\n>  }\n\nThe two error paths in the added lines should both\n\n\t\trollback_lock_file(&msg_file);\n\n, I think. But I do notice that this is not exactly new, so...\n\n-- Hannes\n\n"},{"id":"301724","messageId":"xmqqr38p3z1i.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609121019290.129229@virtualbox","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T15:42:17Z","receivedAt":"2016-09-12T15:42:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I do not offhand see why we want to be lenient here,\n>> especially only to the left.\n>\n> Postel's Law.\n\nHow would that compare/relate to yagni, though?\n"},{"id":"301750","messageId":"xmqqzinc295y.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"942aa559a0af9b52e079c5c78fa313f49b87d50d.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T19:46:33Z","receivedAt":"2016-09-12T19:46:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> like a one-shot command when it reads its configuration: memory is\n> allocated and released only when the command exits.\n>\n> This is kind of okay for git-cherry-pick, which *is* a one-shot\n> command. All the work to make the sequencer its work horse was\n> done to allow using the functionality as a library function, though,\n> including proper clean-up after use.\n>\n> This patch introduces an API to pass the responsibility of releasing\n> certain memory to the sequencer. Example:\n>\n> \tconst char *label =\n> \t\tsequencer_entrust(opts, xstrfmt(\"From: %s\", email));\n\nI thought we (not just me) were already pretty clear during the last\nround of review that we will not want this entrust() thing.\n\n\n\n"},{"id":"301751","messageId":"xmqqvay02959.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"666493d3f166d839deb817042ed7d1636b11f19e.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 01/25] sequencer: use static initializers for replay_opts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T19:46:58Z","receivedAt":"2016-09-12T19:47:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This change is not completely faithful: instead of initializing all fields\n> to 0, we choose to initialize command and subcommand to -1 (instead of\n> defaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\n> it makes no difference at all, but future-proofs the code to require\n> explicit assignments for both fields.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nOK.\n"},{"id":"301752","messageId":"xmqqr38o292v.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"5c52dcbff8b21b24a360d6f5bd2710fe1139eb4a.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 02/25] sequencer: use memoized sequencer directory path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T19:48:24Z","receivedAt":"2016-09-12T19:48:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/commit.c |  2 +-\n>  sequencer.c      | 11 ++++++-----\n>  sequencer.h      |  5 +----\n>  3 files changed, 8 insertions(+), 10 deletions(-)\n\nOK.  It's nice to see code reduction.\n\n> -#define SEQ_DIR\t\t\"sequencer\"\n> -#define SEQ_HEAD_FILE\t\"sequencer/head\"\n> -#define SEQ_TODO_FILE\t\"sequencer/todo\"\n> -#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n> +const char *git_path_seq_dir(void);\n\n"},{"id":"301753","messageId":"xmqqmvjc291s.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"2587881a45d5a81cda4b2eb40e2d7d8d55b7931c.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 03/25] sequencer: avoid unnecessary indirection","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T19:49:03Z","receivedAt":"2016-09-12T19:49:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> -static int read_populate_opts(struct replay_opts **opts)\n> +static int read_populate_opts(struct replay_opts *opts)\n>  {\n>  \tif (!file_exists(git_path_opts_file()))\n>  \t\treturn 0;\n> @@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n>  \t * about this case, though, because we wrote that file ourselves, so we\n>  \t * are pretty certain that it is syntactically correct.\n>  \t */\n> -\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n> +\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n>  \t\treturn error(_(\"Malformed options sheet: %s\"),\n>  \t\t\tgit_path_opts_file());\n>  \treturn 0;\n> @@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n>  \n>  \tif (!file_exists(git_path_todo_file()))\n>  \t\treturn continue_single_pick();\n> -\tif (read_populate_opts(&opts) ||\n> +\tif (read_populate_opts(opts) ||\n>  \t\t\tread_populate_todo(&todo_list, opts))\n>  \t\treturn -1;\n\nGood!\n"},{"id":"301755","messageId":"xmqqinu028tx.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"d6b92cd7aa56ceb515c50467a0e6030401e2e1bc.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T19:53:46Z","receivedAt":"2016-09-12T19:53:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +static const char *get_dir(const struct replay_opts *opts)\n> +{\n> +\treturn git_path_seq_dir();\n> +}\n\nPresumably this is what \"In a couple of commits\" meant, i.e. opts\nwill be used soonish.\n\n> -static void remove_sequencer_state(void)\n> +static void remove_sequencer_state(const struct replay_opts *opts)\n>  {\n> -\tstruct strbuf seq_dir = STRBUF_INIT;\n> +\tstruct strbuf dir = STRBUF_INIT;\n>  \n> -\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n> -\tremove_dir_recursively(&seq_dir, 0);\n> -\tstrbuf_release(&seq_dir);\n> +\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n> +\tremove_dir_recursively(&dir, 0);\n> +\tstrbuf_release(&dir);\n>  }\n\nAs long as \"who called the sequencer\" is the only thing that\ndetermines where the state is kept, this should work fine, I would\nthink.  I wondered that it would introduce a chicken-and-egg problem\nif we had to support \"git sequencer --clear-state\" command ;-) but\nthat is not the case.\n\nGood.\n"},{"id":"301769","messageId":"xmqqh99kzua9.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"44c455710fd9c420a3f759d021c4864f3a83c97a.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 19/25] sequencer: remember do_recursive_merge()'s return value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T21:23:58Z","receivedAt":"2016-09-12T21:24:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The return value of do_recursive_merge() may be positive (indicating merge\n> conflicts), so let's OR later error conditions so as not to overwrite them\n> with 0.\n\nAre the untold assumptions as follows?\n\n - The caller wants to act on positive (not quite an error), zero\n   (success) or negative (error);\n\n - do_recursive_merge() can return positive (success with\n   reservation), zero or negative, and the call to it would return\n   immediately if it got negative;\n\n - all other functions that come later may return either zero or negative, and \n   never positive;\n\n - Hence the caller can be assured that \"res\" being positive can\n   only mean do_recursive_merge() succeeded with reservation and\n   everything else succeeded.\n\nThis can be extended if the only thing the caller cares about is\npositive/zero/negative and it does not care what exact positive\nvalue it gets--in such a case, we can loosen the condition on the\nreturn values from other functions whose return values are OR'ed\ntogether; they may also return positive to signal the same \"not\nquite an error\", i.e. updating the latter two points to\n\n - all other functions that come later can return positive (success\n   with reservation), zero or negative.\n\n - Hence the caller can be assured that \"res\" being positive can\n   mean nobody failed with negative return, but it is not an\n   unconditional success, which is signalled by value \"res\" being\n   0.\n\nI cannot quite tell which is the case, especially what is planned in\nthe future.  The proposed log message is a good place to explain the\nfuture course this code will take.\n\n> This is not yet a problem, but preparing for the patches to come: we will\n> teach the sequencer to do rebase -i's job.\n\nThanks.\n"},{"id":"301770","messageId":"xmqqd1k8ztv7.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"773ba280e64c2dfabff0d6e6a0a0808482461677.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 18/25] sequencer: support cleaning up commit messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T21:33:00Z","receivedAt":"2016-09-12T21:33:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> @@ -788,7 +792,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\topts, allow, opts->edit, 0);\n> +\t\t\topts, allow, opts->edit, 0, 0);\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n\nSo the existing caller did not ask to cleanup\n\n\n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit, int amend)\n> +\t\t\t  int allow_empty, int edit, int amend,\n> +\t\t\t  int cleanup_commit_message)\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -522,9 +523,12 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\targv_array_push(&array, \"-s\");\n>  \tif (defmsg)\n>  \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n> +\tif (cleanup_commit_message)\n> +\t\targv_array_push(&array, \"--cleanup=strip\");\n>  \tif (edit)\n>  \t\targv_array_push(&array, \"-e\");\n> -\telse if (!opts->signoff && !opts->record_origin &&\n> +\telse if (!cleanup_commit_message &&\n> +\t\t !opts->signoff && !opts->record_origin &&\n>  \t\t git_config_get_value(\"commit.cleanup\", &value))\n>  \t\targv_array_push(&array, \"--cleanup=verbatim\");\n\nWhich is consistent with this change.  This is a no-op enhancement\nfor existing callers and makes new callers to ask for cleaning up.\n\nWe will see if a hardcoded \"--cleanup=strip\" is sufficient when we\nsee new callers (we _know_ it would be sufficient for the first new\ncaller by definition ;-).\n\nMakes sense.  Thanks.\n"},{"id":"301771","messageId":"xmqq8tuwztpd.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"68f995eaaad2448f5793f0030f96aa501b985ed5.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 17/25] sequencer: support amending commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-12T21:36:30Z","receivedAt":"2016-09-12T21:36:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This teaches the sequencer_commit() function to take an argument that\n> will allow us to implement \"todo\" commands that need to amend the commit\n> messages (\"fixup\", \"squash\" and \"reword\").\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 ++++--\n>  sequencer.h | 2 +-\n>  2 files changed, 5 insertions(+), 3 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 6e9732c..60b522e 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -485,7 +485,7 @@ static char **read_author_script(void)\n>   * author metadata.\n>   */\n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit)\n> +\t\t\t  int allow_empty, int edit, int amend)\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -514,6 +514,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n>  \targv_array_push(&array, \"commit\");\n>  \targv_array_push(&array, \"-n\");\n>  \n> +\tif (amend)\n> +\t\targv_array_push(&array, \"--amend\");\n>  \tif (opts->gpg_sign)\n>  \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n>  \tif (opts->signoff)\n> @@ -786,7 +788,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\topts, allow, opts->edit);\n> +\t\t\topts, allow, opts->edit, 0);\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n\nHmm, this is more about a comment on 18/25, but I suspect that\n\"amend\" or any opportunity given to the user to futz with the\ncontents in the editor invites a wish for the result to be treated\nwith stripspace.\n\nNo existing callers use \"amend\" to call this function, so there is\nno change in behaviour, but at the same time, we do not have enough\ninformation to see if 'amend' should by default toggle cleanup.\n\n\n> diff --git a/sequencer.h b/sequencer.h\n> index 7f5222f..c45f5c4 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -54,7 +54,7 @@ int sequencer_rollback(struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit);\n> +\t\t\t  int allow_empty, int edit, int amend);\n>  \n>  extern const char sign_off_header[];\n"},{"id":"302000","messageId":"xmqqk2ednfdl.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"955727a7cf5bd64f1c1106b394095d5449a4a2dc.1473590966.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 10/25] sequencer: get rid of the subcommand field","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-15T19:15:50Z","receivedAt":"2016-09-15T19:16:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The subcommands are used exactly once, at the very beginning of\n> sequencer_pick_revisions(), to determine what to do. This is an\n> unnecessary level of indirection: we can simply call the correct\n> function to begin with. So let's do that.\n\nMakes sense.  And the diffstat is also pleasant to the eyes.\n\n>  builtin/revert.c | 36 ++++++++++++++++--------------------\n>  sequencer.c      | 35 +++++++++++------------------------\n>  sequencer.h      | 13 ++++---------\n>  3 files changed, 31 insertions(+), 53 deletions(-)\n"},{"id":"302001","messageId":"xmqqfup1nf3u.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"e21e3391-bfc3-68b8-8eaf-0e15e5a436c5@kdbg.org","subject":"Re: [PATCH v2 21/25] sequencer: refactor write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-15T19:21:41Z","receivedAt":"2016-09-15T19:21:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 11.09.2016 um 12:55 schrieb Johannes Schindelin:\n>> -static int write_message(struct strbuf *msgbuf, const char *filename)\n>> +static int write_with_lock_file(const char *filename,\n>> +\t\t\t\tconst void *buf, size_t len, int append_eol)\n>>  {\n>>  \tstatic struct lock_file msg_file;\n>>\n>>  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n>>  \tif (msg_fd < 0)\n>>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n>> -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n>> -\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n>> -\tstrbuf_release(msgbuf);\n>> +\tif (write_in_full(msg_fd, buf, len) < 0)\n>> +\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n>> +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n>> +\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n>>  \tif (commit_lock_file(&msg_file) < 0)\n>>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>>\n>>  \treturn 0;\n>>  }\n>\n> The two error paths in the added lines should both\n>\n> \t\trollback_lock_file(&msg_file);\n>\n> , I think. But I do notice that this is not exactly new, so...\n\nIt may not be new for this step, but overall the series is aiming to\nlibify the stuff, so we should fix fd and lockfile leaks like this\nas we notice them.\n\nThanks.\n"},{"id":"302267","messageId":"f7fe3f15-664e-61a5-6101-30ed4946c107@gmail.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1609111027330.129229@virtualbox","subject":"Re: Git garden shears, was Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-21T13:17:37Z","receivedAt":"2016-09-21T13:18:06Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Hello Dscho,\n\nW dniu 11.09.2016 o 10:33, Johannes Schindelin napisał: \n> On Fri, 9 Sep 2016, Jakub Narębski wrote:\n[...]\n\n>> When preserving merges, there are (as far as I understand it), two\n>> problems:\n>>  - what it means to preserve changes (which change to pick,\n>>    that is what is the mainline changes rebase is re-applying)\n>>  - what are parents of the merge commit (at least one parent\n>>    would be usually rewritten)\n>>\n>> Maybe the internal (and perhaps also user-visible) representation\n>> of merge in instruction sheet could use the notation of filter-branch,\n>> that is 'map(<sha-1>)'... it could also imply the mainline.\n>>\n>> That is the instruction in the internal instruction sheet could\n>> look like this:\n>>\n>>   merge -m 1 map(2fd4e1c6...) da39a3ee... \\t Merge 'foo' into master  \n>>\n>>\n>> Note that it has nothing to do with this series!\n> \n> Right. But I did solve that already. In the Git garden shears [*1*]\n> (essentially my New And Improved attempt at recreating branch structures\n> while rebasing), I generate and process scripts like this:\n> \n> \tmark onto\n> \n> \t# Branch: super-cool-feature\n> \trewind onto\n> \tpick 00001 feature\n> \tpick 00002 documentation\n> \tmark super-cool-feature\n> \n> \t# Branch: typo-fix\n> \trewind onto\n> \tpick 0000a fix a tyop\n\nThere probably should be there\n\n \tmark typo-fix\n\n> \n> \trewind onto\n> \tmerge -C cafebabe super-cool-feature\n> \tmerge -C babecafe typo-fix\n> \n> \tcleanup super-cool-feature typo-fix\n> \n> Of course this will change a little, still, once I get around to implement\n> this on top of the rebase--helper.\n\nDo I understand it correctly that it is user-visible instruction sheet, and\nnot the internal instruction sheet for sequencer?  This looks very nice\nand is well readable.\n\nI guess that it needs to be pre-populated by Git based on topology of the\nbranch being rebased.\n\nAs I see, there are three basic topologies of non-linear branch to be\nrebased; all else is combination of thereof, or derivative:\n\n1. Merge commit without branching point, that is we need to go\n   from the following situation\n\n   *---*---*---#---o---o---o        <-- old base\n               \\\\\n                \\\\=a===b===M===c    <-- branch being rebased\n                          /\n         ...---x---x---x-/          <-- side branch\n\n  to the following:\n\n   *---*---*---#---o---o---o        \n                            \\\n                             \\-a'--b'--M'--c' \n                                      /\n         ...---x---x---x-------------/          \n\nI think this case is the only one supported by `--preserve-merges`,\nbut I may be mistaken - I never had the need to use this feature IRL.\n\n2. Branching point without accompanying merge commit, or in other words\n   rebasing many branches tied together; a shrub if you will.  That is,\n   we want to go from the following situation:\n\n   *---*---*---#---o---o---o           <-- old base\n               \\\n                \\--a---b---c           <-- branch being rebased\n                        \\\n                         \\-1           <-- dependent branch\n\n   to the following one:\n\n   *---*---*---#---o---o---o\n                            \\\n                             \\--a'--b'--c'\n                                     \\\n                                      \\-1'\n\nI don't think Git supports something like that out of the box, but it\nis not hard to create something like that \"by hand\". It is not much\nof a problem... unless you forget to rebase the second dependent branch.\n\n3. Branching point with merge point, that is subbranch created and\n   merged - an \"eye\" (it is not a loop in DAG):\n\n   *---*---*---#---o---o---o             <-- old base\n               \\\n                \\--a---b---c---M---d     <-- branch being rebased\n                    \\         /\n                     \\-1---2-/         [ <-- possibly a branch ]\n\n   All edges are directed edges, with arrows pointing from right to\n   left; that is  *---*  is really  *<---*\n\n   The expected result is:\n\n   *---*---*---#---o---o---o\n                            \\\n                             \\--a'--b'--c'--M'--d'\n                                 \\         /\n                                  \\-1'--2'/\n\nI guess that is the main purpose of your git-garden-shears script,\nisn't it?\n\n> \n> For example, I am not so hot about the \"merge -C ...\" syntax. I'll\n> probably split that into a \"remerge <SHA-1> <mark>\" and a new \"merge\n> <mark>\" command (the latter asking interactively for the merge commit\n> message).\n\nThere is also an additional complication in that merge commit message\nmay be *partially* automatically generated. First there is the subject\ngenerated by 'git merge' (\"Merge branch 'foo'\") or 'git pull <URL>'.\nIt might have been translated, or extended.  Second there is a place\nfor branch cover letter. Third, subject to merge.log / merge.summary\nthere is a shortlog.\n\nFrom those shortlog should be surely updated to correspond to the\npost-rebase state.  The first line could be used to pre-populate\nmark lines, but during merge it should be, I think, updated to the\nnew name of internal branch if it was changed.\n\n\nAs to 'merge -C <sha1> <marker>' vs 'remerge <sha1> <marker>',\nI don't have specified opinion.  It would be nice to have one\ncharacter shortcuts for insn sheet instructions, to which\n'm -C <sha1> <marker>' is more amendable... \n\n> \n> And also: the cleanup stage should not be necessary, as the \"mark\"\n> commands can accumulate the known marks into a file in the state\n> directory.\n> \n> But you get the idea.\n\nRight. No need to make user do something that computer can easily\nand without errors do.\n\n> \n> No :1 or some such. That's machine readable. But it's utter nonsense for\n> user-facing UIs.\n\nOf course. It's all right for machine-facing instructions, like the\n'todo' file for the sequencer, or for git-fast-import stream...\n\n> \n> Ciao,\n> Dscho\n> \n> Footnote *1*:\n> https://github.com/git-for-windows/build-extra/blob/master/shears.sh\n \nP.S. I wonder if git-imerge[2] requires for integrated branches to have\nboth linear history for it to work.\n\n[2]: https://github.com/mhagger/git-imerge\n     http://softwareswirl.blogspot.com/2013/05/git-imerge-practical-introduction.html\n     https://www.youtube.com/watch?v=FMZ2_-Ny_zc\n\nBest,\n-- \nJakub Narębski\n"},{"id":"302528","messageId":"alpine.DEB.2.20.1609251950300.129229@virtualbox","threadId":"43954","inReplyTo":"f7fe3f15-664e-61a5-6101-30ed4946c107@gmail.com","subject":"Re: Git garden shears, was Re: [PATCH 13/22] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-09-25T18:16:19Z","receivedAt":"2016-09-25T18:16:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Kuba,\n\nOn Wed, 21 Sep 2016, Jakub Narębski wrote:\n\n> W dniu 11.09.2016 o 10:33, Johannes Schindelin napisał: \n> > On Fri, 9 Sep 2016, Jakub Narębski wrote:\n> [...]\n> \n> >> When preserving merges, there are (as far as I understand it), two\n> >> problems:\n> >>  - what it means to preserve changes (which change to pick,\n> >>    that is what is the mainline changes rebase is re-applying)\n> >>  - what are parents of the merge commit (at least one parent\n> >>    would be usually rewritten)\n> >>\n> >> Maybe the internal (and perhaps also user-visible) representation\n> >> of merge in instruction sheet could use the notation of filter-branch,\n> >> that is 'map(<sha-1>)'... it could also imply the mainline.\n> >>\n> >> That is the instruction in the internal instruction sheet could\n> >> look like this:\n> >>\n> >>   merge -m 1 map(2fd4e1c6...) da39a3ee... \\t Merge 'foo' into master  \n> >>\n> >>\n> >> Note that it has nothing to do with this series!\n> > \n> > Right. But I did solve that already. In the Git garden shears [*1*]\n> > (essentially my New And Improved attempt at recreating branch structures\n> > while rebasing), I generate and process scripts like this:\n> > \n> > \tmark onto\n> > \n> > \t# Branch: super-cool-feature\n> > \trewind onto\n> > \tpick 00001 feature\n> > \tpick 00002 documentation\n> > \tmark super-cool-feature\n> > \n> > \t# Branch: typo-fix\n> > \trewind onto\n> > \tpick 0000a fix a tyop\n> \n> There probably should be there\n> \n>  \tmark typo-fix\n\nCorrect. Sorry for the omission.\n\n> > \trewind onto\n> > \tmerge -C cafebabe super-cool-feature\n> > \tmerge -C babecafe typo-fix\n> > \n> > \tcleanup super-cool-feature typo-fix\n> > \n> > Of course this will change a little, still, once I get around to implement\n> > this on top of the rebase--helper.\n> \n> Do I understand it correctly that it is user-visible instruction sheet, and\n> not the internal instruction sheet for sequencer?  This looks very nice\n> and is well readable.\n\nIt is intended as that.\n\nCurrently I need a little trickery to make this work, as rebase -i does\nnot understand rewind nor merge. The trick is to re-use the shears.sh\nscript as editor that then populates the edit script, calls the real\neditor, and then installs a temporary alias that gets called for all\ncustom commands via exec (turning e.g. \"rewind abc\" into \"exec git .r\nrewind abc\").\n\nThe temporary alias point back to the shears script, too, of course.\n\nIn the end, I hope to teach the sequencer a variant of this dialect, as\nwell as the trick to generate such edit scripts.\n\n> I guess that it needs to be pre-populated by Git based on topology of the\n> branch being rebased.\n\nYes. The shears.sh script is in charge of that, and it has to perform a\ncouple of Git calls to do so.\n\n> As I see, there are three basic topologies of non-linear branch to be\n> rebased; all else is combination of thereof, or derivative:\n> \n> 1. Merge commit without branching point, that is we need to go\n>    from the following situation\n> \n>    *---*---*---#---o---o---o        <-- old base\n>                \\\\\n>                 \\\\=a===b===M===c    <-- branch being rebased\n>                           /\n>          ...---x---x---x-/          <-- side branch\n> \n>   to the following:\n> \n>    *---*---*---#---o---o---o        \n>                             \\\n>                              \\-a'--b'--M'--c' \n>                                       /\n>          ...---x---x---x-------------/          \n\nIn other words: rebasing a merge commit merging non-rebased commits.\n\nThis is not yet supported by the shears script, as it would require logic\nthat is not only slow in shell script, but also convoluted. IOW this\nfeature waits for the sequencer to know how to run regular rebase -i\nalready.\n\n> I think this case is the only one supported by `--preserve-merges`,\n> but I may be mistaken - I never had the need to use this feature IRL.\n\nNo, -p would handle merges of non-rebased commits as well as merges of\nto-be-rebased commits.\n\n> 2. Branching point without accompanying merge commit, or in other words\n>    rebasing many branches tied together; a shrub if you will.  That is,\n>    we want to go from the following situation:\n> \n>    *---*---*---#---o---o---o           <-- old base\n>                \\\n>                 \\--a---b---c           <-- branch being rebased\n>                         \\\n>                          \\-1           <-- dependent branch\n> \n>    to the following one:\n> \n>    *---*---*---#---o---o---o\n>                             \\\n>                              \\--a'--b'--c'\n>                                      \\\n>                                       \\-1'\n\nThis is outside the scope of rebase -i (and of the shears), as you are\ntalking about *parallel* rebases. I don't do that, nor does rebase -i,\nrebase -p nor the shears.\n\n> I don't think Git supports something like that out of the box, but it\n> is not hard to create something like that \"by hand\". It is not much\n> of a problem... unless you forget to rebase the second dependent branch.\n\nThe safer thing to do, of course, is to merge all those tips back into the\nbranch you then rebase in one go.\n\n> 3. Branching point with merge point, that is subbranch created and\n>    merged - an \"eye\" (it is not a loop in DAG):\n> \n>    *---*---*---#---o---o---o             <-- old base\n>                \\\n>                 \\--a---b---c---M---d     <-- branch being rebased\n>                     \\         /\n>                      \\-1---2-/         [ <-- possibly a branch ]\n> \n>    All edges are directed edges, with arrows pointing from right to\n>    left; that is  *---*  is really  *<---*\n> \n>    The expected result is:\n> \n>    *---*---*---#---o---o---o\n>                             \\\n>                              \\--a'--b'--c'--M'--d'\n>                                  \\         /\n>                                   \\-1'--2'/\n> \n> I guess that is the main purpose of your git-garden-shears script,\n> isn't it?\n\nYes.\n\n> > For example, I am not so hot about the \"merge -C ...\" syntax. I'll\n> > probably split that into a \"remerge <SHA-1> <mark>\" and a new \"merge\n> > <mark>\" command (the latter asking interactively for the merge commit\n> > message).\n> \n> There is also an additional complication in that merge commit message\n> may be *partially* automatically generated. First there is the subject\n> generated by 'git merge' (\"Merge branch 'foo'\") or 'git pull <URL>'.\n> It might have been translated, or extended.  Second there is a place\n> for branch cover letter. Third, subject to merge.log / merge.summary\n> there is a shortlog.\n\nTrue. The current shears will simply use the original commit message\nverbatim. And I think it would be wise to keep this behaviour until the\nsequencer knows how to recreate merges.\n\nOnce that happens, I cordially invite you to implement any merge commit\nmessage munging mode your heart desires, on top of the straight port of\nthe shears.\n\n> From those shortlog should be surely updated to correspond to the\n> post-rebase state.  The first line could be used to pre-populate\n> mark lines, but during merge it should be, I think, updated to the\n> new name of internal branch if it was changed.\n\nSurely. Or not so surely. Too unsurely, for sure, to be discussed without\na dedicated patch series submitted by a dedicated person requiring that\nfeature.\n\n> As to 'merge -C <sha1> <marker>' vs 'remerge <sha1> <marker>',\n> I don't have specified opinion.  It would be nice to have one\n> character shortcuts for insn sheet instructions, to which\n> 'm -C <sha1> <marker>' is more amendable... \n\nI am pretty certain that you will find yourself disagreeing with that\nstatement once you used the shears for a while.\n\nI use it for over a year now, and I *never* had to type any \"merge -C\"\ncommand (i.e. the command I would call \"remerge\"). The reason is that you\nsimply move those generated lines, and that there is no scenario I\nencountered where you will want to insert a merge manually: you simply\nmerge all you want *before* or *after* rebasing.\n\nAs to \"merge <marker>\": those are quite common, in particular when\nsplitting patch series into parts.\n\n> > No :1 or some such. That's machine readable. But it's utter nonsense for\n> > user-facing UIs.\n> \n> Of course. It's all right for machine-facing instructions, like the\n> 'todo' file for the sequencer, or for git-fast-import stream...\n\nThe 'todo' file for the sequencer *should* be human-friendly. There is no\nreason not to make it so, in particular when you can simply reuse the refs\nmachinery for marks, and when it facilitates debugging (and I can testify\nto that: it does, oh yeah, it does...).\n\nCiao,\nDscho"},{"id":"303353","messageId":"alpine.DEB.2.20.1610051338530.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqzinc295y.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-05T11:41:46Z","receivedAt":"2016-10-05T11:41:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 12 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> > like a one-shot command when it reads its configuration: memory is\n> > allocated and released only when the command exits.\n> >\n> > This is kind of okay for git-cherry-pick, which *is* a one-shot\n> > command. All the work to make the sequencer its work horse was\n> > done to allow using the functionality as a library function, though,\n> > including proper clean-up after use.\n> >\n> > This patch introduces an API to pass the responsibility of releasing\n> > certain memory to the sequencer. Example:\n> >\n> > \tconst char *label =\n> > \t\tsequencer_entrust(opts, xstrfmt(\"From: %s\", email));\n> \n> I thought we (not just me) were already pretty clear during the last\n> round of review that we will not want this entrust() thing.\n\nThat does not match my understanding.\n\nThe problem is that we are building functionality for libgit.a, not merely\nfor a builtin that we know will simply exit() and take all allocated\nmemory with it.\n\nThe additional problem is that the sequencer was *already* meant for\nlibgit.a, yet simply strdup()s data left and right and assigns it to const\nfields, purposefully wasting memory.\n\nSure, I can leave those memory leaks in, but then I also have to introduce\nnew ones via the rebase -i support.\n\nIf you prefer to accept such sloppy work, I will change it of course,\nfeeling dirty that it has my name on it.\n\nCiao,\nDscho\n"},{"id":"303354","messageId":"alpine.DEB.2.20.1610051342490.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqinu028tx.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-05T11:46:03Z","receivedAt":"2016-10-05T11:46:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 12 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +static const char *get_dir(const struct replay_opts *opts)\n> > +{\n> > +\treturn git_path_seq_dir();\n> > +}\n> \n> Presumably this is what \"In a couple of commits\" meant, i.e. opts\n> will be used soonish.\n\nExactly. The sequencer code was taught to use a state directory different\nfrom rebase -i's (even if it quite clearly imitated rebase -i's approach),\nto allow for rebase -i to run at the same time as the sequencer (by\ncalling it via cherry-pick).\n\nSo we need to be able to use different seq_dir locations, depending on the\nmode we are running in.\n\nI briefly considered consolidating them and using .git/rebase-merge/ as\nstate directory also for cherry-pick/revert, but that would cause\nproblems: I am surely not the only user who cherry-picks commits manually\nwhile running interactive rebases.\n\nCiao,\nDscho\n"},{"id":"303356","messageId":"alpine.DEB.2.20.1610051348020.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqh99kzua9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 19/25] sequencer: remember do_recursive_merge()'s return value","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-05T12:35:50Z","receivedAt":"2016-10-05T12:36:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 12 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > The return value of do_recursive_merge() may be positive (indicating merge\n> > conflicts), so let's OR later error conditions so as not to overwrite them\n> > with 0.\n> \n> Are the untold assumptions as follows?\n> \n>  - The caller wants to act on positive (not quite an error), zero\n>  (success) or negative (error);\n> \n>  - do_recursive_merge() can return positive (success with reservation),\n>  zero or negative, and the call to it would return immediately if it got\n>  negative;\n> \n>  - all other functions that come later may return either zero or\n>  negative, and never positive;\n> \n>  - Hence the caller can be assured that \"res\" being positive can only\n>  mean do_recursive_merge() succeeded with reservation and everything\n>  else succeeded.\n\nMore or less. The idea is that there are problems with the merge, and\nthere are fatal errors.\n\nAlex and I chose to stay close to the original Python implementation when\nwe decided that merge_trees() should return 1 for success and 0 for\nfailure. In hindsight, I regret that, as it disagrees with the C\nconvention to return 0 for success. However, it would have been yet\nanother mistake to return -1 in case of merge conflicts: the function did\nnot have a problem (such as out-of-memory or some such).\n\nI can only guess that the do_recursive_merge() function tried to undo the\ndamage by reversing the logic: 0 for success, 1 for unclean merge. It is\nat least more in line with the C convention.\n\nSo much so, in fact, that we can still use negative values to indicate\nfatal errors that should be handled accordingly.\n\n> This can be extended if the only thing the caller cares about is\n> positive/zero/negative and it does not care what exact positive\n> value it gets--in such a case, we can loosen the condition on the\n> return values from other functions whose return values are OR'ed\n> together; they may also return positive to signal the same \"not\n> quite an error\", i.e. updating the latter two points to\n> \n>  - all other functions that come later can return positive (success\n>    with reservation), zero or negative.\n> \n>  - Hence the caller can be assured that \"res\" being positive can\n>    mean nobody failed with negative return, but it is not an\n>    unconditional success, which is signalled by value \"res\" being\n>    0.\n> \n> I cannot quite tell which is the case, especially what is planned in\n> the future.  The proposed log message is a good place to explain the\n> future course this code will take.\n\nOkay, I will try to come up with a better commit message.\n\nActually, come to think of it, I will change the patch, as it is too\nconfusing. What I want is to preserve a positive return value in case of\nmerge conflicts, and that is exactly what I should do instead of playing\ngames with the Boolean OR operator.\n\nCiao,\nDscho\n"},{"id":"303357","messageId":"alpine.DEB.2.20.1610051437050.35196@virtualbox","threadId":"43954","inReplyTo":"xmqq8tuwztpd.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 17/25] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-05T12:41:38Z","receivedAt":"2016-10-05T12:41:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 12 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This teaches the sequencer_commit() function to take an argument that\n> > will allow us to implement \"todo\" commands that need to amend the commit\n> > messages (\"fixup\", \"squash\" and \"reword\").\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 6 ++++--\n> >  sequencer.h | 2 +-\n> >  2 files changed, 5 insertions(+), 3 deletions(-)\n> >\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 6e9732c..60b522e 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -485,7 +485,7 @@ static char **read_author_script(void)\n> >   * author metadata.\n> >   */\n> >  int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> > -\t\t\t  int allow_empty, int edit)\n> > +\t\t\t  int allow_empty, int edit, int amend)\n> >  {\n> >  \tchar **env = NULL;\n> >  \tstruct argv_array array;\n> > @@ -514,6 +514,8 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n> >  \targv_array_push(&array, \"commit\");\n> >  \targv_array_push(&array, \"-n\");\n> >  \n> > +\tif (amend)\n> > +\t\targv_array_push(&array, \"--amend\");\n> >  \tif (opts->gpg_sign)\n> >  \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n> >  \tif (opts->signoff)\n> > @@ -786,7 +788,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n> >  \t}\n> >  \tif (!opts->no_commit)\n> >  \t\tres = sequencer_commit(opts->edit ? NULL : git_path_merge_msg(),\n> > -\t\t\topts, allow, opts->edit);\n> > +\t\t\topts, allow, opts->edit, 0);\n> >  \n> >  leave:\n> >  \tfree_message(commit, &msg);\n> \n> Hmm, this is more about a comment on 18/25, but I suspect that\n> \"amend\" or any opportunity given to the user to futz with the\n> contents in the editor invites a wish for the result to be treated\n> with stripspace.\n\nThe point of separating the cleanup_commit_message from the edit flag is\nto allow final fixup commands to stripspace, even without letting the user\nedit the message.\n\nSo while you are correct that \"edit != 0\" should imply\n\"cleanup_commit_message != 0\", I would rather keep that explicit.\n\n> No existing callers use \"amend\" to call this function, so there is\n> no change in behaviour, but at the same time, we do not have enough\n> information to see if 'amend' should by default toggle cleanup.\n\nIt should not. Non-final fixup/squash commands *need* to keep the\ncomment lines.\n\nKeeping things explicit makes it easier to understand the flow, methinks.\n\nCiao,\nDscho\n"},{"id":"303359","messageId":"alpine.DEB.2.20.1610051504360.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqfup1nf3u.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 21/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-05T13:08:25Z","receivedAt":"2016-10-05T13:08:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio & Hannes,\n\nOn Thu, 15 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Sixt <j6t@kdbg.org> writes:\n> \n> > Am 11.09.2016 um 12:55 schrieb Johannes Schindelin:\n> >> -static int write_message(struct strbuf *msgbuf, const char *filename)\n> >> +static int write_with_lock_file(const char *filename,\n> >> +\t\t\t\tconst void *buf, size_t len, int append_eol)\n> >>  {\n> >>  \tstatic struct lock_file msg_file;\n> >>\n> >>  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n> >>  \tif (msg_fd < 0)\n> >>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n> >> -\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n> >> -\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n> >> -\tstrbuf_release(msgbuf);\n> >> +\tif (write_in_full(msg_fd, buf, len) < 0)\n> >> +\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n> >> +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n> >> +\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n> >>  \tif (commit_lock_file(&msg_file) < 0)\n> >>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n> >>\n> >>  \treturn 0;\n> >>  }\n> >\n> > The two error paths in the added lines should both\n> >\n> > \t\trollback_lock_file(&msg_file);\n> >\n> > , I think. But I do notice that this is not exactly new, so...\n> \n> It may not be new for this step, but overall the series is aiming to\n> libify the stuff, so we should fix fd and lockfile leaks like this\n> as we notice them.\n\nMakes sense, even for the final commit_lock_file().\n\nCiao,\nDscho\n"},{"id":"303411","messageId":"xmqqr37upubf.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610051342490.35196@virtualbox","subject":"Re: [PATCH v2 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-05T17:41:24Z","receivedAt":"2016-10-05T17:41:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> I briefly considered consolidating them and using .git/rebase-merge/ as\n> state directory also for cherry-pick/revert, but that would cause\n> problems: I am surely not the only user who cherry-picks commits manually\n> while running interactive rebases.\n\nGood thinking.\n"},{"id":"303412","messageId":"xmqqmviipu7p.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610051348020.35196@virtualbox","subject":"Re: [PATCH v2 19/25] sequencer: remember do_recursive_merge()'s return value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-05T17:43:38Z","receivedAt":"2016-10-05T17:43:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Actually, come to think of it, I will change the patch, as it is too\n> confusing. What I want is to preserve a positive return value in case of\n> merge conflicts, and that is exactly what I should do instead of playing\n> games with the Boolean OR operator.\n\nThat would be good; that was exactly the confusion I felt that led\nto my comments.\n"},{"id":"303481","messageId":"alpine.DEB.2.20.1610061459390.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqr38p3z1i.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-06T13:08:53Z","receivedAt":"2016-10-06T13:09:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 12 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> I do not offhand see why we want to be lenient here,\n> >> especially only to the left.\n> >\n> > Postel's Law.\n> \n> How would that compare/relate to yagni, though?\n\nI did need it, though. Blame it on being overworked or simply tired: I\nended up inserting a spurious space before a \"fixup\" command. This command\nwas handled as intended by the scripted rebase -i, and with the patch in\nquestion the rebase--helper agreed, too.\n\nNote: we have no problem to the right because we do handle variable-length\nwhitespace between command and SHA-1, and we do not care one iota about\nthe exact form of the oneline (hence right-stripping is not necessary).\n\nCiao,\nDscho\n"},{"id":"303487","messageId":"alpine.DEB.2.20.1610061541300.35196@virtualbox","threadId":"43954","inReplyTo":"xmqq60q26mfw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 24/25] sequencer: quote filenames in error messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-06T13:41:47Z","receivedAt":"2016-10-06T13:42:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 11 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This makes the code consistent by fixing quite a couple of error messages.\n> \n> Looks OK.  While at it, we may want another one to downcase the\n> first word, perhaps?\n> \n> These may not be messages added by your series and can be left\n> outside this series, but I have to point out that\n> \n>     if (commit_lock_file(&msg_file) < 0)\n>         return error(_(\"Error wrapping up '%s'.\"), filename);\n> \n> results in \"error: Error wrapping up\", which sounds quite funny.\n> \n> \"failed to finalize\" or something would flow a bit better, I'd say.\n\nFair enough. I added a patch to make it so.\n\nThanks,\nDscho\n"},{"id":"303489","messageId":"alpine.DEB.2.20.1610061559450.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqa8fe6mln.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 25/25] sequencer: remove bogus hint for translators","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-06T14:18:22Z","receivedAt":"2016-10-06T14:18:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 11 Sep 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > When translating error messages, we need to be careful *not* to translate\n> > the todo commands such as \"pick\", \"reword\", etc because they are commands,\n> > and Git would not understand translated versions of those commands.\n> >\n> > Therefore, translating the commands in the error messages would simply be\n> > misleading.\n> \n> This comes from b9c993e0 (\"i18n: git-revert literal \"me\" messages\",\n> 2011-02-22) where it said\n> \n> Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> \n>     i18n: git-revert literal \"me\" messages\n>     \n>     Translate messages that use the `me' variable. These are all error\n>     messages referencing the command name, so the name shouldn't be\n>     translated.\n>     \n>     Reported-by: Jonathan Nieder <jrnieder@gmail.com>\n>     Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>     Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> \n> This looks like a positive attempt to remind translators that their\n> translation must flow with these literal command names that will not\n> get translated in place, not a bogus hint at all, at least to me.\n\nAlright, I misread it to mean: \"You need to translate these terms\".\n\nI fixed it by skipping this patch, and amending the \"revamp the todo\nparsing\" patch: the first %s now actually refers to the much more helpful\ntodo command rather than the overall Git command.\n\nThanks,\nDscho"},{"id":"303496","messageId":"5ed8aaea-9fbe-11b0-49b7-1b42567d4918@kdbg.org","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610061459390.35196@virtualbox","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-10-06T16:23:27Z","receivedAt":"2016-10-06T16:23:34Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 06.10.2016 um 15:08 schrieb Johannes Schindelin:\n> Hi Junio,\n> \n> On Mon, 12 Sep 2016, Junio C Hamano wrote:\n> \n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>>\n>>>> I do not offhand see why we want to be lenient here,\n>>>> especially only to the left.\n>>>\n>>> Postel's Law.\n>>\n>> How would that compare/relate to yagni, though?\n> \n> I did need it, though. Blame it on being overworked or simply tired: I\n> ended up inserting a spurious space before a \"fixup\" command. This command\n> was handled as intended by the scripted rebase -i, and with the patch in\n> question the rebase--helper agreed, too.\n> \n> Note: we have no problem to the right because we do handle variable-length\n> whitespace between command and SHA-1, and we do not care one iota about\n> the exact form of the oneline (hence right-stripping is not necessary).\n\nThe last sentence is not entirely correct. See the patch below. You\nmay pick up the idea in one form or another, or just queue the patch\nnear the end of your series.\n\nLet me take the opportunity to say\n\n   Thank You Very Much!\n\nfor the new implementation of rebase -i. I'm using your branch\nrebase-i-extra, and it is such a pleasure to work with on Windows\ncompared to the old fully scripted version.\n\n---- 8< ----\n[PATCH] sequencer: strip CR from the end of exec insns\n\nIt is not unheard of that editors on Windows write CRLF even if the file\noriginally had only LF. This is particularly awkward for exec lines of a\nrebase -i todo sheet. Take for example the insn \"exec echo\": The shell\nscript parser (either of the sequencer or of the shell that is invoked,\nI do not know) splits at the LF and leaves the CR attached to \"echo\",\nwhich leads to the unknown command \"echo\\r\".\n\nWork it around by stripping CR before the command specified with exec is\npassed to the shell.\n\nThis happens to fix t9903.14 and .15 in my environment: the insn sheet\nconstructed here contains CRLF thanks to MSYS1's bash cleverness.\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n sequencer.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex daf8f13..6961820 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2005,8 +2005,11 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t}\n \t\telse if (item->command == TODO_EXEC) {\n \t\t\tchar *end_of_arg = (char *)(item->arg + item->arg_len);\n-\t\t\tint saved = *end_of_arg;\n+\t\t\tint saved;\n \n+\t\t\twhile (end_of_arg != item->arg && end_of_arg[-1] == '\\r')\n+\t\t\t\tend_of_arg--;\n+\t\t\tsaved = *end_of_arg;\n \t\t\t*end_of_arg = '\\0';\n \t\t\tres = do_exec(item->arg);\n \t\t\t*end_of_arg = saved;\n-- \n2.10.0.343.g37bc62b\n\n"},{"id":"303510","messageId":"xmqqa8ehl3qv.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"5ed8aaea-9fbe-11b0-49b7-1b42567d4918@kdbg.org","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-06T18:41:12Z","receivedAt":"2016-10-06T18:41:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Let me take the opportunity to say\n>\n>    Thank You Very Much!\n>\n> for the new implementation of rebase -i. I'm using your branch\n> rebase-i-extra, and it is such a pleasure to work with on Windows\n> compared to the old fully scripted version.\n\nThanks for testing.  \n\nHaving more guinea pigs ^W ^W testers before the series is reviewed\nhere would be a nice boost and would hopefully encourage more\nreviewers to help the series into a good shape to be upstreamed ;-)\n\n> ---- 8< ----\n> [PATCH] sequencer: strip CR from the end of exec insns\n>\n> It is not unheard of that editors on Windows write CRLF even if the file\n> originally had only LF. This is particularly awkward for exec lines of a\n> rebase -i todo sheet. Take for example the insn \"exec echo\": The shell\n> script parser (either of the sequencer or of the shell that is invoked,\n> I do not know) splits at the LF and leaves the CR attached to \"echo\",\n> which leads to the unknown command \"echo\\r\".\n\nInteresting find.  So it's not just ltrim is being lenient only to\nend-user typo, but not doing rtrim can actively hurt ;-)\n\n> Work it around by stripping CR before the command specified with exec is\n> passed to the shell.\n\nMakes sense.\n\n"},{"id":"303518","messageId":"xmqqeg3tjn7n.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610051338530.35196@virtualbox","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-06T19:23:40Z","receivedAt":"2016-10-06T19:24:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> If you prefer to accept such sloppy work, I will change it of course,\n> feeling dirty that it has my name on it.\n\nI do want neither leaks nor sloppyness, and I thought that was\nunderstood by everybody, hence I thought the last round made it\nclear that _entrust() must not exist.\n\nLet's try again.\n\nWe manage lifetime of a field in a structure in one of three ways in\nour codebase [*1*].\n\n * A field can always point at a borrowed piece of memory that the\n   destruction of the containing structure or re-assignment to the\n   field do not have to free the current value of the field.  This\n   is a minority, simply because it is rare for a field to be always\n   able to borrow from others.  The destruction of the containing\n   structure or re-assignment to the field needs to do nothing\n   special.\n\n * A field can own the piece of memory that it points at.  The\n   destruction of the containing structure or re-assignment to the\n   field needs to free the current value of the field [*2*].  A\n   field that can be assigned a value from the configuration (which\n   is typically xstrdup()'ed) is an example of such a field, and if\n   a command line option also can assign to the field, we'd need to\n   xstrdup() it, even though we know we could borrow from argv[],\n   because cleaning-up needs to be able to free(3) it.\n\n * A field can sometimes own and sometimes borrow the memory, and it\n   is accompanied by another field to tell which case it is, so that\n   cleaning-up can tell when it needs to be free(3)d.  This is a\n   minority case, and we generally avoid it especially in modern\n   code for small allocation, as it makes the lifetime rule more\n   complex than it is worth.\n\nThe _entrust() thing may have been an excellent fourth option if it\nwere cost-free.  xstrdup() that the second approach necessitates for\nliteral strings (like part of argv[]) would become unnecessary and\nwe can treat as if all the fields in a structure were all borrowing\nthe memory from elsewhere (in fact, _entrust() creates the missing\nowners of pieces of memory that need to be freed later); essentially\nit turns a \"mixed ownership\" case into the first approach.\n\nBut it is not cost-free.  The mechanism needs to allocate memory to\nbecome the missing owner and keep track of which pieces of memory\nneed to be freed later, and the resulting code does not become any\neasier to follow.  The programmer still needs to know which ones to\n_entrust() just like the programmer in the model #2 needs to make\nsure xstrdup() is done for appropriate pieces of memory--the only\ndifference is that an _entrust() programmer needs to mark the pieces\nof memory to be freed, while a #2 programmer needs to xstrdup() the\npieces of memory that are being \"borrowed\".\n\nSo let's not add the fourth way to our codebase.  \"mixed ownership\"\ncase should be turned into \"field owns the memory\", i.e. approach #2.\n\n\n[Footnotes]\n\n*1* It is normal for different fields in the same structure follow\n    different lifetime rules.\n\n*2* Unless leaks are allowed, that is.  I think we have instances\n    where \"git cmd --opt=A --opt=B\" allocates and stores a new piece\n    of memory that is computed based on A and store it to a field,\n    and then overwrites the field with another allocation of a value\n    based on B without freeing old value, saying \"the caller can\n    avoid passing the same thing twice, and such a leak is miniscule\n    anyway\".  That is not nice, and we've been reducing them over\n    time.\n"},{"id":"303537","messageId":"28935e27-5ba8-c261-ba44-424f7b91cdda@gmail.com","threadId":"43954","inReplyTo":"xmqqeg3tjn7n.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-10-06T22:40:59Z","receivedAt":"2016-10-06T22:41:45Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 06.10.2016 o 21:23, Junio C Hamano pisze:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n>> If you prefer to accept such sloppy work, I will change it of course,\n>> feeling dirty that it has my name on it.\n> \n> I do want neither leaks nor sloppyness, and I thought that was\n> understood by everybody, hence I thought the last round made it\n> clear that _entrust() must not exist.\n\nAlso, the *_entrust() mechanism in v1 was quite sequencer-specific,\nrather than be a generic mechanism.\n\n> \n> Let's try again.\n> \n> We manage lifetime of a field in a structure in one of three ways in\n> our codebase [*1*].\n> \n>  * A field can always point at a borrowed piece of memory that the\n>    destruction of the containing structure or re-assignment to the\n>    field do not have to free the current value of the field.  This\n>    is a minority, simply because it is rare for a field to be always\n>    able to borrow from others.  The destruction of the containing\n>    structure or re-assignment to the field needs to do nothing\n>    special.\n> \n>  * A field can own the piece of memory that it points at.  The\n>    destruction of the containing structure or re-assignment to the\n>    field needs to free the current value of the field [*2*].  A\n>    field that can be assigned a value from the configuration (which\n>    is typically xstrdup()'ed) is an example of such a field, and if\n>    a command line option also can assign to the field, we'd need to\n>    xstrdup() it, even though we know we could borrow from argv[],\n>    because cleaning-up needs to be able to free(3) it.\n> \n>  * A field can sometimes own and sometimes borrow the memory, and it\n>    is accompanied by another field to tell which case it is, so that\n>    cleaning-up can tell when it needs to be free(3)d.  This is a\n>    minority case, and we generally avoid it especially in modern\n>    code for small allocation, as it makes the lifetime rule more\n>    complex than it is worth.\n\nGreat writeup!\n\n> The _entrust() thing may have been an excellent fourth option if it\n> were cost-free.  xstrdup() that the second approach necessitates for\n> literal strings (like part of argv[]) would become unnecessary and\n> we can treat as if all the fields in a structure were all borrowing\n> the memory from elsewhere (in fact, _entrust() creates the missing\n> owners of pieces of memory that need to be freed later); essentially\n> it turns a \"mixed ownership\" case into the first approach.\n> \n> But it is not cost-free.  The mechanism needs to allocate memory to\n> become the missing owner and keep track of which pieces of memory\n> need to be freed later, and the resulting code does not become any\n> easier to follow.  The programmer still needs to know which ones to\n> _entrust() just like the programmer in the model #2 needs to make\n> sure xstrdup() is done for appropriate pieces of memory--the only\n> difference is that an _entrust() programmer needs to mark the pieces\n> of memory to be freed, while a #2 programmer needs to xstrdup() the\n> pieces of memory that are being \"borrowed\".\n> \n> So let's not add the fourth way to our codebase.  \"mixed ownership\"\n> case should be turned into \"field owns the memory\", i.e. approach #2.\n\nOn the other hand the _entrust() mechanism might be a good solution\nif the amount of memory was large, for example order of magnitude more\nthan what would be needed to keep ownership info *and* borrowing would\nnot be possible for some reason.\n\nBut the _entrust() mechanism reminds me on one hand side of memory\ndebuggers like dmalloc, Electric Fence (eFence), or valgrind; combined\na bit with garbage collection.  Namely, when we are in a library call,\nrecord all allocations (perhaps by redirecting alloc functions), then\nfree those resources at the exit of library call.\n \n> \n> [Footnotes]\n> \n> *1* It is normal for different fields in the same structure follow\n>     different lifetime rules.\n> \n> *2* Unless leaks are allowed, that is.  I think we have instances\n>     where \"git cmd --opt=A --opt=B\" allocates and stores a new piece\n>     of memory that is computed based on A and store it to a field,\n>     and then overwrites the field with another allocation of a value\n>     based on B without freeing old value, saying \"the caller can\n>     avoid passing the same thing twice, and such a leak is miniscule\n>     anyway\".  That is not nice, and we've been reducing them over\n>     time.\n> \n\n"},{"id":"303539","messageId":"xmqq8tu1hyxc.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"28935e27-5ba8-c261-ba44-424f7b91cdda@gmail.com","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-06T22:53:35Z","receivedAt":"2016-10-06T22:53:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n>> We manage lifetime of a field in a structure in one of three ways in\n>> our codebase [*1*].\n>> \n>>  ...\n>>  * A field can sometimes own and sometimes borrow the memory, and it\n>>    is accompanied by another field to tell which case it is, so that\n>>    cleaning-up can tell when it needs to be free(3)d.  This is a\n>>    minority case, and we generally avoid it especially in modern\n>>    code for small allocation, as it makes the lifetime rule more\n>>    complex than it is worth.\n> ...\n> On the other hand the _entrust() mechanism might be a good solution\n> if the amount of memory was large, for example order of magnitude more\n> than what would be needed to keep ownership info *and* borrowing would\n> not be possible for some reason.\n\nWe have approach #3 exactly for that usage pattern.\n"},{"id":"303628","messageId":"alpine.DEB.2.20.1610081108520.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqeg3tjn7n.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 05/25] sequencer: allow the sequencer to take custody of malloc()ed data","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-08T09:11:50Z","receivedAt":"2016-10-08T09:18:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 6 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > If you prefer to accept such sloppy work, I will change it of course,\n> > feeling dirty that it has my name on it.\n> \n> I do want neither leaks nor sloppyness, and I thought that was\n> understood by everybody, hence I thought the last round made it\n> clear that _entrust() must not exist.\n\nWell, you leave me with but one choice. With shame in my face I will send\nout the next re-roll with this construct:\n\n@@ -796,24 +1002,52 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n                opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n        else if (!strcmp(key, \"options.mainline\"))\n                opts->mainline = git_config_int(key, value);\n-       else if (!strcmp(key, \"options.strategy\"))\n-               git_config_string(&opts->strategy, key, value);\n-       else if (!strcmp(key, \"options.gpg-sign\"))\n-               git_config_string(&opts->gpg_sign, key, value);\n+       else if (!strcmp(key, \"options.strategy\")) {\n+               if (!value)\n+                       config_error_nonbool(key);\n+               else {\n+                       free(opts->strategy);\n+                       opts->strategy = xstrdup(value);\n+               }\n+       }\n+       else if (!strcmp(key, \"options.gpg-sign\")) {\n+               if (!value)\n+                       config_error_nonbool(key);\n+               else {\n+                       free(opts->gpg_sign);\n+                       opts->gpg_sign = xstrdup(value);\n+               }\n+       }\n...\n@@ -37,18 +26,32 @@ struct replay_opts {\n\n        int mainline;\n\n-       const char *gpg_sign;\n+       char *gpg_sign;\n\n        /* Merge strategy */\n-       const char *strategy;\n-       const char **xopts;\n+       char *strategy;\n+       char **xopts;\n\n(this is not the complete diff, of course, but you get the idea.)\n\nCiao,\nDscho\n"},{"id":"303660","messageId":"alpine.DEB.2.20.1610091054490.35196@virtualbox","threadId":"43954","inReplyTo":"5ed8aaea-9fbe-11b0-49b7-1b42567d4918@kdbg.org","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-09T08:57:20Z","receivedAt":"2016-10-09T09:04:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Hannes,\n\nOn Thu, 6 Oct 2016, Johannes Sixt wrote:\n\n> [PATCH] sequencer: strip CR from the end of exec insns\n> \n> It is not unheard of that editors on Windows write CRLF even if the file\n> originally had only LF. This is particularly awkward for exec lines of a\n> rebase -i todo sheet. Take for example the insn \"exec echo\": The shell\n> script parser (either of the sequencer or of the shell that is invoked,\n> I do not know) splits at the LF and leaves the CR attached to \"echo\",\n> which leads to the unknown command \"echo\\r\".\n> \n> Work it around by stripping CR before the command specified with exec is\n> passed to the shell.\n> \n> This happens to fix t9903.14 and .15 in my environment: the insn sheet\n> constructed here contains CRLF thanks to MSYS1's bash cleverness.\n\nGood point. I decided to do it at a different level, though:\nparse_insn_line() should already receive the line without trailing\nend-of-line markers (this was already the case for LF-only todo scripts).\n\nI reused your commit message and touched it up a bit, hope you don't mind!\n\nCiao,\nDscho\n"},{"id":"303666","messageId":"5d9ab6f1-211c-37fc-9396-0742426b2c45@kdbg.org","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610091054490.35196@virtualbox","subject":"Re: [PATCH v2 20/25] sequencer: left-trim lines read from the script","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-10-09T10:45:08Z","receivedAt":"2016-10-09T10:45:16Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 09.10.2016 um 10:57 schrieb Johannes Schindelin:\n> Good point. I decided to do it at a different level, though:\n> parse_insn_line() should already receive the line without trailing\n> end-of-line markers (this was already the case for LF-only todo scripts).\n>\n> I reused your commit message and touched it up a bit, hope you don't mind!\n\nI don't mind at all.\n\nThanks,\n-- Hannes\n\n"},{"id":"303738","messageId":"cover.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1473590966.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 00/25] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:13Z","receivedAt":"2016-10-10T17:24:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series marks the  '4' in the countdown to speed up rebase -i\nby implementing large parts in C. It is based on the `libify-sequencer`\npatch series that I submitted last week.\n\nThe patches in this series merely prepare the sequencer code for the\nnext patch series that actually teaches the sequencer to run an\ninteractive rebase.\n\nThe reason to split these two patch series is simple: to keep them at a\nsensible size.\n\nThe two patch series after that are much smaller: a two-patch \"series\"\nthat switches rebase -i to use the sequencer (except with --root or\n--preserve-merges), and a couple of patches to move several pretty\nexpensive script processing steps to C (think: autosquash).\n\nThe end game of this patch series is a git-rebase--helper that makes\nrebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\nthat even MacOSX and Linux benefit (4x and 3x, respectively).\n\nI have been working on this since early February, whenever time allowed,\nand it is time to put it into the users' hands. To that end, I will most\nlikely submit the remaining three patch series in the next two days, and\nintegrate the whole shebang into Git for Windows 2.10.0.\n\nTherefore I would be most grateful for every in-depth review.\n\nChanges vs v2:\n\n- dramatically simplified the logic to retain do_recursive_merge()'s\n  return value, even when positive (indicating merge conflicts).\n\n- ensured that write_message() rolls back locked files in case of\n  errors.\n\n- added a patch to downcase all first letters of sequencer's error\n  messages, as suggested by Junio.\n\n- replaced 25/25 (\"sequencer: remove bogus hint for translators\") by a\n  fix to 8/25 (\"completely revamp todo parsing\"): the first %s is no\n  longer \"revert\" or \"cherry-pick\", but a \"todo\" command.\n\n- backed out the sequencer_entrust() function and uglified the code to\n  always duplicate the option values for the sake of being able to\n  properly releasing them afterwards.\n\n- CR/LFs are now handled like LFs in todo scripts: they are stripped\n  (thanks to Hannes Sixt for pointing that out).\n\n- unexported sequencer_commit() (it can safely remain a static\n  function). While at it, renamed it back to run_git_commit() (the\n  unspecific name does not hurt if it remains private to sequencer.c).\n\n- clarified in a code comment what read_author_script() does.\n\n- marked for translation the last remaining error message in sequencer.c\n  that was not yet marked for translation.\n\n\nJohannes Schindelin (25):\n  sequencer: use static initializers for replay_opts\n  sequencer: use memoized sequencer directory path\n  sequencer: avoid unnecessary indirection\n  sequencer: future-proof remove_sequencer_state()\n  sequencer: eventually release memory allocated for the option values\n  sequencer: future-proof read_populate_todo()\n  sequencer: completely revamp the \"todo\" script parsing\n  sequencer: strip CR from the todo script\n  sequencer: avoid completely different messages for different actions\n  sequencer: get rid of the subcommand field\n  sequencer: refactor the code to obtain a short commit name\n  sequencer: remember the onelines when parsing the todo file\n  sequencer: prepare for rebase -i's commit functionality\n  sequencer: introduce a helper to read files written by scripts\n  sequencer: allow editing the commit message on a case-by-case basis\n  sequencer: support amending commits\n  sequencer: support cleaning up commit messages\n  sequencer: do not try to commit when there were merge conflicts\n  sequencer: left-trim lines read from the script\n  sequencer: refactor write_message()\n  sequencer: remove overzealous assumption in rebase -i mode\n  sequencer: mark action_name() for translation\n  sequencer: quote filenames in error messages\n  sequencer: start error messages consistently with lower case\n  sequencer: mark all error messages for translation\n\n builtin/commit.c              |   2 +-\n builtin/revert.c              |  48 +--\n sequencer.c                   | 690 ++++++++++++++++++++++++++++--------------\n sequencer.h                   |  23 +-\n t/t3501-revert-cherry-pick.sh |   2 +-\n 5 files changed, 503 insertions(+), 262 deletions(-)\n\nPublished-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v3\nFetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v3\n\nInterdiff vs v2:\n\n diff --git a/builtin/revert.c b/builtin/revert.c\n index c9ae4dc..0a7b5f4 100644\n --- a/builtin/revert.c\n +++ b/builtin/revert.c\n @@ -165,6 +165,12 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n  \tif (argc > 1)\n  \t\tusage_with_options(usage_str, options);\n  \n +\t/* These option values will be free()d */\n +\tif (opts->gpg_sign)\n +\t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n +\tif (opts->strategy)\n +\t\topts->strategy = xstrdup(opts->strategy);\n +\n  \tif (cmd == 'q')\n  \t\treturn sequencer_remove_state(opts);\n  \tif (cmd == 'c')\n diff --git a/sequencer.c b/sequencer.c\n index cdff0f1..86d86ce 100644\n --- a/sequencer.c\n +++ b/sequencer.c\n @@ -148,23 +148,15 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n  \treturn buf.buf;\n  }\n  \n -void *sequencer_entrust(struct replay_opts *opts, void *to_free)\n -{\n -\tALLOC_GROW(opts->owned, opts->owned_nr + 1, opts->owned_alloc);\n -\topts->owned[opts->owned_nr++] = to_free;\n -\n -\treturn to_free;\n -}\n -\n  int sequencer_remove_state(struct replay_opts *opts)\n  {\n  \tstruct strbuf dir = STRBUF_INIT;\n  \tint i;\n  \n -\tfor (i = 0; i < opts->owned_nr; i++)\n -\t\tfree(opts->owned[i]);\n -\tfree(opts->owned);\n -\n +\tfree(opts->gpg_sign);\n +\tfree(opts->strategy);\n +\tfor (i = 0; i < opts->xopts_nr; i++)\n +\t\tfree(opts->xopts[i]);\n  \tfree(opts->xopts);\n  \n  \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n @@ -249,13 +241,19 @@ static int write_with_lock_file(const char *filename,\n  \n  \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n  \tif (msg_fd < 0)\n -\t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n -\tif (write_in_full(msg_fd, buf, len) < 0)\n -\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n -\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0)\n -\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n -\tif (commit_lock_file(&msg_file) < 0)\n -\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n +\t\treturn error_errno(_(\"could not lock '%s'\"), filename);\n +\tif (write_in_full(msg_fd, buf, len) < 0) {\n +\t\trollback_lock_file(&msg_file);\n +\t\treturn error_errno(_(\"could not write to '%s'\"), filename);\n +\t}\n +\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n +\t\trollback_lock_file(&msg_file);\n +\t\treturn error_errno(_(\"could not write eol to '%s\"), filename);\n +\t}\n +\tif (commit_lock_file(&msg_file) < 0) {\n +\t\trollback_lock_file(&msg_file);\n +\t\treturn error(_(\"failed to finalize '%s'.\"), filename);\n +\t}\n  \n  \treturn 0;\n  }\n @@ -288,7 +286,7 @@ static int read_oneliner(struct strbuf *buf,\n  \t\treturn 0;\n  \n  \tif (strbuf_read_file(buf, path, 0) < 0) {\n -\t\twarning_errno(\"could not read '%s'\", path);\n +\t\twarning_errno(_(\"could not read '%s'\"), path);\n  \t\treturn 0;\n  \t}\n  \n @@ -314,11 +312,11 @@ static int error_dirty_index(struct replay_opts *opts)\n  \tif (read_cache_unmerged())\n  \t\treturn error_resolve_conflict(_(action_name(opts)));\n  \n -\terror(_(\"Your local changes would be overwritten by %s.\"),\n +\terror(_(\"your local changes would be overwritten by %s.\"),\n  \t\t_(action_name(opts)));\n  \n  \tif (advice_commit_before_merge)\n -\t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n +\t\tadvise(_(\"commit your changes or stash them to proceed.\"));\n  \treturn -1;\n  }\n  \n @@ -379,7 +377,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  \tstruct merge_options o;\n  \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n  \tint clean;\n -\tconst char **xopt;\n +\tchar **xopt;\n  \tstatic struct lock_file index_lock;\n  \n  \thold_locked_index(&index_lock, 1);\n @@ -427,7 +425,7 @@ static int is_index_unchanged(void)\n  \tstruct commit *head_commit;\n  \n  \tif (!resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING, head_sha1, NULL))\n -\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n +\t\treturn error(_(\"could not resolve HEAD commit\\n\"));\n  \n  \thead_commit = lookup_commit(head_sha1);\n  \n @@ -447,11 +445,15 @@ static int is_index_unchanged(void)\n  \n  \tif (!cache_tree_fully_valid(active_cache_tree))\n  \t\tif (cache_tree_update(&the_index, 0))\n -\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n +\t\t\treturn error(_(\"unable to update cache tree\\n\"));\n  \n  \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n  }\n  \n +/*\n + * Read the author-script file into an environment block, ready for use in\n + * run_command(), that can be free()d afterwards.\n + */\n  static char **read_author_script(void)\n  {\n  \tstruct strbuf script = STRBUF_INIT;\n @@ -495,11 +497,11 @@ static char **read_author_script(void)\n   * If we are revert, or if our cherry-pick results in a hand merge,\n   * we had better say that the current user is responsible for that.\n   *\n - * An exception is when sequencer_commit() is called during an\n + * An exception is when run_git_commit() is called during an\n   * interactive rebase: in that case, we will want to retain the\n   * author metadata.\n   */\n -int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n +static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n  \t\t\t  int allow_empty, int edit, int amend,\n  \t\t\t  int cleanup_commit_message)\n  {\n @@ -513,16 +515,19 @@ int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n  \t\tif (!env) {\n  \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n  \n -\t\t\treturn error(\"You have staged changes in your working \"\n -\t\t\t\t\"tree. If these changes are meant to be\\n\"\n -\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n -\t\t\t\t\"  git commit --amend %s\\n\\n\"\n -\t\t\t\t\"If they are meant to go into a new commit, \"\n -\t\t\t\t\"run:\\n\\n\"\n -\t\t\t\t\"  git commit %s\\n\\n\"\n -\t\t\t\t\"In both cases, once you're done, continue \"\n -\t\t\t\t\"with:\\n\\n\"\n -\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n +\t\t\treturn error(_(\"you have staged changes in your \"\n +\t\t\t\t       \"working tree. If these changes are \"\n +\t\t\t\t       \"meant to be\\n\"\n +\t\t\t\t       \"squashed into the previous commit, \"\n +\t\t\t\t       \"run:\\n\\n\"\n +\t\t\t\t       \"  git commit --amend %s\\n\\n\"\n +\t\t\t\t       \"If they are meant to go into a new \"\n +\t\t\t\t       \"commit, run:\\n\\n\"\n +\t\t\t\t       \"  git commit %s\\n\\n\"\n +\t\t\t\t       \"In both cases, once you're done, \"\n +\t\t\t\t       \"continue with:\\n\\n\"\n +\t\t\t\t       \"  git rebase --continue\\n\"),\n +\t\t\t\t     gpg_opt, gpg_opt);\n  \t\t}\n  \t}\n  \n @@ -566,12 +571,12 @@ static int is_original_commit_empty(struct commit *commit)\n  \tconst unsigned char *ptree_sha1;\n  \n  \tif (parse_commit(commit))\n -\t\treturn error(_(\"Could not parse commit %s\\n\"),\n +\t\treturn error(_(\"could not parse commit %s\\n\"),\n  \t\t\t     oid_to_hex(&commit->object.oid));\n  \tif (commit->parents) {\n  \t\tstruct commit *parent = commit->parents->item;\n  \t\tif (parse_commit(parent))\n -\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n +\t\t\treturn error(_(\"could not parse parent commit %s\\n\"),\n  \t\t\t\toid_to_hex(&parent->object.oid));\n  \t\tptree_sha1 = parent->tree->object.oid.hash;\n  \t} else {\n @@ -645,7 +650,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \tconst char *base_label, *next_label;\n  \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n  \tstruct strbuf msgbuf = STRBUF_INIT;\n -\tint res = 0, unborn = 0, allow;\n +\tint res, unborn = 0, allow;\n  \n  \tif (opts->no_commit) {\n  \t\t/*\n @@ -655,7 +660,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\t * to work on.\n  \t\t */\n  \t\tif (write_cache_as_tree(head, 0, NULL))\n -\t\t\treturn error(_(\"Your index file is unmerged.\"));\n +\t\t\treturn error(_(\"your index file is unmerged.\"));\n  \t} else {\n  \t\tunborn = get_sha1(\"HEAD\", head);\n  \t\tif (unborn)\n @@ -674,7 +679,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\tstruct commit_list *p;\n  \n  \t\tif (!opts->mainline)\n -\t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n +\t\t\treturn error(_(\"commit %s is a merge but no -m option was given.\"),\n  \t\t\t\toid_to_hex(&commit->object.oid));\n  \n  \t\tfor (cnt = 1, p = commit->parents;\n @@ -682,11 +687,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\t     cnt++)\n  \t\t\tp = p->next;\n  \t\tif (cnt != opts->mainline || !p)\n -\t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n +\t\t\treturn error(_(\"commit %s does not have parent %d\"),\n  \t\t\t\toid_to_hex(&commit->object.oid), opts->mainline);\n  \t\tparent = p->item;\n  \t} else if (0 < opts->mainline)\n -\t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n +\t\treturn error(_(\"mainline was specified but commit %s is not a merge.\"),\n  \t\t\toid_to_hex(&commit->object.oid));\n  \telse\n  \t\tparent = commit->parents->item;\n @@ -697,12 +702,16 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n  \n  \tif (parent && parse_commit(parent) < 0)\n +\t\t/*\n +\t\t * TRANSLATORS: The first %s will be a \"todo\" command like\n +\t\t * \"revert\" or \"pick\", the second %s a SHA1.\n +\t\t */\n  \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n  \t\t\tcommand_to_string(command),\n  \t\t\toid_to_hex(&parent->object.oid));\n  \n  \tif (get_message(commit, &msg) != 0)\n -\t\treturn error(_(\"Cannot get commit message for %s\"),\n +\t\treturn error(_(\"cannot get commit message for %s\"),\n  \t\t\toid_to_hex(&commit->object.oid));\n  \n  \t/*\n @@ -754,7 +763,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t}\n  \n  \tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n -\t\tres |= do_recursive_merge(base, next, base_label, next_label,\n +\t\tres = do_recursive_merge(base, next, base_label, next_label,\n  \t\t\t\t\t head, &msgbuf, opts);\n  \t\tif (res < 0)\n  \t\t\treturn res;\n @@ -763,11 +772,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\tstruct commit_list *common = NULL;\n  \t\tstruct commit_list *remotes = NULL;\n  \n -\t\tres |= write_message(&msgbuf, git_path_merge_msg());\n +\t\tres = write_message(&msgbuf, git_path_merge_msg());\n  \n  \t\tcommit_list_insert(base, &common);\n  \t\tcommit_list_insert(next, &remotes);\n -\t\tres |= try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,\n +\t\tres |= try_merge_command(opts->strategy,\n +\t\t\t\t\t opts->xopts_nr, (const char **)opts->xopts,\n  \t\t\t\t\tcommon, sha1_to_hex(head), remotes);\n  \t\tfree_commit_list(common);\n  \t\tfree_commit_list(remotes);\n @@ -800,13 +810,12 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \n  \tallow = allow_empty(opts, commit);\n  \tif (allow < 0) {\n -\t\tres |= allow;\n +\t\tres = allow;\n  \t\tgoto leave;\n  \t}\n -\tif (!opts->no_commit)\n -\t\tres |= sequencer_commit(opts->edit ?\n -\t\t\t\tNULL : git_path_merge_msg(),\n -\t\t\topts, allow, opts->edit, 0, 0);\n +\tif (!res && !opts->no_commit)\n +\t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n +\t\t\t\t     opts, allow, opts->edit, 0, 0);\n  \n  leave:\n  \tfree_message(commit, &msg);\n @@ -924,23 +933,27 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n  static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n  {\n  \tstruct todo_item *item;\n -\tchar *p = buf;\n +\tchar *p = buf, *next_p;\n  \tint i, res = 0;\n  \n -\tfor (i = 1; *p; i++) {\n +\tfor (i = 1; *p; i++, p = next_p) {\n  \t\tchar *eol = strchrnul(p, '\\n');\n  \n +\t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n +\n +\t\tif (p != eol && eol[-1] == '\\r')\n +\t\t\teol--; /* skip Carriage Return */\n +\n  \t\titem = append_new_todo(todo_list);\n  \t\titem->offset_in_buf = p - todo_list->buf.buf;\n  \t\tif (parse_insn_line(item, p, eol)) {\n -\t\t\tres |= error(_(\"Invalid line %d: %.*s\"),\n +\t\t\tres = error(_(\"invalid line %d: %.*s\"),\n  \t\t\t\ti, (int)(eol - p), p);\n  \t\t\titem->command = -1;\n  \t\t}\n -\t\tp = *eol ? eol + 1 : eol;\n  \t}\n  \tif (!todo_list->nr)\n -\t\treturn error(_(\"No commits parsed.\"));\n +\t\treturn error(_(\"no commits parsed.\"));\n  \treturn res;\n  }\n  \n @@ -953,16 +966,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n  \tstrbuf_reset(&todo_list->buf);\n  \tfd = open(todo_file, O_RDONLY);\n  \tif (fd < 0)\n -\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n +\t\treturn error_errno(_(\"could not open '%s'\"), todo_file);\n  \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n  \t\tclose(fd);\n -\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n +\t\treturn error(_(\"could not read '%s'.\"), todo_file);\n  \t}\n  \tclose(fd);\n  \n  \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n  \tif (res)\n -\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n +\t\treturn error(_(\"unusable instruction sheet: '%s'\"), todo_file);\n  \n  \tif (!is_rebase_i(opts)) {\n  \t\tenum todo_command valid =\n @@ -973,9 +986,9 @@ static int read_populate_todo(struct todo_list *todo_list,\n  \t\t\tif (valid == todo_list->items[i].command)\n  \t\t\t\tcontinue;\n  \t\t\telse if (valid == TODO_PICK)\n -\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n +\t\t\t\treturn error(_(\"cannot cherry-pick during a revert.\"));\n  \t\t\telse\n -\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n +\t\t\t\treturn error(_(\"cannot revert during a cherry-pick.\"));\n  \t}\n  \n  \treturn 0;\n @@ -1001,22 +1014,29 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n  \telse if (!strcmp(key, \"options.mainline\"))\n  \t\topts->mainline = git_config_int(key, value);\n  \telse if (!strcmp(key, \"options.strategy\")) {\n -\t\tgit_config_string(&opts->strategy, key, value);\n -\t\tsequencer_entrust(opts, (char *) opts->strategy);\n +\t\tif (!value)\n +\t\t\tconfig_error_nonbool(key);\n +\t\telse {\n +\t\t\tfree(opts->strategy);\n +\t\t\topts->strategy = xstrdup(value);\n +\t\t}\n  \t}\n  \telse if (!strcmp(key, \"options.gpg-sign\")) {\n -\t\tgit_config_string(&opts->gpg_sign, key, value);\n -\t\tsequencer_entrust(opts, (char *) opts->gpg_sign);\n +\t\tif (!value)\n +\t\t\tconfig_error_nonbool(key);\n +\t\telse {\n +\t\t\tfree(opts->gpg_sign);\n +\t\t\topts->gpg_sign = xstrdup(value);\n +\t\t}\n  \t}\n  \telse if (!strcmp(key, \"options.strategy-option\")) {\n  \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n -\t\topts->xopts[opts->xopts_nr++] =\n -\t\t\tsequencer_entrust(opts, xstrdup(value));\n +\t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n  \t} else\n -\t\treturn error(_(\"Invalid key: %s\"), key);\n +\t\treturn error(_(\"invalid key: %s\"), key);\n  \n  \tif (!error_flag)\n -\t\treturn error(_(\"Invalid value for %s: %s\"), key, value);\n +\t\treturn error(_(\"invalid value for %s: %s\"), key, value);\n  \n  \treturn 0;\n  }\n @@ -1030,11 +1050,11 @@ static int read_populate_opts(struct replay_opts *opts)\n  \t\t\tif (!starts_with(buf.buf, \"-S\"))\n  \t\t\t\tstrbuf_reset(&buf);\n  \t\t\telse {\n -\t\t\t\topts->gpg_sign = buf.buf + 2;\n -\t\t\t\tsequencer_entrust(opts,\n -\t\t\t\t\tstrbuf_detach(&buf, NULL));\n +\t\t\t\tfree(opts->gpg_sign);\n +\t\t\t\topts->gpg_sign = xstrdup(buf.buf + 2);\n  \t\t\t}\n  \t\t}\n +\t\tstrbuf_release(&buf);\n  \n  \t\treturn 0;\n  \t}\n @@ -1048,7 +1068,7 @@ static int read_populate_opts(struct replay_opts *opts)\n  \t * are pretty certain that it is syntactically correct.\n  \t */\n  \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n -\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n +\t\treturn error(_(\"malformed options sheet: '%s'\"),\n  \t\t\tgit_path_opts_file());\n  \treturn 0;\n  }\n @@ -1091,7 +1111,7 @@ static int create_seq_dir(void)\n  \t\treturn -1;\n  \t}\n  \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n -\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n +\t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n  \t\t\t\t   git_path_seq_dir());\n  \treturn 0;\n  }\n @@ -1105,17 +1125,17 @@ static int save_head(const char *head)\n  \tfd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);\n  \tif (fd < 0) {\n  \t\trollback_lock_file(&head_lock);\n -\t\treturn error_errno(_(\"Could not lock HEAD\"));\n +\t\treturn error_errno(_(\"could not lock HEAD\"));\n  \t}\n  \tstrbuf_addf(&buf, \"%s\\n\", head);\n  \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n  \t\trollback_lock_file(&head_lock);\n -\t\treturn error_errno(_(\"Could not write to '%s'\"),\n +\t\treturn error_errno(_(\"could not write to '%s'\"),\n  \t\t\t\t   git_path_head_file());\n  \t}\n  \tif (commit_lock_file(&head_lock) < 0) {\n  \t\trollback_lock_file(&head_lock);\n -\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n +\t\treturn error(_(\"failed to finalize '%s'.\"), git_path_head_file());\n  \t}\n  \treturn 0;\n  }\n @@ -1194,14 +1214,14 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n  \n  \tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n  \tif (fd < 0)\n -\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n +\t\treturn error_errno(_(\"could not lock '%s'\"), todo_path);\n  \toffset = next < todo_list->nr ?\n  \t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n  \tif (write_in_full(fd, todo_list->buf.buf + offset,\n  \t\t\ttodo_list->buf.len - offset) < 0)\n -\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n +\t\treturn error_errno(_(\"could not write to '%s'\"), todo_path);\n  \tif (commit_lock_file(&todo_lock) < 0)\n -\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n +\t\treturn error(_(\"failed to finalize '%s'.\"), todo_path);\n  \treturn 0;\n  }\n  \n @@ -1376,7 +1396,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n  \t\t\tcreate_seq_dir() < 0)\n  \t\treturn -1;\n  \tif (get_sha1(\"HEAD\", sha1) && (opts->action == REPLAY_REVERT))\n -\t\treturn error(_(\"Can't revert as initial commit\"));\n +\t\treturn error(_(\"can't revert as initial commit\"));\n  \tif (save_head(sha1_to_hex(sha1)))\n  \t\treturn -1;\n  \tif (save_opts(opts))\n diff --git a/sequencer.h b/sequencer.h\n index 688fff1..7a513c5 100644\n --- a/sequencer.h\n +++ b/sequencer.h\n @@ -26,37 +26,23 @@ struct replay_opts {\n  \n  \tint mainline;\n  \n -\tconst char *gpg_sign;\n +\tchar *gpg_sign;\n  \n  \t/* Merge strategy */\n -\tconst char *strategy;\n -\tconst char **xopts;\n +\tchar *strategy;\n +\tchar **xopts;\n  \tsize_t xopts_nr, xopts_alloc;\n  \n  \t/* Only used by REPLAY_NONE */\n  \tstruct rev_info *revs;\n -\n -\t/* malloc()ed data entrusted to the sequencer */\n -\tvoid **owned;\n -\tint owned_nr, owned_alloc;\n  };\n  #define REPLAY_OPTS_INIT { -1 }\n  \n -/*\n - * Make it the duty of sequencer_remove_state() to release the memory;\n - * For ease of use, return the same pointer.\n - */\n -void *sequencer_entrust(struct replay_opts *opts, void *to_free);\n -\n  int sequencer_pick_revisions(struct replay_opts *opts);\n  int sequencer_continue(struct replay_opts *opts);\n  int sequencer_rollback(struct replay_opts *opts);\n  int sequencer_remove_state(struct replay_opts *opts);\n  \n -int sequencer_commit(const char *defmsg, struct replay_opts *opts,\n -\t\t\t  int allow_empty, int edit, int amend,\n -\t\t\t  int cleanup_commit_message);\n -\n  extern const char sign_off_header[];\n  \n  void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);\n diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh\n index 51f3bbb..394f000 100755\n --- a/t/t3501-revert-cherry-pick.sh\n +++ b/t/t3501-revert-cherry-pick.sh\n @@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '\n  \techo content >extra_file &&\n  \tgit add extra_file &&\n  \ttest_must_fail git revert HEAD 2>errors &&\n -\ttest_i18ngrep \"Your local changes would be overwritten by \" errors\n +\ttest_i18ngrep \"your local changes would be overwritten by \" errors\n  \n  '\n  \n\n-- \n2.10.0.windows.1.325.ge6089c1\n\nbase-commit: a23ca1b8dc42ffd4de2ef30d67ce1e21ded29886\n"},{"id":"303739","messageId":"5c4c86f0ea7ee4a9bad15e48f72b8fe5baa72dfb.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 01/25] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:19Z","receivedAt":"2016-10-10T17:24:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This change is not completely faithful: instead of initializing all fields\nto 0, we choose to initialize command and subcommand to -1 (instead of\ndefaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\nit makes no difference at all, but future-proofs the code to require\nexplicit assignments for both fields.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 6 ++----\n sequencer.h      | 1 +\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4e69380..7365559 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -178,10 +178,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n@@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n \tparse_args(argc, argv, &opts);\ndiff --git a/sequencer.h b/sequencer.h\nindex 5ed5cb1..db425ad 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -47,6 +47,7 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n+#define REPLAY_OPTS_INIT { -1, -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303740","messageId":"76b7d1bce59681f84ca91db2f87bd38b74072e48.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 02/25] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:25Z","receivedAt":"2016-10-10T17:25:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/commit.c |  2 +-\n sequencer.c      | 11 ++++++-----\n sequencer.h      |  5 +----\n 3 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1cba3b7..9fddb19 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)\n \t\twhence = FROM_MERGE;\n \telse if (file_exists(git_path_cherry_pick_head())) {\n \t\twhence = FROM_CHERRY_PICK;\n-\t\tif (file_exists(git_path(SEQ_DIR)))\n+\t\tif (file_exists(git_path_seq_dir()))\n \t\t\tsequencer_in_use = 1;\n \t}\n \telse\ndiff --git a/sequencer.c b/sequencer.c\nindex eec8a60..cb16cbd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -21,10 +21,11 @@\n const char sign_off_header[] = \"Signed-off-by: \";\n static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n \n-static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n-static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n-static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n-static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n+GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n+\n+static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n+static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n+static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n static int is_rfc2822_line(const char *buf, int len)\n {\n@@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n+\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n \tremove_dir_recursively(&seq_dir, 0);\n \tstrbuf_release(&seq_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex db425ad..dd4d33a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -1,10 +1,7 @@\n #ifndef SEQUENCER_H\n #define SEQUENCER_H\n \n-#define SEQ_DIR\t\t\"sequencer\"\n-#define SEQ_HEAD_FILE\t\"sequencer/head\"\n-#define SEQ_TODO_FILE\t\"sequencer/todo\"\n-#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n+const char *git_path_seq_dir(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303741","messageId":"ccfa46aba51d553ce3841f9e9a2466c2174b12f5.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:53Z","receivedAt":"2016-10-10T17:25:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In a couple of commits, we will teach the sequencer to handle the\nnitty gritty of the interactive rebase, which keeps its state in a\ndifferent directory.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c2fbf6f..8d272fb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,11 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+static const char *get_dir(const struct replay_opts *opts)\n+{\n+\treturn git_path_seq_dir();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -109,13 +114,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(void)\n+static void remove_sequencer_state(const struct replay_opts *opts)\n {\n-\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n-\tremove_dir_recursively(&seq_dir, 0);\n-\tstrbuf_release(&seq_dir);\n+\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -940,7 +945,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n \treturn 0;\n fail:\n@@ -1034,7 +1039,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \treturn 0;\n }\n \n@@ -1095,7 +1100,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t * one that is being continued\n \t */\n \tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(opts);\n \t\treturn 0;\n \t}\n \tif (opts->subcommand == REPLAY_ROLLBACK)\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303742","messageId":"336cefca0bda214b5b43b1094af13d787d1a79e3.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 03/25] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:30Z","receivedAt":"2016-10-10T17:25:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We really do not need the *pointer to a* pointer to the options in\nthe read_populate_opts() function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb16cbd..c2fbf6f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -813,7 +813,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static int read_populate_opts(struct replay_opts **opts)\n+static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n@@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n \t * about this case, though, because we wrote that file ourselves, so we\n \t * are pretty certain that it is syntactically correct.\n \t */\n-\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n+\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n \t\treturn error(_(\"Malformed options sheet: %s\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n@@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n \n \tif (!file_exists(git_path_todo_file()))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(&opts) ||\n+\tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n \t\treturn -1;\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303743","messageId":"a67af02ef363311b526bddba864c7f1ca9087b43.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:56Z","receivedAt":"2016-10-10T17:25:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\nlike a one-shot command when it reads its configuration: memory is\nallocated and released only when the command exits.\n\nThis is kind of okay for git-cherry-pick, which *is* a one-shot\ncommand. All the work to make the sequencer its work horse was\ndone to allow using the functionality as a library function, though,\nincluding proper clean-up after use.\n\nTo remedy that, we now take custody of the option values in question,\nrequiring those values to be malloc()ed or strdup()ed (an alternative\napproach, to add a list of pointers to malloc()ed data and to ask the\nsequencer to release all of them in the end, was proposed earlier but\nrejected during review).\n\nSadly, the current approach makes the code uglier, as we now have to\ntake care to strdup() the values passed via the command-line.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c |  6 ++++++\n sequencer.c      | 32 ++++++++++++++++++++++++++------\n sequencer.h      |  6 +++---\n 3 files changed, 35 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 7365559..fce9c75 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -174,6 +174,12 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n \tif (argc > 1)\n \t\tusage_with_options(usage_str, options);\n+\n+\t/* These option values will be free()d */\n+\tif (opts->gpg_sign)\n+\t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n+\tif (opts->strategy)\n+\t\topts->strategy = xstrdup(opts->strategy);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d272fb..22c31c8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -117,6 +117,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n static void remove_sequencer_state(const struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n+\tint i;\n+\n+\tfree(opts->gpg_sign);\n+\tfree(opts->strategy);\n+\tfor (i = 0; i < opts->xopts_nr; i++)\n+\t\tfree(opts->xopts[i]);\n+\tfree(opts->xopts);\n \n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n@@ -280,7 +287,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \tstruct merge_options o;\n \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n \tint clean;\n-\tconst char **xopt;\n+\tchar **xopt;\n \tstatic struct lock_file index_lock;\n \n \thold_locked_index(&index_lock, 1);\n@@ -583,7 +590,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-\t\tres |= try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,\n+\t\tres |= try_merge_command(opts->strategy,\n+\t\t\t\t\t opts->xopts_nr, (const char **)opts->xopts,\n \t\t\t\t\tcommon, sha1_to_hex(head), remotes);\n \t\tfree_commit_list(common);\n \t\tfree_commit_list(remotes);\n@@ -802,10 +810,22 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n \telse if (!strcmp(key, \"options.mainline\"))\n \t\topts->mainline = git_config_int(key, value);\n-\telse if (!strcmp(key, \"options.strategy\"))\n-\t\tgit_config_string(&opts->strategy, key, value);\n-\telse if (!strcmp(key, \"options.gpg-sign\"))\n-\t\tgit_config_string(&opts->gpg_sign, key, value);\n+\telse if (!strcmp(key, \"options.strategy\")) {\n+\t\tif (!value)\n+\t\t\tconfig_error_nonbool(key);\n+\t\telse {\n+\t\t\tfree(opts->strategy);\n+\t\t\topts->strategy = xstrdup(value);\n+\t\t}\n+\t}\n+\telse if (!strcmp(key, \"options.gpg-sign\")) {\n+\t\tif (!value)\n+\t\t\tconfig_error_nonbool(key);\n+\t\telse {\n+\t\t\tfree(opts->gpg_sign);\n+\t\t\topts->gpg_sign = xstrdup(value);\n+\t\t}\n+\t}\n \telse if (!strcmp(key, \"options.strategy-option\")) {\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\ndiff --git a/sequencer.h b/sequencer.h\nindex dd4d33a..8453669 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -34,11 +34,11 @@ struct replay_opts {\n \n \tint mainline;\n \n-\tconst char *gpg_sign;\n+\tchar *gpg_sign;\n \n \t/* Merge strategy */\n-\tconst char *strategy;\n-\tconst char **xopts;\n+\tchar *strategy;\n+\tchar **xopts;\n \tsize_t xopts_nr, xopts_alloc;\n \n \t/* Only used by REPLAY_NONE */\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303744","messageId":"4e73ba3e8c1700259ffcc3224d1f66e6a760142d.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:07Z","receivedAt":"2016-10-10T17:25:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When we came up with the \"sequencer\" idea, we really wanted to have\nkind of a plumbing equivalent of the interactive rebase. Hence the\nchoice of words: the \"todo\" script, a \"pick\", etc.\n\nHowever, when it came time to implement the entire shebang, somehow this\nidea got lost and the sequencer was used as working horse for\ncherry-pick and revert instead. So as not to interfere with the\ninteractive rebase, it even uses a separate directory to store its\nstate.\n\nFurthermore, it also is stupidly strict about the \"todo\" script it\naccepts: while it parses commands in a way that was *designed* to be\nsimilar to the interactive rebase, it then goes on to *error out* if the\ncommands disagree with the overall action (cherry-pick or revert).\n\nFinally, the sequencer code chose to deviate from the interactive rebase\ncode insofar that when it comes to writing the file with the remaining\ncommands, it *reformats* the \"todo\" script instead of just writing the\npart of the parsed script that were not yet processed. This is not only\nunnecessary churn, but might well lose information that is valuable to\nthe user (i.e. comments after the commands).\n\nLet's just bite the bullet and rewrite the entire parser; the code now\nbecomes not only more elegant: it allows us to go on and teach the\nsequencer how to parse *true* \"todo\" scripts as used by the interactive\nrebase itself. In a way, the sequencer is about to grow up to do its\nolder brother's job. Better.\n\nIn particular, we choose to maintain the list of commands in an array\ninstead of a linked list: this is flexible enough to allow us later on to\neven implement rebase -i's reordering of fixup!/squash! commits very\neasily (and with a very nice speed bonus, at least on Windows).\n\nWhile at it, do not stop at the first problem, but list *all* of the\nproblems. This will help the user when the sequencer will do `rebase\n-i`'s work by allowing to address all issues in one go rather than going\nback and forth until the todo list is valid.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 288 +++++++++++++++++++++++++++++++++++-------------------------\n 1 file changed, 167 insertions(+), 121 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 4e00c5e..678fdf3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -465,7 +465,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \t\treturn 1;\n }\n \n-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n+enum todo_command {\n+\tTODO_PICK = 0,\n+\tTODO_REVERT\n+};\n+\n+static const char *todo_command_strings[] = {\n+\t\"pick\",\n+\t\"revert\"\n+};\n+\n+static const char *command_to_string(const enum todo_command command)\n+{\n+\tif (command < ARRAY_SIZE(todo_command_strings))\n+\t\treturn todo_command_strings[command];\n+\tdie(\"Unknown command: %d\", command);\n+}\n+\n+\n+static int do_pick_commit(enum todo_command command, struct commit *commit,\n+\t\tstruct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -524,10 +543,13 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n \n \tif (parent && parse_commit(parent) < 0)\n-\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n-\t\t   \"cherry-pick\", the second %s a SHA1 */\n+\t\t/*\n+\t\t * TRANSLATORS: The first %s will be a \"todo\" command like\n+\t\t * \"revert\" or \"pick\", the second %s a SHA1.\n+\t\t */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n-\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n+\t\t\tcommand_to_string(command),\n+\t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n@@ -540,7 +562,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * reverse of it if we are revert.\n \t */\n \n-\tif (opts->action == REPLAY_REVERT) {\n+\tif (command == TODO_REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -581,7 +603,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t}\n \t}\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n@@ -608,17 +630,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * However, if the merge did not even start, then we don't want to\n \t * write it at all.\n \t */\n-\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n+\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n-\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n+\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n \n \tif (res) {\n-\t\terror(opts->action == REPLAY_REVERT\n+\t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n \t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n@@ -680,116 +702,122 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n-\t\tstruct replay_opts *opts)\n+struct todo_item {\n+\tenum todo_command command;\n+\tstruct commit *commit;\n+\tsize_t offset_in_buf;\n+};\n+\n+struct todo_list {\n+\tstruct strbuf buf;\n+\tstruct todo_item *items;\n+\tint nr, alloc, current;\n+};\n+\n+#define TODO_LIST_INIT { STRBUF_INIT }\n+\n+static void todo_list_release(struct todo_list *todo_list)\n {\n-\tstruct commit_list *cur = NULL;\n-\tconst char *sha1_abbrev = NULL;\n-\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n-\tconst char *subject;\n-\tint subject_len;\n+\tstrbuf_release(&todo_list->buf);\n+\tfree(todo_list->items);\n+\ttodo_list->items = NULL;\n+\ttodo_list->nr = todo_list->alloc = 0;\n+}\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n-\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n-\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n-\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n-\t\t\tsubject_len, subject);\n-\t\tunuse_commit_buffer(cur->item, commit_buffer);\n-\t}\n-\treturn 0;\n+struct todo_item *append_new_todo(struct todo_list *todo_list)\n+{\n+\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n+\treturn todo_list->items + todo_list->nr++;\n }\n \n-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n {\n \tunsigned char commit_sha1[20];\n-\tenum replay_action action;\n \tchar *end_of_object_name;\n-\tint saved, status, padding;\n-\n-\tif (starts_with(bol, \"pick\")) {\n-\t\taction = REPLAY_PICK;\n-\t\tbol += strlen(\"pick\");\n-\t} else if (starts_with(bol, \"revert\")) {\n-\t\taction = REPLAY_REVERT;\n-\t\tbol += strlen(\"revert\");\n-\t} else\n-\t\treturn NULL;\n+\tint i, saved, status, padding;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n+\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n+\t\t\titem->command = i;\n+\t\t\tbreak;\n+\t\t}\n+\tif (i >= ARRAY_SIZE(todo_command_strings))\n+\t\treturn -1;\n \n \t/* Eat up extra spaces/ tabs before object name */\n \tpadding = strspn(bol, \" \\t\");\n \tif (!padding)\n-\t\treturn NULL;\n+\t\treturn -1;\n \tbol += padding;\n \n-\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n+\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n \tsaved = *end_of_object_name;\n \t*end_of_object_name = '\\0';\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n-\t/*\n-\t * Verify that the action matches up with the one in\n-\t * opts; we don't support arbitrary instructions\n-\t */\n-\tif (action != opts->action) {\n-\t\tif (action == REPLAY_REVERT)\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot revert during another revert.\")\n-\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n-\t\telse\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n-\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n-\t\treturn NULL;\n-\t}\n-\n \tif (status < 0)\n-\t\treturn NULL;\n+\t\treturn -1;\n \n-\treturn lookup_commit_reference(commit_sha1);\n+\titem->commit = lookup_commit_reference(commit_sha1);\n+\treturn !item->commit;\n }\n \n-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n-\t\t\tstruct replay_opts *opts)\n+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n {\n-\tstruct commit_list **next = todo_list;\n-\tstruct commit *commit;\n-\tchar *p = buf;\n-\tint i;\n+\tstruct todo_item *item;\n+\tchar *p = buf, *next_p;\n+\tint i, res = 0;\n \n-\tfor (i = 1; *p; i++) {\n+\tfor (i = 1; *p; i++, p = next_p) {\n \t\tchar *eol = strchrnul(p, '\\n');\n-\t\tcommit = parse_insn_line(p, eol, opts);\n-\t\tif (!commit)\n-\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n-\t\tnext = commit_list_append(commit, next);\n-\t\tp = *eol ? eol + 1 : eol;\n+\n+\t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n+\n+\t\titem = append_new_todo(todo_list);\n+\t\titem->offset_in_buf = p - todo_list->buf.buf;\n+\t\tif (parse_insn_line(item, p, eol)) {\n+\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\t\ti, (int)(eol - p), p);\n+\t\t\titem->command = -1;\n+\t\t}\n \t}\n-\tif (!*todo_list)\n+\tif (!todo_list->nr)\n \t\treturn error(_(\"No commits parsed.\"));\n-\treturn 0;\n+\treturn res;\n }\n \n-static int read_populate_todo(struct commit_list **todo_list,\n+static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n \tconst char *todo_file = get_todo_path(opts);\n-\tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n+\tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n-\tif (strbuf_read(&buf, fd, 0) < 0) {\n+\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\tstrbuf_release(&buf);\n \t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n-\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n-\tstrbuf_release(&buf);\n+\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n+\tif (!res) {\n+\t\tenum todo_command valid =\n+\t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < todo_list->nr; i++)\n+\t\t\tif (valid == todo_list->items[i].command)\n+\t\t\t\tcontinue;\n+\t\t\telse if (valid == TODO_PICK)\n+\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\telse\n+\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t}\n+\n \tif (res)\n \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n@@ -858,18 +886,33 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int walk_revs_populate_todo(struct commit_list **todo_list,\n+static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n+\tenum todo_command command = opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT;\n+\tconst char *command_string = todo_command_strings[command];\n \tstruct commit *commit;\n-\tstruct commit_list **next;\n \n \tif (prepare_revs(opts))\n \t\treturn -1;\n \n-\tnext = todo_list;\n-\twhile ((commit = get_revision(opts->revs)))\n-\t\tnext = commit_list_append(commit, next);\n+\twhile ((commit = get_revision(opts->revs))) {\n+\t\tstruct todo_item *item = append_new_todo(todo_list);\n+\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n+\t\tconst char *subject;\n+\t\tint subject_len;\n+\n+\t\titem->command = command;\n+\t\titem->commit = commit;\n+\t\titem->offset_in_buf = todo_list->buf.len;\n+\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n+\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n+\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n+\t\t\t\tDEFAULT_ABBREV),\n+\t\t\tsubject_len, subject);\n+\t\tunuse_commit_buffer(commit, commit_buffer);\n+\t}\n \treturn 0;\n }\n \n@@ -977,30 +1020,22 @@ static int sequencer_rollback(struct replay_opts *opts)\n \treturn -1;\n }\n \n-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstatic struct lock_file todo_lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint fd;\n+\tconst char *todo_path = get_todo_path(opts);\n+\tint next = todo_list->current, offset, fd;\n \n-\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n+\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"),\n-\t\t\t\t   git_path_todo_file());\n-\tif (format_todo(&buf, todo_list, opts) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n-\t}\n-\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n-\t\t\t\t   git_path_todo_file());\n-\t}\n-\tif (commit_lock_file(&todo_lock) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n-\t}\n-\tstrbuf_release(&buf);\n+\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\toffset = next < todo_list->nr ?\n+\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n+\tif (write_in_full(fd, todo_list->buf.buf + offset,\n+\t\t\ttodo_list->buf.len - offset) < 0)\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\tif (commit_lock_file(&todo_lock) < 0)\n+\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1039,9 +1074,8 @@ static int save_opts(struct replay_opts *opts)\n \treturn res;\n }\n \n-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *cur;\n \tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n@@ -1051,10 +1085,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tif (save_todo(cur, opts))\n+\twhile (todo_list->current < todo_list->nr) {\n+\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n+\t\tif (save_todo(todo_list, opts))\n \t\t\treturn -1;\n-\t\tres = do_pick_commit(cur->item, opts);\n+\t\tres = do_pick_commit(item->command, item->commit, opts);\n+\t\ttodo_list->current++;\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -1079,38 +1115,46 @@ static int continue_single_pick(void)\n \n static int sequencer_continue(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n \n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(opts) ||\n-\t\t\tread_populate_todo(&todo_list, opts))\n+\tif (read_populate_opts(opts))\n \t\treturn -1;\n+\tif ((res = read_populate_todo(&todo_list, opts)))\n+\t\tgoto release_todo_list;\n \n \t/* Verify that the conflict has been resolved */\n \tif (file_exists(git_path_cherry_pick_head()) ||\n \t    file_exists(git_path_revert_head())) {\n-\t\tint ret = continue_single_pick();\n-\t\tif (ret)\n-\t\t\treturn ret;\n+\t\tres = continue_single_pick();\n+\t\tif (res)\n+\t\t\tgoto release_todo_list;\n \t}\n-\tif (index_differs_from(\"HEAD\", 0))\n-\t\treturn error_dirty_index(opts);\n-\ttodo_list = todo_list->next;\n-\treturn pick_commits(todo_list, opts);\n+\tif (index_differs_from(\"HEAD\", 0)) {\n+\t\tres = error_dirty_index(opts);\n+\t\tgoto release_todo_list;\n+\t}\n+\ttodo_list.current++;\n+\tres = pick_commits(&todo_list, opts);\n+release_todo_list:\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n static int single_pick(struct commit *cmit, struct replay_opts *opts)\n {\n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(cmit, opts);\n+\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n }\n \n int sequencer_pick_revisions(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n \tunsigned char sha1[20];\n-\tint i;\n+\tint i, res;\n \n \tif (opts->subcommand == REPLAY_NONE)\n \t\tassert(opts->revs);\n@@ -1185,7 +1229,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\treturn -1;\n \tif (save_opts(opts))\n \t\treturn -1;\n-\treturn pick_commits(todo_list, opts);\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303745","messageId":"541259c114f37aac03bea5d8f0d63888bb5a69c6.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 06/25] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:24:59Z","receivedAt":"2016-10-10T17:25:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Over the next commits, we will work on improving the sequencer to the\npoint where it can process the todo script of an interactive rebase. To\nthat end, we will need to teach the sequencer to read interactive\nrebase's todo file. In preparation, we consolidate all places where\nthat todo file is needed to call a function that we will later extend.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 22c31c8..4e00c5e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n \treturn git_path_seq_dir();\n }\n \n+static const char *get_todo_path(const struct replay_opts *opts)\n+{\n+\treturn git_path_todo_file();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -769,25 +774,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n static int read_populate_todo(struct commit_list **todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n+\tconst char *todo_file = get_todo_path(opts);\n \tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n-\tfd = open(git_path_todo_file(), O_RDONLY);\n+\tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"),\n-\t\t\t\t   git_path_todo_file());\n+\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n \tif (strbuf_read(&buf, fd, 0) < 0) {\n \t\tclose(fd);\n \t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n+\t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n \tstrbuf_release(&buf);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n-\t\t\tgit_path_todo_file());\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n@@ -1077,7 +1081,7 @@ static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n \n-\tif (!file_exists(git_path_todo_file()))\n+\tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303746","messageId":"5a639610c09bf1dacc8143603f321a8ea23cd270.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 08/25] sequencer: strip CR from the todo script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:11Z","receivedAt":"2016-10-10T17:25:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"It is not unheard of that editors on Windows write CR/LF even if the\nfile originally had only LF. This is particularly awkward for exec lines\nof a rebase -i todo sheet. Take for example the insn \"exec echo\": The\nshell script parser splits at the LF and leaves the CR attached to\n\"echo\", which leads to the unknown command \"echo\\r\".\n\nWork around that by stripping CR when reading the todo commands, as we\nalready do for LF.\n\nThis happens to fix t9903.14 and .15 in MSYS1 environments (with the\nrebase--helper patches based on this patch series): the todo script\nconstructed in such a setup contains CR/LF thanks to MSYS1 runtime's\ncleverness.\n\nBased on a report and a patch by Johannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 678fdf3..cee7e50 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -774,6 +774,9 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \n \t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n \n+\t\tif (p != eol && eol[-1] == '\\r')\n+\t\t\teol--; /* skip Carriage Return */\n+\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303747","messageId":"0244a3f187fed257c96d33c0d6fec705215769f6.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 11/25] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:35Z","receivedAt":"2016-10-10T17:26:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Not only does this DRY up the code (providing a better documentation what\nthe code is about, as well as allowing to change the behavior in a single\nplace), it also makes it substantially shorter to use the same\nfunctionality in functions to be introduced when we teach the sequencer to\nprocess interactive-rebase's git-rebase-todo file.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 14b1746..afc494e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -149,13 +149,18 @@ struct commit_message {\n \tconst char *message;\n };\n \n+static const char *short_commit_name(struct commit *commit)\n+{\n+\treturn find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+}\n+\n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n \tint subject_len;\n \n \tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n-\tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+\tabbrev = short_commit_name(commit);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n@@ -642,8 +647,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n-\t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n-\t\t      msg.subject);\n+\t\t      short_commit_name(commit), msg.subject);\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t\tgoto leave;\n@@ -910,9 +914,7 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n-\t\t\t\tDEFAULT_ABBREV),\n-\t\t\tsubject_len, subject);\n+\t\t\tshort_commit_name(commit), subject_len, subject);\n \t\tunuse_commit_buffer(commit, commit_buffer);\n \t}\n \treturn 0;\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303748","messageId":"1b7c940b274e1ac0887ea310ee4d629b8b6b200f.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 09/25] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:14Z","receivedAt":"2016-10-10T17:26:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cee7e50..443a238 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -224,11 +224,8 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(action_name(opts));\n \n-\t/* Different translation strings for cherry-pick and revert */\n-\tif (opts->action == REPLAY_PICK)\n-\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n-\telse\n-\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n+\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\t\taction_name(opts));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303749","messageId":"f22bdcda3f748813e6b9fd08dc65f11c6f9f4b1e.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:38Z","receivedAt":"2016-10-10T17:26:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The `git-rebase-todo` file contains a list of commands. Most of those\ncommands have the form\n\n\t<verb> <sha1> <oneline>\n\nThe <oneline> is displayed primarily for the user's convenience, as\nrebase -i really interprets only the <verb> <sha1> part. However, there\nare *some* places in interactive rebase where the <oneline> is used to\ndisplay messages, e.g. for reporting at which commit we stopped.\n\nSo let's just remember it when parsing the todo file; we keep a copy of\nthe entire todo file anyway (to write out the new `done` and\n`git-rebase-todo` file just before processing each command), so all we\nneed to do is remember the begin offsets and lengths.\n\nAs we will have to parse and remember the command-line for `exec` commands\nlater, we do not call the field \"oneline\" but rather \"arg\" (and will reuse\nthat for exec's command-line).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex afc494e..7ba5e07 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -708,6 +708,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n struct todo_item {\n \tenum todo_command command;\n \tstruct commit *commit;\n+\tconst char *arg;\n+\tint arg_len;\n \tsize_t offset_in_buf;\n };\n \n@@ -759,6 +761,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n+\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n+\titem->arg_len = (int)(eol - item->arg);\n+\n \tif (status < 0)\n \t\treturn -1;\n \n@@ -911,6 +916,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \n \t\titem->command = command;\n \t\titem->commit = commit;\n+\t\titem->arg = NULL;\n+\t\titem->arg_len = 0;\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303750","messageId":"b554346c600fafa71d2a3461fda8402e377b596e.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:47Z","receivedAt":"2016-10-10T17:26:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As we are slowly teaching the sequencer to perform the hard work for\nthe interactive rebase, we need to read files that were written by\nshell scripts.\n\nThese files typically contain a single line and are invariably ended\nby a line feed (and possibly a carriage return before that). Let's use\na helper to read such files and to remove the line ending.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 31 +++++++++++++++++++++++++++++++\n 1 file changed, 31 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b694ace..681552a 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,6 +234,37 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \treturn 0;\n }\n \n+/*\n+ * Reads a file that was presumably written by a shell script, i.e.\n+ * with an end-of-line marker that needs to be stripped.\n+ *\n+ * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n+ */\n+static int read_oneliner(struct strbuf *buf,\n+\tconst char *path, int skip_if_empty)\n+{\n+\tint orig_len = buf->len;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (strbuf_read_file(buf, path, 0) < 0) {\n+\t\twarning_errno(_(\"could not read '%s'\"), path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n+\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n+\t\t\t--buf->len;\n+\t\tbuf->buf[buf->len] = '\\0';\n+\t}\n+\n+\tif (skip_if_empty && buf->len == orig_len)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static struct tree *empty_tree(void)\n {\n \treturn lookup_tree(EMPTY_TREE_SHA1_BIN);\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303751","messageId":"9b2782e64f678ab2d261042b63fafc3e4a519295.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:44Z","receivedAt":"2016-10-10T17:26:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In interactive rebases, we commit a little bit differently than the\nsequencer did so far: we heed the \"author-script\", the \"message\" and the\n\"amend\" files in the .git/rebase-merge/ subdirectory.\n\nLikewise, we may want to edit the commit message *even* when providing a\nfile containing the suggested commit message. Therefore we change the\ncode to not even provide a default message when we do not want any, and\nto call the editor explicitly.\n\nAlso, in \"interactive rebase\" mode we want to skip reading the options\nin the state directory of the cherry-pick/revert commands.\n\nFinally, as interactive rebase's GPG settings are configured differently\nfrom how cherry-pick (and therefore sequencer) handles them, we will\nleave support for that to the next commit.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 89 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 7ba5e07..b694ace 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+/*\n+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n+ * GIT_AUTHOR_DATE that will be used for the commit that is currently\n+ * being rebased.\n+ */\n+static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+\n+/* We will introduce the 'interactive rebase' mode later */\n+static inline int is_rebase_i(const struct replay_opts *opts)\n+{\n+\treturn 0;\n+}\n+\n static const char *get_dir(const struct replay_opts *opts)\n {\n \treturn git_path_seq_dir();\n@@ -370,19 +383,79 @@ static int is_index_unchanged(void)\n }\n \n /*\n+ * Read the author-script file into an environment block, ready for use in\n+ * run_command(), that can be free()d afterwards.\n+ */\n+static char **read_author_script(void)\n+{\n+\tstruct strbuf script = STRBUF_INIT;\n+\tint i, count = 0;\n+\tchar *p, *p2, **env;\n+\tsize_t env_size;\n+\n+\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n+\t\treturn NULL;\n+\n+\tfor (p = script.buf; *p; p++)\n+\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n+\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n+\t\telse if (*p == '\\'')\n+\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n+\t\telse if (*p == '\\n') {\n+\t\t\t*p = '\\0';\n+\t\t\tcount++;\n+\t\t}\n+\n+\tenv_size = (count + 1) * sizeof(*env);\n+\tstrbuf_grow(&script, env_size);\n+\tmemmove(script.buf + env_size, script.buf, script.len);\n+\tp = script.buf + env_size;\n+\tenv = (char **)strbuf_detach(&script, NULL);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tenv[i] = p;\n+\t\tp += strlen(p) + 1;\n+\t}\n+\tenv[count] = NULL;\n+\n+\treturn env;\n+}\n+\n+/*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n  * author date and name.\n+ *\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n+ *\n+ * An exception is when run_git_commit() is called during an\n+ * interactive rebase: in that case, we will want to retain the\n+ * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\t\t  int allow_empty)\n {\n+\tchar **env = NULL;\n \tstruct argv_array array;\n \tint rc;\n \tconst char *value;\n \n+\tif (is_rebase_i(opts)) {\n+\t\tenv = read_author_script();\n+\t\tif (!env)\n+\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\t\t\"tree. If these changes are meant to be\\n\"\n+\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n+\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"If they are meant to go into a new commit, \"\n+\t\t\t\t\"run:\\n\\n\"\n+\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"In both cases, once you're done, continue \"\n+\t\t\t\t\"with:\\n\\n\"\n+\t\t\t\t\"  git rebase --continue\\n\");\n+\t}\n+\n \targv_array_init(&array);\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n@@ -391,14 +464,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n \t\targv_array_push(&array, \"-s\");\n-\tif (!opts->edit) {\n-\t\targv_array_push(&array, \"-F\");\n-\t\targv_array_push(&array, defmsg);\n-\t\tif (!opts->signoff &&\n-\t\t    !opts->record_origin &&\n-\t\t    git_config_get_value(\"commit.cleanup\", &value))\n-\t\t\targv_array_push(&array, \"--cleanup=verbatim\");\n-\t}\n+\tif (defmsg)\n+\t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (opts->edit)\n+\t\targv_array_push(&array, \"-e\");\n+\telse if (!opts->signoff && !opts->record_origin &&\n+\t\t git_config_get_value(\"commit.cleanup\", &value))\n+\t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n \tif (allow_empty)\n \t\targv_array_push(&array, \"--allow-empty\");\n@@ -406,8 +478,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&array, \"--allow-empty-message\");\n \n-\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\trc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,\n+\t\t\t(const char *const *)env);\n \targv_array_clear(&array);\n+\tfree(env);\n+\n \treturn rc;\n }\n \n@@ -659,7 +734,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = run_git_commit(git_path_merge_msg(), opts, allow);\n+\t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\t\t\t     opts, allow);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -883,6 +959,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n+\tif (is_rebase_i(opts))\n+\t\treturn 0;\n+\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n \t/*\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303752","messageId":"0577f66a108dced07775e10b87292c0eabfcc514.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 15/25] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:50Z","receivedAt":"2016-10-10T17:26:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In the upcoming commits, we will implement more and more of rebase -i's\nfunctionality inside the sequencer. One particular feature of the\ncommands to come is that some of them allow editing the commit message\nwhile others don't, i.e. we cannot define in the replay_opts whether the\ncommit message should be edited or not.\n\nLet's add a new parameter to the run_git_commit() function. Previously,\nit was the duty of the caller to ensure that the opts->edit setting\nindicates whether to let the user edit the commit message or not,\nindicating that it is an \"all or nothing\" setting, i.e. that the\nsequencer wants to let the user edit *all* commit message, or none at\nall. In the upcoming rebase -i mode, it will depend on the particular\ncommand that is currently executed, though.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 48 ++++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 40 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 681552a..b621f4b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -15,6 +15,7 @@\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n #include \"argv-array.h\"\n+#include \"quote.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n  * being rebased.\n  */\n static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+/*\n+ * The following files are written by git-rebase just after parsing the\n+ * command-line (and are only consumed, not modified, by the sequencer).\n+ */\n+static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n \n /* We will introduce the 'interactive rebase' mode later */\n static inline int is_rebase_i(const struct replay_opts *opts)\n@@ -132,6 +138,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n+{\n+\tstatic struct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_reset(&buf);\n+\tif (opts->gpg_sign)\n+\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n+\treturn buf.buf;\n+}\n+\n int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n@@ -465,7 +481,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty)\n+\t\t\t  int allow_empty, int edit)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -474,17 +490,20 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tif (is_rebase_i(opts)) {\n \t\tenv = read_author_script();\n-\t\tif (!env)\n+\t\tif (!env) {\n+\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\n \t\t\treturn error(\"You have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit --amend %s\\n\\n\"\n \t\t\t\t\"If they are meant to go into a new commit, \"\n \t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit %s\\n\\n\"\n \t\t\t\t\"In both cases, once you're done, continue \"\n \t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\");\n+\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t}\n \t}\n \n \targv_array_init(&array);\n@@ -497,7 +516,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n-\tif (opts->edit)\n+\tif (edit)\n \t\targv_array_push(&array, \"-e\");\n \telse if (!opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n@@ -766,7 +785,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow);\n+\t\t\t\t     opts, allow, opts->edit);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -990,8 +1009,21 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n-\tif (is_rebase_i(opts))\n+\tif (is_rebase_i(opts)) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n+\t\t\tif (!starts_with(buf.buf, \"-S\"))\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\telse {\n+\t\t\t\tfree(opts->gpg_sign);\n+\t\t\t\topts->gpg_sign = xstrdup(buf.buf + 2);\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\n \t\treturn 0;\n+\t}\n \n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303753","messageId":"08ddd5f5ba1a9829cdeb09da834b8d71664de19d.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 10/25] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:32Z","receivedAt":"2016-10-10T17:26:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The subcommands are used exactly once, at the very beginning of\nsequencer_pick_revisions(), to determine what to do. This is an\nunnecessary level of indirection: we can simply call the correct\nfunction to begin with. So let's do that.\n\nWhile at it, ensure that the subcommands return an error code so that\nthey do not have to die() all over the place (bad practice for library\nfunctions...).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 36 ++++++++++++++++--------------------\n sequencer.c      | 35 +++++++++++------------------------\n sequencer.h      | 13 ++++---------\n 3 files changed, 31 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex fce9c75..0a7b5f4 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \t\tdie(_(\"%s: %s cannot be used with %s\"), me, this_opt, base_opt);\n }\n \n-static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n+static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tconst char *me = action_name(opts);\n@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n-\t/* Set the subcommand */\n-\tif (cmd == 'q')\n-\t\topts->subcommand = REPLAY_REMOVE_STATE;\n-\telse if (cmd == 'c')\n-\t\topts->subcommand = REPLAY_CONTINUE;\n-\telse if (cmd == 'a')\n-\t\topts->subcommand = REPLAY_ROLLBACK;\n-\telse\n-\t\topts->subcommand = REPLAY_NONE;\n-\n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\tchar *this_operation;\n-\t\tif (opts->subcommand == REPLAY_REMOVE_STATE)\n+\t\tif (cmd == 'q')\n \t\t\tthis_operation = \"--quit\";\n-\t\telse if (opts->subcommand == REPLAY_CONTINUE)\n+\t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n \t\telse {\n-\t\t\tassert(opts->subcommand == REPLAY_ROLLBACK);\n+\t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n \t\t}\n \n@@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--edit\", opts->edit,\n \t\t\t\tNULL);\n \n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\topts->revs = NULL;\n \t} else {\n \t\tstruct setup_revision_opt s_r_opt;\n@@ -180,6 +170,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n \tif (opts->strategy)\n \t\topts->strategy = xstrdup(opts->strategy);\n+\n+\tif (cmd == 'q')\n+\t\treturn sequencer_remove_state(opts);\n+\tif (cmd == 'c')\n+\t\treturn sequencer_continue(opts);\n+\tif (cmd == 'a')\n+\t\treturn sequencer_rollback(opts);\n+\treturn sequencer_pick_revisions(opts);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n@@ -191,8 +189,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -205,8 +202,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\ndiff --git a/sequencer.c b/sequencer.c\nindex 443a238..14b1746 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -119,7 +119,7 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(const struct replay_opts *opts)\n+int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tint i;\n@@ -133,6 +133,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n+\n+\treturn 0;\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -977,7 +979,7 @@ static int rollback_single_pick(void)\n \treturn reset_for_rollback(head_sha1);\n }\n \n-static int sequencer_rollback(struct replay_opts *opts)\n+int sequencer_rollback(struct replay_opts *opts)\n {\n \tFILE *f;\n \tunsigned char sha1[20];\n@@ -1012,9 +1014,8 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n fail:\n \tstrbuf_release(&buf);\n \treturn -1;\n@@ -1099,8 +1100,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state(opts);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n }\n \n static int continue_single_pick(void)\n@@ -1113,11 +1113,14 @@ static int continue_single_pick(void)\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n \n-static int sequencer_continue(struct replay_opts *opts)\n+int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tint res;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts))\n@@ -1156,26 +1159,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tint i, res;\n \n-\tif (opts->subcommand == REPLAY_NONE)\n-\t\tassert(opts->revs);\n-\n+\tassert(opts->revs);\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\t/*\n-\t * Decide what to do depending on the arguments; a fresh\n-\t * cherry-pick should be handled differently from an existing\n-\t * one that is being continued\n-\t */\n-\tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state(opts);\n-\t\treturn 0;\n-\t}\n-\tif (opts->subcommand == REPLAY_ROLLBACK)\n-\t\treturn sequencer_rollback(opts);\n-\tif (opts->subcommand == REPLAY_CONTINUE)\n-\t\treturn sequencer_continue(opts);\n-\n \tfor (i = 0; i < opts->revs->pending.nr; i++) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = opts->revs->pending.objects[i].name;\ndiff --git a/sequencer.h b/sequencer.h\nindex 8453669..7a513c5 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -10,16 +10,8 @@ enum replay_action {\n \tREPLAY_PICK\n };\n \n-enum replay_subcommand {\n-\tREPLAY_NONE,\n-\tREPLAY_REMOVE_STATE,\n-\tREPLAY_CONTINUE,\n-\tREPLAY_ROLLBACK\n-};\n-\n struct replay_opts {\n \tenum replay_action action;\n-\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -44,9 +36,12 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n-#define REPLAY_OPTS_INIT { -1, -1 }\n+#define REPLAY_OPTS_INIT { -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n+int sequencer_continue(struct replay_opts *opts);\n+int sequencer_rollback(struct replay_opts *opts);\n+int sequencer_remove_state(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303754","messageId":"a0e8254fef108586d3c7a660861b5b1ae8d6e788.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 17/25] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:11Z","receivedAt":"2016-10-10T17:26:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The run_git_commit() function already knows how to amend commits, and\nwith this new option, it can also clean up commit messages (i.e. strip\nout commented lines). This is needed to implement rebase -i's 'fixup'\nand 'squash' commands as sequencer commands.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 403a4f0..108bca8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -481,7 +481,8 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend)\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -518,9 +519,12 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (cleanup_commit_message)\n+\t\targv_array_push(&array, \"--cleanup=strip\");\n \tif (edit)\n \t\targv_array_push(&array, \"-e\");\n-\telse if (!opts->signoff && !opts->record_origin &&\n+\telse if (!cleanup_commit_message &&\n+\t\t !opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n \t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n@@ -787,7 +791,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit, 0);\n+\t\t\t\t     opts, allow, opts->edit, 0, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303755","messageId":"c043a4e3eae33dac5b0d1ac802dba14311ab42c9.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 18/25] sequencer: do not try to commit when there were merge conflicts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:14Z","receivedAt":"2016-10-10T17:26:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The return value of do_recursive_merge() may be positive (indicating merge\nconflicts), or 0 (indicating success). It also may be negative, indicating\na fatal error that requires us to abort.\n\nNow, if the return value indicates that there are merge conflicts, we\nshould not try to commit those changes, of course.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 108bca8..23fe7db 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -789,7 +789,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tres = allow;\n \t\tgoto leave;\n \t}\n-\tif (!opts->no_commit)\n+\tif (!res && !opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n \t\t\t\t     opts, allow, opts->edit, 0, 0);\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303756","messageId":"ec146dc2f3a3698bd433bbec4d7ecbab762c1bfb.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 16/25] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:25:53Z","receivedAt":"2016-10-10T17:26:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This teaches the run_git_commit() function to take an argument that will\nallow us to implement \"todo\" commands that need to amend the commit\nmessages (\"fixup\", \"squash\" and \"reword\").\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b621f4b..403a4f0 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -481,7 +481,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit)\n+\t\t\t  int allow_empty, int edit, int amend)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -510,6 +510,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n \n+\tif (amend)\n+\t\targv_array_push(&array, \"--amend\");\n \tif (opts->gpg_sign)\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n@@ -785,7 +787,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit);\n+\t\t\t\t     opts, allow, opts->edit, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303757","messageId":"18eb2ccecb17b05b0742bde38cd10a9719f5a199.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 19/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:17Z","receivedAt":"2016-10-10T17:26:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Interactive rebase's scripts may be indented; we need to handle this\ncase, too, now that we prepare the sequencer to process interactive\nrebases.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 23fe7db..45a3651 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -873,6 +873,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tchar *end_of_object_name;\n \tint i, saved, status, padding;\n \n+\t/* left-trim */\n+\tbol += strspn(bol, \" \\t\");\n+\n \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n \t\t\titem->command = i;\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303758","messageId":"2365ff42eec1c795a4b9caf1f419cd5eb8137965.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 20/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:20Z","receivedAt":"2016-10-10T17:26:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The write_message() function safely writes an strbuf to a file.\nSometimes it is inconvenient to require an strbuf, though: the text to\nbe written may not be stored in a strbuf, or the strbuf should not be\nreleased after writing.\n\nLet's refactor \"safely writing string to a file\" into\nwrite_with_lock_file(), and make write_message() use it. The new\nfunction makes it easy to create new convenience function\nwrite_file_gently(); as some of the upcoming callers of this new\nfunction would want to append a newline character, add a flag for it in\nwrite_file_gently(), and thus in write_with_lock_file().\n\nWhile at it, roll back the locked files in case of failure, as pointed\nout by Hannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 31 ++++++++++++++++++++++++++-----\n 1 file changed, 26 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 45a3651..5cca8d8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,22 +234,43 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(struct strbuf *msgbuf, const char *filename)\n+static int write_with_lock_file(const char *filename,\n+\t\t\t\tconst void *buf, size_t len, int append_eol)\n {\n \tstatic struct lock_file msg_file;\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n-\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tstrbuf_release(msgbuf);\n-\tif (commit_lock_file(&msg_file) < 0)\n+\tif (write_in_full(msg_fd, buf, len) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t}\n+\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t}\n+\tif (commit_lock_file(&msg_file) < 0) {\n+\t\trollback_lock_file(&msg_file);\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t}\n \n \treturn 0;\n }\n \n+static int write_message(struct strbuf *msgbuf, const char *filename)\n+{\n+\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n+\tstrbuf_release(msgbuf);\n+\treturn res;\n+}\n+\n+static int write_file_gently(const char *filename,\n+\t\t\t     const char *text, int append_eol)\n+{\n+\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n+}\n+\n /*\n  * Reads a file that was presumably written by a shell script, i.e.\n  * with an end-of-line marker that needs to be stripped.\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303759","messageId":"5f2a1aacfba5e661d8a3782358a1c651b21d57e8.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 23/25] sequencer: quote filenames in error messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:29Z","receivedAt":"2016-10-10T17:33:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This makes the code consistent by fixing quite a couple of error messages.\n\nSuggested by Jakub Narębski.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 40ef33c..4596540 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -252,7 +252,7 @@ static int write_with_lock_file(const char *filename,\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -963,16 +963,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n+\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read %s.\"), todo_file);\n+\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -1065,7 +1065,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: %s\"),\n+\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1108,7 +1108,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory %s\"),\n+\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1127,12 +1127,12 @@ static int save_head(const char *head)\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n+\t\treturn error_errno(_(\"Could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_head_file());\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1177,9 +1177,9 @@ int sequencer_rollback(struct replay_opts *opts)\n \t\treturn rollback_single_pick();\n \t}\n \tif (!f)\n-\t\treturn error_errno(_(\"cannot open %s\"), git_path_head_file());\n+\t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n \tif (strbuf_getline_lf(&buf, f)) {\n-\t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n+\t\terror(_(\"cannot read '%s': %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\n \t\tgoto fail;\n@@ -1218,7 +1218,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t\ttodo_list->buf.len - offset) < 0)\n \t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n \treturn 0;\n }\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n"},{"id":"303760","messageId":"499955168c1da6240c32d6d12786f35ecc1cd048.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 24/25] sequencer: start error messages consistently with lower case","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:32Z","receivedAt":"2016-10-10T17:33:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Quite a few error messages touched by this developer during the work to\nspeed up rebase -i started with an upper case letter, violating our\ncurrent conventions. Instead of sneaking in this fix (and forgetting\nquite a few error messages), let's just have one wholesale patch fixing\nall of the error messages in the sequencer.\n\nWhile at it, the funny \"error: Error wrapping up...\" was changed to a\nless funny, but more helpful, \"error: failed to finalize...\".\n\nPointed out by Junio Hamano.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c                   | 68 +++++++++++++++++++++----------------------\n t/t3501-revert-cherry-pick.sh |  2 +-\n 2 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 4596540..676f16c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -241,18 +241,18 @@ static int write_with_lock_file(const char *filename,\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), filename);\n \tif (write_in_full(msg_fd, buf, len) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), filename);\n \t}\n \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t\treturn error_errno(_(\"could not write eol to '%s\"), filename);\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -312,11 +312,11 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(_(action_name(opts)));\n \n-\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\terror(_(\"your local changes would be overwritten by %s.\"),\n \t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n-\t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n+\t\tadvise(_(\"commit your changes or stash them to proceed.\"));\n \treturn -1;\n }\n \n@@ -425,7 +425,7 @@ static int is_index_unchanged(void)\n \tstruct commit *head_commit;\n \n \tif (!resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING, head_sha1, NULL))\n-\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\t\treturn error(_(\"could not resolve HEAD commit\\n\"));\n \n \thead_commit = lookup_commit(head_sha1);\n \n@@ -445,7 +445,7 @@ static int is_index_unchanged(void)\n \n \tif (!cache_tree_fully_valid(active_cache_tree))\n \t\tif (cache_tree_update(&the_index, 0))\n-\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\t\t\treturn error(_(\"unable to update cache tree\\n\"));\n \n \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n }\n@@ -515,7 +515,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\treturn error(\"you have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n \t\t\t\t\"  git commit --amend %s\\n\\n\"\n@@ -568,12 +568,12 @@ static int is_original_commit_empty(struct commit *commit)\n \tconst unsigned char *ptree_sha1;\n \n \tif (parse_commit(commit))\n-\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tif (commit->parents) {\n \t\tstruct commit *parent = commit->parents->item;\n \t\tif (parse_commit(parent))\n-\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\treturn error(_(\"could not parse parent commit %s\\n\"),\n \t\t\t\toid_to_hex(&parent->object.oid));\n \t\tptree_sha1 = parent->tree->object.oid.hash;\n \t} else {\n@@ -657,7 +657,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t * to work on.\n \t\t */\n \t\tif (write_cache_as_tree(head, 0, NULL))\n-\t\t\treturn error(_(\"Your index file is unmerged.\"));\n+\t\t\treturn error(_(\"your index file is unmerged.\"));\n \t} else {\n \t\tunborn = get_sha1(\"HEAD\", head);\n \t\tif (unborn)\n@@ -676,7 +676,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tstruct commit_list *p;\n \n \t\tif (!opts->mainline)\n-\t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n+\t\t\treturn error(_(\"commit %s is a merge but no -m option was given.\"),\n \t\t\t\toid_to_hex(&commit->object.oid));\n \n \t\tfor (cnt = 1, p = commit->parents;\n@@ -684,11 +684,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t     cnt++)\n \t\t\tp = p->next;\n \t\tif (cnt != opts->mainline || !p)\n-\t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n+\t\t\treturn error(_(\"commit %s does not have parent %d\"),\n \t\t\t\toid_to_hex(&commit->object.oid), opts->mainline);\n \t\tparent = p->item;\n \t} else if (0 < opts->mainline)\n-\t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n+\t\treturn error(_(\"mainline was specified but commit %s is not a merge.\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \telse\n \t\tparent = commit->parents->item;\n@@ -708,7 +708,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n-\t\treturn error(_(\"Cannot get commit message for %s\"),\n+\t\treturn error(_(\"cannot get commit message for %s\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \n \t/*\n@@ -944,13 +944,13 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\tres = error(_(\"invalid line %d: %.*s\"),\n \t\t\t\ti, (int)(eol - p), p);\n \t\t\titem->command = -1;\n \t\t}\n \t}\n \tif (!todo_list->nr)\n-\t\treturn error(_(\"No commits parsed.\"));\n+\t\treturn error(_(\"no commits parsed.\"));\n \treturn res;\n }\n \n@@ -963,16 +963,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n+\t\treturn error_errno(_(\"could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n+\t\treturn error(_(\"could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n+\t\treturn error(_(\"unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -983,9 +983,9 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tif (valid == todo_list->items[i].command)\n \t\t\t\tcontinue;\n \t\t\telse if (valid == TODO_PICK)\n-\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\t\treturn error(_(\"cannot cherry-pick during a revert.\"));\n \t\t\telse\n-\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t\t\t\treturn error(_(\"cannot revert during a cherry-pick.\"));\n \t}\n \n \treturn 0;\n@@ -1030,10 +1030,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n \t} else\n-\t\treturn error(_(\"Invalid key: %s\"), key);\n+\t\treturn error(_(\"invalid key: %s\"), key);\n \n \tif (!error_flag)\n-\t\treturn error(_(\"Invalid value for %s: %s\"), key, value);\n+\t\treturn error(_(\"invalid value for %s: %s\"), key, value);\n \n \treturn 0;\n }\n@@ -1065,7 +1065,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n+\t\treturn error(_(\"malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1108,7 +1108,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n+\t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1122,17 +1122,17 @@ static int save_head(const char *head)\n \tfd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);\n \tif (fd < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not lock HEAD\"));\n+\t\treturn error_errno(_(\"could not lock HEAD\"));\n \t}\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"),\n+\t\treturn error_errno(_(\"could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n+\t\treturn error(_(\"failed to finalize '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1211,14 +1211,14 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \n \tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), todo_path);\n \toffset = next < todo_list->nr ?\n \t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n \tif (write_in_full(fd, todo_list->buf.buf + offset,\n \t\t\ttodo_list->buf.len - offset) < 0)\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1393,7 +1393,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\t\tcreate_seq_dir() < 0)\n \t\treturn -1;\n \tif (get_sha1(\"HEAD\", sha1) && (opts->action == REPLAY_REVERT))\n-\t\treturn error(_(\"Can't revert as initial commit\"));\n+\t\treturn error(_(\"can't revert as initial commit\"));\n \tif (save_head(sha1_to_hex(sha1)))\n \t\treturn -1;\n \tif (save_opts(opts))\ndiff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh\nindex 51f3bbb..394f000 100755\n--- a/t/t3501-revert-cherry-pick.sh\n+++ b/t/t3501-revert-cherry-pick.sh\n@@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '\n \techo content >extra_file &&\n \tgit add extra_file &&\n \ttest_must_fail git revert HEAD 2>errors &&\n-\ttest_i18ngrep \"Your local changes would be overwritten by \" errors\n+\ttest_i18ngrep \"your local changes would be overwritten by \" errors\n \n '\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303761","messageId":"e38bf77ff57d06ca3250bc3ec71a34088b49abd0.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 25/25] sequencer: mark all error messages for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:36Z","receivedAt":"2016-10-10T17:33:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There was actually only one error message that was not yet marked for\ntranslation.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 23 +++++++++++++----------\n 1 file changed, 13 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 676f16c..86d86ce 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -515,16 +515,19 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"you have staged changes in your working \"\n-\t\t\t\t\"tree. If these changes are meant to be\\n\"\n-\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend %s\\n\\n\"\n-\t\t\t\t\"If they are meant to go into a new commit, \"\n-\t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit %s\\n\\n\"\n-\t\t\t\t\"In both cases, once you're done, continue \"\n-\t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t\treturn error(_(\"you have staged changes in your \"\n+\t\t\t\t       \"working tree. If these changes are \"\n+\t\t\t\t       \"meant to be\\n\"\n+\t\t\t\t       \"squashed into the previous commit, \"\n+\t\t\t\t       \"run:\\n\\n\"\n+\t\t\t\t       \"  git commit --amend %s\\n\\n\"\n+\t\t\t\t       \"If they are meant to go into a new \"\n+\t\t\t\t       \"commit, run:\\n\\n\"\n+\t\t\t\t       \"  git commit %s\\n\\n\"\n+\t\t\t\t       \"In both cases, once you're done, \"\n+\t\t\t\t       \"continue with:\\n\\n\"\n+\t\t\t\t       \"  git rebase --continue\\n\"),\n+\t\t\t\t     gpg_opt, gpg_opt);\n \t\t}\n \t}\n \n-- \n2.10.0.windows.1.325.ge6089c1\n"},{"id":"303762","messageId":"826d552366d1ce9550e448c0e05db6090f529873.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 22/25] sequencer: mark action_name() for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:26Z","receivedAt":"2016-10-10T17:33:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The definition of this function goes back all the way to 043a449\n(sequencer: factor code out of revert builtin, 2012-01-11), long before a\nserious effort was made to translate all the error messages.\n\nIt is slightly out of the context of the current patch series (whose\npurpose it is to re-implement the performance critical parts of the\ninteractive rebase in C) to make the error messages in the sequencer\ntranslatable, but what the heck. We'll just do it while we're looking at\nthis part of the code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ffce095..40ef33c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -168,7 +168,7 @@ int sequencer_remove_state(struct replay_opts *opts)\n \n static const char *action_name(const struct replay_opts *opts)\n {\n-\treturn opts->action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\";\n+\treturn opts->action == REPLAY_REVERT ? N_(\"revert\") : N_(\"cherry-pick\");\n }\n \n struct commit_message {\n@@ -310,10 +310,10 @@ static struct tree *empty_tree(void)\n static int error_dirty_index(struct replay_opts *opts)\n {\n \tif (read_cache_unmerged())\n-\t\treturn error_resolve_conflict(action_name(opts));\n+\t\treturn error_resolve_conflict(_(action_name(opts)));\n \n \terror(_(\"Your local changes would be overwritten by %s.\"),\n-\t\taction_name(opts));\n+\t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n@@ -331,7 +331,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,\n \tif (checkout_fast_forward(from, to, 1))\n \t\treturn -1; /* the callee should have complained already */\n \n-\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), action_name(opts));\n+\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), _(action_name(opts)));\n \n \ttransaction = ref_transaction_begin(&err);\n \tif (!transaction ||\n@@ -407,7 +407,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \t    write_locked_index(&the_index, &index_lock, COMMIT_LOCK))\n \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n \t\treturn error(_(\"%s: Unable to write new index file\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \trollback_lock_file(&index_lock);\n \n \tif (opts->signoff)\n@@ -844,14 +844,14 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \tif (read_index_preload(&the_index, NULL) < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn error(_(\"git %s: failed to read the index\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \t}\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n \tif (the_index.cache_changed && index_fd >= 0) {\n \t\tif (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {\n \t\t\trollback_lock_file(&index_lock);\n \t\t\treturn error(_(\"git %s: failed to refresh the index\"),\n-\t\t\t\taction_name(opts));\n+\t\t\t\t_(action_name(opts)));\n \t\t}\n \t}\n \trollback_lock_file(&index_lock);\n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303763","messageId":"15032a93b02d8a0f5a0c48d79b933f4e1a6c9ee1.1476120229.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 21/25] sequencer: remove overzealous assumption in rebase -i mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-10T17:26:23Z","receivedAt":"2016-10-10T17:34:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer was introduced to make the cherry-pick and revert\nfunctionality available as library function, with the original idea\nbeing to extend the sequencer to also implement the rebase -i\nfunctionality.\n\nThe test to ensure that all of the commands in the script are identical\nto the overall operation does not mesh well with that.\n\nTherefore let's disable the test in rebase -i mode.\n\nWhile at it, error out early if the \"instruction sheet\" (i.e. the todo\nscript) could not be parsed.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5cca8d8..ffce095 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -971,7 +971,10 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n-\tif (!res) {\n+\tif (res)\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\n+\tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n \t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n \t\tint i;\n@@ -985,8 +988,6 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n \t}\n \n-\tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n-- \n2.10.0.windows.1.325.ge6089c1\n\n\n"},{"id":"303811","messageId":"xmqqlgxvdf90.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"4e73ba3e8c1700259ffcc3224d1f66e6a760142d.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-10T22:13:31Z","receivedAt":"2016-10-10T22:13:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Let's just bite the bullet and rewrite the entire parser; the code now\n> ...\n> In particular, we choose to maintain the list of commands in an array\n> instead of a linked list: this is flexible enough to allow us later on to\n> even implement rebase -i's reordering of fixup!/squash! commits very\n> easily (and with a very nice speed bonus, at least on Windows).\n>\n> While at it, do not stop at the first problem, but list *all* of the\n> problems. This will help the user when the sequencer will do `rebase\n> -i`'s work by allowing to address all issues in one go rather than going\n> back and forth until the todo list is valid.\n\nAll sounds sensible.\n\n>  \tif (parent && parse_commit(parent) < 0)\n> -\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n> -\t\t   \"cherry-pick\", the second %s a SHA1 */\n> +\t\t/*\n> +\t\t * TRANSLATORS: The first %s will be a \"todo\" command like\n> +\t\t * \"revert\" or \"pick\", the second %s a SHA1.\n> +\t\t */\n\nYou may want to double check this with i18n folks; IIRC the tool\nthat extracts TRANSLATORS: comment was somewhat particular about\nwhere that magic \"TRANSLATORS:\" token resides on a comment line and\nthat is why we have this multi-line comment formatted in an unusual\nway.\n\nAhh, no you do not have to bug i18n folks.  47fbfded53 (\"i18n: only\nextract comments marked with \"TRANSLATORS:\"\", 2014-04-17) is an\nexample of such an adjustment.\n\nI just found it in CodingGuidelines, cbcfd4e3ea (\"i18n: mention\n\"TRANSLATORS:\" marker in Documentation/CodingGuidelines\",\n2014-04-18).\n\n> +\twhile ((commit = get_revision(opts->revs))) {\n> +\t\tstruct todo_item *item = append_new_todo(todo_list);\n> +\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n> +\t\tconst char *subject;\n> +\t\tint subject_len;\n> +\n> +\t\titem->command = command;\n> +\t\titem->commit = commit;\n> +\t\titem->offset_in_buf = todo_list->buf.len;\n> +\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> +\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n> +\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n> +\t\t\t\tDEFAULT_ABBREV),\n> +\t\t\tsubject_len, subject);\n\nI am personally fine with this line; two things come to mind:\n\n - This would work just fine as-is with Linus's change to turn\n   DEFAULT_ABBREV to -1.\n\n - It appears that it is more fashionable to use\n   strbuf_add_unique_abbrev() these days.\n\nThanks.\n"},{"id":"303812","messageId":"xmqqeg3ndf85.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"5c4c86f0ea7ee4a9bad15e48f72b8fe5baa72dfb.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 01/25] sequencer: use static initializers for replay_opts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-10T22:14:02Z","receivedAt":"2016-10-10T22:14:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This change is not completely faithful: instead of initializing all fields\n> to 0, we choose to initialize command and subcommand to -1 (instead of\n> defaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\n> it makes no difference at all, but future-proofs the code to require\n> explicit assignments for both fields.\n\nThe assignments to opts.action immediately following, I would say\nthis is quite faithful conversion that looks good.\n\n>  int cmd_revert(int argc, const char **argv, const char *prefix)\n>  {\n> -\tstruct replay_opts opts;\n> +\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n>  \tint res;\n>  \n> -\tmemset(&opts, 0, sizeof(opts));\n>  \tif (isatty(0))\n>  \t\topts.edit = 1;\n>  \topts.action = REPLAY_REVERT;\n> @@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n>  \n>  int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n>  {\n> -\tstruct replay_opts opts;\n> +\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n>  \tint res;\n>  \n> -\tmemset(&opts, 0, sizeof(opts));\n>  \topts.action = REPLAY_PICK;\n>  \tgit_config(git_default_config, NULL);\n>  \tparse_args(argc, argv, &opts);\n> diff --git a/sequencer.h b/sequencer.h\n> index 5ed5cb1..db425ad 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -47,6 +47,7 @@ struct replay_opts {\n>  \t/* Only used by REPLAY_NONE */\n>  \tstruct rev_info *revs;\n>  };\n> +#define REPLAY_OPTS_INIT { -1, -1 }\n>  \n>  int sequencer_pick_revisions(struct replay_opts *opts);\n"},{"id":"303813","messageId":"xmqq7f9fdf7a.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"336cefca0bda214b5b43b1094af13d787d1a79e3.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 03/25] sequencer: avoid unnecessary indirection","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-10T22:14:33Z","receivedAt":"2016-10-10T22:14:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> We really do not need the *pointer to a* pointer to the options in\n> the read_populate_opts() function.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n\nI vaguely recall seeing this in the previous round and finding it\npretty sensible.  And I still do ;-)\n\n\n[the remainder left as-is to help those who are reading from\nsidelines]\n\n> diff --git a/sequencer.c b/sequencer.c\n> index cb16cbd..c2fbf6f 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -813,7 +813,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  \treturn 0;\n>  }\n>  \n> -static int read_populate_opts(struct replay_opts **opts)\n> +static int read_populate_opts(struct replay_opts *opts)\n>  {\n>  \tif (!file_exists(git_path_opts_file()))\n>  \t\treturn 0;\n> @@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n>  \t * about this case, though, because we wrote that file ourselves, so we\n>  \t * are pretty certain that it is syntactically correct.\n>  \t */\n> -\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n> +\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n>  \t\treturn error(_(\"Malformed options sheet: %s\"),\n>  \t\t\tgit_path_opts_file());\n>  \treturn 0;\n> @@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n>  \n>  \tif (!file_exists(git_path_todo_file()))\n>  \t\treturn continue_single_pick();\n> -\tif (read_populate_opts(&opts) ||\n> +\tif (read_populate_opts(opts) ||\n>  \t\t\tread_populate_todo(&todo_list, opts))\n>  \t\treturn -1;\n"},{"id":"303814","messageId":"xmqqzimbc0gw.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"a67af02ef363311b526bddba864c7f1ca9087b43.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-10T22:18:07Z","receivedAt":"2016-10-10T22:18:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index 7365559..fce9c75 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -174,6 +174,12 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n>  \n>  \tif (argc > 1)\n>  \t\tusage_with_options(usage_str, options);\n> +\n> +\t/* These option values will be free()d */\n> +\tif (opts->gpg_sign)\n> +\t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n> +\tif (opts->strategy)\n> +\t\topts->strategy = xstrdup(opts->strategy);\n>  }\n\nThis certainly is good, but I wonder if a new variant of OPT_STRING\nand OPTION_STRING that does the strdup for you, something along the\nlines of ...\n\ndiff --git a/parse-options.c b/parse-options.c\nindex 312a85dbde..6aab6b0b05 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -138,6 +138,21 @@ static int get_value(struct parse_opt_ctx_t *p,\n \t\t\treturn get_arg(p, opt, flags, (const char **)opt->value);\n \t\treturn 0;\n \n+\tcase OPTION_STRDUP:\n+\t\terr = 0;\n+\t\tfree(opt->value);\n+\t\tif (unset)\n+\t\t\t*(const char **)opt->value = NULL;\n+\t\telse if (opt->flags & PARSE_OPT_OPTARG && !p->opt)\n+\t\t\t*(const char **)opt->value = xstrdup(opt->defval);\n+\t\telse {\n+\t\t\tconst char *v;\n+\t\t\terr = get_arg(p, opt, flags, &v);\n+\t\t\tif (!err)\n+\t\t\t\t*(const char **)opt->value = xstrdup(v);\n+\t\t}\n+\t\treturn err;\n+\n \tcase OPTION_FILENAME:\n \t\terr = 0;\n \t\tif (unset)\n\n... may make it even more pleasant to use?  Only for two fields in\nthis patch that may probably be an overkill, but we may eventually \nbenefit from such an approach when we audit and plug leaks in\nparse-options users.  I dunno.\n\nIt is a sign that the caller wants to _own_ the memory to mark a\nvariable or field with OPTION_STRDUP, which is why I added the\nfree() at the beginning there.\n\nThe remainder of this patch looks sensible.  The code that frees\nthese fields when we are done with the struct (and when we are\nre-assigning) looked all good.\n"},{"id":"303859","messageId":"alpine.DEB.2.20.1610111148340.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqzimbc0gw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-11T10:07:55Z","receivedAt":"2016-10-11T10:08:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 10 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > diff --git a/builtin/revert.c b/builtin/revert.c\n> > index 7365559..fce9c75 100644\n> > --- a/builtin/revert.c\n> > +++ b/builtin/revert.c\n> > @@ -174,6 +174,12 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n> >  \n> >  \tif (argc > 1)\n> >  \t\tusage_with_options(usage_str, options);\n> > +\n> > +\t/* These option values will be free()d */\n> > +\tif (opts->gpg_sign)\n> > +\t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n> > +\tif (opts->strategy)\n> > +\t\topts->strategy = xstrdup(opts->strategy);\n> >  }\n> \n> This certainly is good, but I wonder if a new variant of OPT_STRING\n> and OPTION_STRING that does the strdup for you, something along the\n> lines of ...\n> \n> diff --git a/parse-options.c b/parse-options.c\n> index 312a85dbde..6aab6b0b05 100644\n> --- a/parse-options.c\n> +++ b/parse-options.c\n> @@ -138,6 +138,21 @@ static int get_value(struct parse_opt_ctx_t *p,\n>  \t\t\treturn get_arg(p, opt, flags, (const char **)opt->value);\n>  \t\treturn 0;\n>  \n> +\tcase OPTION_STRDUP:\n> +\t\terr = 0;\n> +\t\tfree(opt->value);\n\nProbably\n\n\t\tfree(*(char **)opt->value);\n\ninstead.\n\n> +\t\tif (unset)\n> +\t\t\t*(const char **)opt->value = NULL;\n> +\t\telse if (opt->flags & PARSE_OPT_OPTARG && !p->opt)\n> +\t\t\t*(const char **)opt->value = xstrdup(opt->defval);\n> +\t\telse {\n> +\t\t\tconst char *v;\n> +\t\t\terr = get_arg(p, opt, flags, &v);\n> +\t\t\tif (!err)\n> +\t\t\t\t*(const char **)opt->value = xstrdup(v);\n> +\t\t}\n> +\t\treturn err;\n> +\n>  \tcase OPTION_FILENAME:\n>  \t\terr = 0;\n>  \t\tif (unset)\n> \n> ... may make it even more pleasant to use?\n\nWith s/even// I would agree.\n\nI will keep this patch in mind and will try to come back to it, once the\nrebase--helper patches are well on target for `master`.\n\nCiao,\nDscho\n"},{"id":"303861","messageId":"alpine.DEB.2.20.1610111212090.35196@virtualbox","threadId":"43954","inReplyTo":"xmqqlgxvdf90.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-11T10:20:38Z","receivedAt":"2016-10-11T10:20:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 10 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> >  \tif (parent && parse_commit(parent) < 0)\n> > -\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n> > -\t\t   \"cherry-pick\", the second %s a SHA1 */\n> > +\t\t/*\n> > +\t\t * TRANSLATORS: The first %s will be a \"todo\" command like\n> > +\t\t * \"revert\" or \"pick\", the second %s a SHA1.\n> > +\t\t */\n> \n> You may want to double check this with i18n folks; IIRC the tool\n> that extracts TRANSLATORS: comment was somewhat particular about\n> where that magic \"TRANSLATORS:\" token resides on a comment line and\n> that is why we have this multi-line comment formatted in an unusual\n> way.\n> \n> Ahh, no you do not have to bug i18n folks.  47fbfded53 (\"i18n: only\n> extract comments marked with \"TRANSLATORS:\"\", 2014-04-17) is an\n> example of such an adjustment.\n\nUrgh. Thanks for pointing this out to me, though. Will be fixed in the\nnext iteration.\n\n> > +\twhile ((commit = get_revision(opts->revs))) {\n> > +\t\tstruct todo_item *item = append_new_todo(todo_list);\n> > +\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n> > +\t\tconst char *subject;\n> > +\t\tint subject_len;\n> > +\n> > +\t\titem->command = command;\n> > +\t\titem->commit = commit;\n> > +\t\titem->offset_in_buf = todo_list->buf.len;\n> > +\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n> > +\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n> > +\t\t\tfind_unique_abbrev(commit->object.oid.hash,\n> > +\t\t\t\tDEFAULT_ABBREV),\n> > +\t\t\tsubject_len, subject);\n> \n> I am personally fine with this line; two things come to mind:\n> \n>  - This would work just fine as-is with Linus's change to turn\n>    DEFAULT_ABBREV to -1.\n> \n>  - It appears that it is more fashionable to use\n>    strbuf_add_unique_abbrev() these days.\n\nRight, I actually looked at this place when I tried to decide where I\ncould use that function. Somehow I thought I'd not break up the flow here.\n\nBut since you asked so nicely, I'll squash this in (I personally find it\nuglier, and longer, but it does use strbuf_add_unique_abbrev() now):\n\n-- snipsnap --\n@@ -906,11 +904,13 @@ static int walk_revs_populate_todo(struct todo_list\n*todo_list,\n                item->command = command;\n                item->commit = commit;\n                item->offset_in_buf = todo_list->buf.len;\n+               strbuf_addstr(&todo_list->buf, command);\n+               strbuf_addch(&todo_list->buf, ' ');\n+               strbuf_add_unique_abbrev(&todo_list->buf,\n+                                        commit->object.oid.hash,\n+                                        DEFAULT_ABBREV);\n                subject_len = find_commit_subject(commit_buffer, &subject);\n-               strbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n                command_string,\n-                       find_unique_abbrev(commit->object.oid.hash,\n-                               DEFAULT_ABBREV),\n-                       subject_len, subject);\n+               strbuf_add(&todo_list->buf, subject, subject_len);\n                unuse_commit_buffer(commit, commit_buffer);\n        }\n        return 0;\n"},{"id":"303862","messageId":"alpine.DEB.2.20.1610111221530.35196@virtualbox","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610111212090.35196@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-11T10:22:15Z","receivedAt":"2016-10-11T10:22:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Johannes Schindelin wrote:\n\n> -- snipsnap --\n> @@ -906,11 +904,13 @@ static int walk_revs_populate_todo(struct todo_list\n> *todo_list,\n>                 item->command = command;\n>                 item->commit = commit;\n>                 item->offset_in_buf = todo_list->buf.len;\n> +               strbuf_addstr(&todo_list->buf, command);\n\nThis would be command_string instead of command, of course.\n\n> +               strbuf_addch(&todo_list->buf, ' ');\n> +               strbuf_add_unique_abbrev(&todo_list->buf,\n> +                                        commit->object.oid.hash,\n> +                                        DEFAULT_ABBREV);\n>                 subject_len = find_commit_subject(commit_buffer, &subject);\n> -               strbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n>                 command_string,\n> -                       find_unique_abbrev(commit->object.oid.hash,\n> -                               DEFAULT_ABBREV),\n> -                       subject_len, subject);\n> +               strbuf_add(&todo_list->buf, subject, subject_len);\n>                 unuse_commit_buffer(commit, commit_buffer);\n>         }\n>         return 0;\n\nCiao,\nDscho\n"},{"id":"303864","messageId":"alpine.DEB.2.20.1610111238470.35196@virtualbox","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610111221530.35196@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-11T10:55:14Z","receivedAt":"2016-10-11T10:55:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Johannes Schindelin wrote:\n\n> On Tue, 11 Oct 2016, Johannes Schindelin wrote:\n> \n> > -- snipsnap --\n> > @@ -906,11 +904,13 @@ static int walk_revs_populate_todo(struct todo_list\n> > *todo_list,\n> >                 item->command = command;\n> >                 item->commit = commit;\n> >                 item->offset_in_buf = todo_list->buf.len;\n> > +               strbuf_addstr(&todo_list->buf, command);\n> \n> This would be command_string instead of command, of course.\n> \n> > +               strbuf_addch(&todo_list->buf, ' ');\n> > +               strbuf_add_unique_abbrev(&todo_list->buf,\n> > +                                        commit->object.oid.hash,\n> > +                                        DEFAULT_ABBREV);\n> >                 subject_len = find_commit_subject(commit_buffer, &subject);\n> > -               strbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n> >                 command_string,\n> > -                       find_unique_abbrev(commit->object.oid.hash,\n> > -                               DEFAULT_ABBREV),\n> > -                       subject_len, subject);\n> > +               strbuf_add(&todo_list->buf, subject, subject_len);\n> >                 unuse_commit_buffer(commit, commit_buffer);\n> >         }\n> >         return 0;\n\nIn the end, I decided to actually *not* use strbuf_add_unique_abbrev()\nhere because it really makes the code very much too ugly after the\nintroduction of short_commit_name():\n\n-- snip --\n@@ -1093,10 +1093,16 @@ static int walk_revs_populate_todo(struct\ntodo_list *todo_list,\n                item->arg = NULL;\n                item->arg_len = 0;\n                item->offset_in_buf = todo_list->buf.len;\n+               strbuf_addstr(&todo_list->buf, command_string);\n+               strbuf_addch(&todo_list->buf, ' ');\n+               strbuf_add_unique_abbrev(&todo_list->buf,\n+                                        commit->object.oid.hash,\n+                                        DEFAULT_ABBREV);\n+               strbuf_addch(&todo_list->buf, ' ');\n                subject_len = find_commit_subject(commit_buffer, &subject);\n-               strbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\",\n                command_string,\n-                       short_commit_name(commit), subject_len, subject);\n+               strbuf_add(&todo_list->buf, subject, subject_len);\n                unuse_commit_buffer(commit, commit_buffer);\n+               strbuf_addch(&todo_list->buf, '\\n');\n        }\n        return 0;\n }\n-- snap --\n\nI hope you will forgive me disagreeing with you here.\n\nTo make it easier to accept, I reordered the short_commit_name() patch so\nit comes before revamping the todo parsing.\n\nCiao,\nDscho\n"},{"id":"303883","messageId":"xmqq4m4ic0gw.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"xmqqzimbc0gw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T16:30:23Z","receivedAt":"2016-10-11T16:30:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> This certainly is good, but I wonder if a new variant of OPT_STRING\n> and OPTION_STRING that does the strdup for you, something along the\n> lines of ...\n> ... may make it even more pleasant to use?  Only for two fields in\n> this patch that may probably be an overkill, but we may eventually \n> benefit from such an approach when we audit and plug leaks in\n> parse-options users.  I dunno.\n\nAfter sleeping on it, I do think this is an overkill.  The pattern I\nwould expect for the most normal (boring) code to use is rather:\n\n    struct app_specific app;\n    const char *opt_x = NULL;\n    struct option options[] = {\n\t...\n\tOPT_STRING(0, \"xopt\", &opt_x, N_(\"x option\"), ...),\n        ...\n\tOPT_END()\n    };\n\n    parse_options(ac, av, prefix, options, ...);\n    app.x_field = xstrdup_or_null(opt_x);\n    ... other values set to app's field based on\n    ... not just command line options but from\n    ... other sources.\n\nThe only reason why the OPT_STRDUP appeared convenient was because\noptions[] element happened to use a field in the structure directly.\nThe patch under discussion does an equivalent of\n\n    app.x_field = xstrdup_or_null(opt_x);\n\nbut the \"opt_x\" happens to be the same \"app.x_field\" in this case,\nso in that sense, it follows the normal and boring pattern.\n\nThe \"struct app_specific\" may not even exist in the same scope as\nthe caller of parse_options(), but may have to be initialized in a\nfunction that is three-level deep in the callchain, with opt_x\nvariable passed through as a parameter.  So OPT_STRDUP may not be a\nbad or horrible idea, but it is not such a great one, either.\n\n"},{"id":"303886","messageId":"xmqqzimaaks6.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610111212090.35196@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T16:54:33Z","receivedAt":"2016-10-11T16:55:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I am personally fine with this line; two things come to mind:\n>> \n>>  - This would work just fine as-is with Linus's change to turn\n>>    DEFAULT_ABBREV to -1.\n>> \n>>  - It appears that it is more fashionable to use\n>>    strbuf_add_unique_abbrev() these days.\n>\n> Right, I actually looked at this place when I tried to decide where I\n> could use that function. Somehow I thought I'd not break up the flow here.\n>\n> But since you asked so nicely,...\n\nWhen I say \"I am fine\", I am not asking you to change anything.\n\nSome of the places that have been updated recently to use\nstrbuf_add_unique_abbrev() in other topics did improve the\nreadability of the code, but I do not think it would universally\nbe true.\n"},{"id":"303890","messageId":"xmqqvawyakme.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610111238470.35196@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T16:58:01Z","receivedAt":"2016-10-11T17:10:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> In the end, I decided to actually *not* use strbuf_add_unique_abbrev()\n> here because it really makes the code very much too ugly after the\n> introduction of short_commit_name():\n\nIt's perfectly fine not to use that function when it does not make\nsense; we shouldn't use it (or anything for that matter) just for\nthe sake of using it.\n"},{"id":"303906","messageId":"xmqq60oyaf7s.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"5a639610c09bf1dacc8143603f321a8ea23cd270.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 08/25] sequencer: strip CR from the todo script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T18:54:47Z","receivedAt":"2016-10-11T18:56:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> It is not unheard of that editors on Windows write CR/LF even if the\n> file originally had only LF. This is particularly awkward for exec lines\n> of a rebase -i todo sheet. Take for example the insn \"exec echo\": The\n> shell script parser splits at the LF and leaves the CR attached to\n> \"echo\", which leads to the unknown command \"echo\\r\".\n>\n> Work around that by stripping CR when reading the todo commands, as we\n> already do for LF.\n>\n> This happens to fix t9903.14 and .15 in MSYS1 environments (with the\n> rebase--helper patches based on this patch series): the todo script\n> constructed in such a setup contains CR/LF thanks to MSYS1 runtime's\n> cleverness.\n>\n> Based on a report and a patch by Johannes Sixt.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 3 +++\n>  1 file changed, 3 insertions(+)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 678fdf3..cee7e50 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -774,6 +774,9 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n>  \n>  \t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n>  \n> +\t\tif (p != eol && eol[-1] == '\\r')\n> +\t\t\teol--; /* skip Carriage Return */\n\nmicronit: s/skip/strip/ ;-)\n\n> +\n>  \t\titem = append_new_todo(todo_list);\n>  \t\titem->offset_in_buf = p - todo_list->buf.buf;\n>  \t\tif (parse_insn_line(item, p, eol)) {\n"},{"id":"303911","messageId":"xmqqwphe8zl2.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"9b2782e64f678ab2d261042b63fafc3e4a519295.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T19:17:45Z","receivedAt":"2016-10-11T19:17:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"> @@ -370,19 +383,79 @@ static int is_index_unchanged(void)\n>  }\n>  \n>  /*\n> + * Read the author-script file into an environment block, ready for use in\n> + * run_command(), that can be free()d afterwards.\n> + */\n> +static char **read_author_script(void)\n> +{\n> +\tstruct strbuf script = STRBUF_INIT;\n> +\tint i, count = 0;\n> +\tchar *p, *p2, **env;\n> +\tsize_t env_size;\n> +\n> +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n> +\t\treturn NULL;\n> +\n> +\tfor (p = script.buf; *p; p++)\n> +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n> +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n> +\t\telse if (*p == '\\'')\n> +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n> +\t\telse if (*p == '\\n') {\n> +\t\t\t*p = '\\0';\n> +\t\t\tcount++;\n> +\t\t}\n\nHmph, didn't we recently add parse_key_value_squoted() to build\nread_author_script() in builtin/am.c on top of it, so that this\npiece of code can also take advantage of and share the parser?\n\n> +/*\n\nOfftopic: this line and the beginning of the new comment block that\nbegins with \"Read the author-script\" above show a suboptimal marking\nof what is added and what is left.  I wonder \"diff-indent-heuristic\"\ntopic by Michael can help to make it look better.\n\n>   * If we are cherry-pick, and if the merge did not result in\n>   * hand-editing, we will hit this commit and inherit the original\n>   * author date and name.\n> + *\n>   * If we are revert, or if our cherry-pick results in a hand merge,\n>   * we had better say that the current user is responsible for that.\n> + *\n> + * An exception is when run_git_commit() is called during an\n> + * interactive rebase: in that case, we will want to retain the\n> + * author metadata.\n>   */\n"},{"id":"303913","messageId":"xmqq1szmaemr.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"f22bdcda3f748813e6b9fd08dc65f11c6f9f4b1e.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-11T19:07:24Z","receivedAt":"2016-10-11T19:25:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The `git-rebase-todo` file contains a list of commands. Most of those\n> commands have the form\n>\n> \t<verb> <sha1> <oneline>\n>\n> The <oneline> is displayed primarily for the user's convenience, as\n> rebase -i really interprets only the <verb> <sha1> part. However, there\n> are *some* places in interactive rebase where the <oneline> is used to\n> display messages, e.g. for reporting at which commit we stopped.\n>\n> So let's just remember it when parsing the todo file; we keep a copy of\n> the entire todo file anyway (to write out the new `done` and\n> `git-rebase-todo` file just before processing each command), so all we\n> need to do is remember the begin offsets and lengths.\n>\n> As we will have to parse and remember the command-line for `exec` commands\n> later, we do not call the field \"oneline\" but rather \"arg\" (and will reuse\n> that for exec's command-line).\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 7 +++++++\n>  1 file changed, 7 insertions(+)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index afc494e..7ba5e07 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -708,6 +708,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n>  struct todo_item {\n>  \tenum todo_command command;\n>  \tstruct commit *commit;\n> +\tconst char *arg;\n> +\tint arg_len;\n>  \tsize_t offset_in_buf;\n\nmicronit: you can make it to size_t and lose the cast below, no?\n\n>  };\n>  \n> @@ -759,6 +761,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n>  \tstatus = get_sha1(bol, commit_sha1);\n>  \t*end_of_object_name = saved;\n>  \n> +\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n> +\titem->arg_len = (int)(eol - item->arg);\n> +\n>  \tif (status < 0)\n>  \t\treturn -1;\n>  \n> @@ -911,6 +916,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \n>  \t\titem->command = command;\n>  \t\titem->commit = commit;\n> +\t\titem->arg = NULL;\n> +\t\titem->arg_len = 0;\n>  \t\titem->offset_in_buf = todo_list->buf.len;\n>  \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n>  \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n"},{"id":"303975","messageId":"alpine.DEB.2.20.1610121347361.3492@virtualbox","threadId":"43954","inReplyTo":"xmqq1szmaemr.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-12T11:49:27Z","receivedAt":"2016-10-12T11:51:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > diff --git a/sequencer.c b/sequencer.c\n> > index afc494e..7ba5e07 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -708,6 +708,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n> >  struct todo_item {\n> >  \tenum todo_command command;\n> >  \tstruct commit *commit;\n> > +\tconst char *arg;\n> > +\tint arg_len;\n> >  \tsize_t offset_in_buf;\n> \n> micronit: you can make it to size_t and lose the cast below, no?\n\nNo. The primary users of arg_len call a printf() style function with %.*s,\nexpecting an int. So your suggestion would lose one cast, but introduce at\nleast four casts in return.\n\nCiao,\nDscho\n"},{"id":"303976","messageId":"alpine.DEB.2.20.1610121346360.3492@virtualbox","threadId":"43954","inReplyTo":"xmqq60oyaf7s.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 08/25] sequencer: strip CR from the todo script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-12T11:46:50Z","receivedAt":"2016-10-12T11:53:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > diff --git a/sequencer.c b/sequencer.c\n> > index 678fdf3..cee7e50 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -774,6 +774,9 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n> >  \n> >  \t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n> >  \n> > +\t\tif (p != eol && eol[-1] == '\\r')\n> > +\t\t\teol--; /* skip Carriage Return */\n> \n> micronit: s/skip/strip/ ;-)\n\nOkay,\nDscho\n"},{"id":"303977","messageId":"alpine.DEB.2.20.1610121356510.3492@virtualbox","threadId":"43954","inReplyTo":"xmqqwphe8zl2.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-12T12:00:21Z","receivedAt":"2016-10-12T12:01:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Junio C Hamano wrote:\n\n> > @@ -370,19 +383,79 @@ static int is_index_unchanged(void)\n> >  }\n> >  \n> >  /*\n> > + * Read the author-script file into an environment block, ready for use in\n> > + * run_command(), that can be free()d afterwards.\n> > + */\n> > +static char **read_author_script(void)\n> > +{\n> > +\tstruct strbuf script = STRBUF_INIT;\n> > +\tint i, count = 0;\n> > +\tchar *p, *p2, **env;\n> > +\tsize_t env_size;\n> > +\n> > +\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n> > +\t\treturn NULL;\n> > +\n> > +\tfor (p = script.buf; *p; p++)\n> > +\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n> > +\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n> > +\t\telse if (*p == '\\'')\n> > +\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n> > +\t\telse if (*p == '\\n') {\n> > +\t\t\t*p = '\\0';\n> > +\t\t\tcount++;\n> > +\t\t}\n> \n> Hmph, didn't we recently add parse_key_value_squoted() to build\n> read_author_script() in builtin/am.c on top of it, so that this\n> piece of code can also take advantage of and share the parser?\n\nI already pointed out that the author-script file may *not* be quoted.\nsq_dequote() would return NULL and parse_key_value_squoted() would *fail*.\n\nTo complicate things further, the sequencer does not even need to access\nthe values at all. It needs to pass them to run_command() as an\nenvironment block, which means that we would have to reconstruct the lines\nafter parse_key_value_squoted() painstakingly untangled the key names from\nthe values.\n\nIn short, this is another instance where using a function just because it\nexists and is nominally related would make the resulting patch *more*\ncomplicated than it currently is.\n\n> > +/*\n> \n> Offtopic: this line and the beginning of the new comment block that\n> begins with \"Read the author-script\" above show a suboptimal marking\n> of what is added and what is left.  I wonder \"diff-indent-heuristic\"\n> topic by Michael can help to make it look better.\n\nMaybe. I'll try to look into that once the more serious questions about\nthis patch series have been addressed.\n\nCiao,\nDscho\n"},{"id":"303978","messageId":"alpine.DEB.2.20.1610121405410.3492@virtualbox","threadId":"43954","inReplyTo":"xmqq4m4ic0gw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-12T12:06:09Z","receivedAt":"2016-10-12T12:12:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 11 Oct 2016, Junio C Hamano wrote:\n\n> The only reason why the OPT_STRDUP appeared convenient was because\n> options[] element happened to use a field in the structure directly.\n> The patch under discussion does an equivalent of\n> \n>     app.x_field = xstrdup_or_null(opt_x);\n\nOh, that xstrdup_or_null() function slipped by me. My local patches use it\nnow.\n\nCiao,\nDscho\n"},{"id":"304007","messageId":"xmqqbmyp5ycw.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610121347361.3492@virtualbox","subject":"Re: [PATCH v3 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-12T16:24:47Z","receivedAt":"2016-10-12T16:24:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +\tconst char *arg;\n>> > +\tint arg_len;\n>> >  \tsize_t offset_in_buf;\n>> \n>> micronit: you can make it to size_t and lose the cast below, no?\n>\n> No. The primary users of arg_len call a printf() style function with %.*s,\n> expecting an int. So your suggestion would lose one cast, but introduce at\n> least four casts in return.\n\nActually my point was not the number of casts required, but more\nabout using the correct type to store things.  Granted, I do not\nexpect each of the lines would ever get too long to exceed \"int\"\n(but fit in \"size_t\") in practice, and from that point of view, one\nmay be able to argue that \"int\" and \"size_t\" are both correct types,\nbut that argument applies equally to offset_in_buf, so...\n\n\n"},{"id":"304011","messageId":"xmqq60ox5wxb.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610121356510.3492@virtualbox","subject":"Re: [PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-12T16:55:44Z","receivedAt":"2016-10-12T16:55:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Hmph, didn't we recently add parse_key_value_squoted() to build\n>> read_author_script() in builtin/am.c on top of it, so that this\n>> piece of code can also take advantage of and share the parser?\n>\n> I already pointed out that the author-script file may *not* be quoted.\n\nI think my puzzlement comes from here.  What makes it OK for \"am\" to\nexpect the contents of author-script file to be quoted but it is not\nOK to expect the same here?  What makes it not quoted for _this_\nreader, in other words?\n\nI am not sure what you meant by \"nominally related\", but the purpose\nof the author-script in these two codepaths is the same, isn't it?\nSomebody leaves the author information from the source (either from\nan e-mailed patch or an existing commit), so that a later step can\nuse that pieces of information left in the file when (re)creating a\ncommit to record the tree made by using pieces of information from\nthe source.\n\nAre our use in the author-script in these two codepaths _already_\ninconsistent?  IOW, \"am\" never writes malformed unquoted values,\nwhile the sequencer writes out in a way that is randomly quoted or\nnot quoted, iow, if you fed such an author-file to \"am\", it wouldn't\nunderstand it?\n\nI fully support your position to use different codepaths, if the\nfile that has the same name and that is used for the same purpose\nuses different format in these two separate codepaths and the users\nalready expect them to be different.  We obviously need to have two\nseparate parsers.\n\nBut if that is not the case, IOW, if \"am\"'s author-script shares the\nsame issue (i.e. \"'am' initially writes the file properly quoted,\nbut this or that can happen to change its quoting and we need to\nread from such a file\"), then perhaps sharing needs to happen the\nother way around?  This patch may prepare \"rebase -i\" side for the\n\"this or that\" (I still do not know what they are) to allow the\nresulting file read correctly, but the same \"this or that\" can break\nwhat \"am\" has used and is in use there if that is the case, no?\n\nWhat makes it OK for \"am\" to expect the contents of author-script\nfile to be quoted but it is not OK to expect the same here?  What\nmakes it not quoted for _this_ reader, and doesn't \"am\" share the\nsame issue?\n\n>> > +/*\n>> \n>> Offtopic: this line and the beginning of the new comment block that\n>> begins with \"Read the author-script\" above show a suboptimal marking\n>> of what is added and what is left.  I wonder \"diff-indent-heuristic\"\n>> topic by Michael can help to make it look better.\n>\n> Maybe. I'll try to look into that once the more serious questions about\n> this patch series have been addressed.\n\nYou do not have to; the remark was meant for Michael (newly cc'ed in\nthe message you are responding to).\n"},{"id":"304019","messageId":"xmqqk2dd4efs.fsf_-_@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610121405410.3492@virtualbox","subject":"Re* [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-12T18:20:23Z","receivedAt":"2016-10-12T18:20:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Tue, 11 Oct 2016, Junio C Hamano wrote:\n>\n>> The only reason why the OPT_STRDUP appeared convenient was because\n>> options[] element happened to use a field in the structure directly.\n>> The patch under discussion does an equivalent of\n>> \n>>     app.x_field = xstrdup_or_null(opt_x);\n>\n> Oh, that xstrdup_or_null() function slipped by me. My local patches use it\n> now.\n\nIt has slipped many people ;-)\n\n-- >8 --\nSubject: cocci: refactor common patterns to use xstrdup_or_null()\n\nd64ea0f83b (\"git-compat-util: add xstrdup_or_null helper\",\n2015-01-12) added a handy wrapper that allows us to get a duplicate\nof a string or NULL if the original is NULL, but a handful of\ncodepath predate its introduction or just weren't aware of it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n contrib/coccinelle/xstrdup_or_null.cocci | 7 +++++++\n git.c                                    | 3 +--\n imap-send.c                              | 6 ++----\n mailmap.c                                | 6 ++----\n refs.c                                   | 3 +--\n send-pack.c                              | 3 +--\n trailer.c                                | 9 +++------\n 7 files changed, 17 insertions(+), 20 deletions(-)\n\ndiff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/contrib/coccinelle/xstrdup_or_null.cocci\nnew file mode 100644\nindex 0000000000..3fceef132b\n--- /dev/null\n+++ b/contrib/coccinelle/xstrdup_or_null.cocci\n@@ -0,0 +1,7 @@\n+@@\n+expression E;\n+expression V;\n+@@\n+- if (E)\n+-    V = xstrdup(E);\n++ V = xstrdup_or_null(E);\ndiff --git a/git.c b/git.c\nindex 0f1937fd0c..f914490e14 100644\n--- a/git.c\n+++ b/git.c\n@@ -35,8 +35,7 @@ static void save_env_before_alias(void)\n \torig_cwd = xgetcwd();\n \tfor (i = 0; i < ARRAY_SIZE(env_names); i++) {\n \t\torig_env[i] = getenv(env_names[i]);\n-\t\tif (orig_env[i])\n-\t\t\torig_env[i] = xstrdup(orig_env[i]);\n+\t\torig_env[i] = xstrdup_or_null(orig_env[i]);\n \t}\n }\n \ndiff --git a/imap-send.c b/imap-send.c\nindex 0f5f4760e9..9514ddc565 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -1082,10 +1082,8 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f\n \t\t\tcred.protocol = xstrdup(srvc->use_ssl ? \"imaps\" : \"imap\");\n \t\t\tcred.host = xstrdup(srvc->host);\n \n-\t\t\tif (srvc->user)\n-\t\t\t\tcred.username = xstrdup(srvc->user);\n-\t\t\tif (srvc->pass)\n-\t\t\t\tcred.password = xstrdup(srvc->pass);\n+\t\t\tcred.username = xstrdup_or_null(srvc->user);\n+\t\t\tcred.password = xstrdup_or_null(srvc->pass);\n \n \t\t\tcredential_fill(&cred);\n \ndiff --git a/mailmap.c b/mailmap.c\nindex b5c521fdea..c1a79c100c 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -103,10 +103,8 @@ static void add_mapping(struct string_list *map,\n \t} else {\n \t\tstruct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));\n \t\tdebug_mm(\"mailmap: adding (complex) entry for '%s'\\n\", old_email);\n-\t\tif (new_name)\n-\t\t\tmi->name = xstrdup(new_name);\n-\t\tif (new_email)\n-\t\t\tmi->email = xstrdup(new_email);\n+\t\tmi->name = xstrdup_or_null(new_name);\n+\t\tmi->email = xstrdup_or_null(new_email);\n \t\tstring_list_insert(&me->namemap, old_name)->util = mi;\n \t}\n \ndiff --git a/refs.c b/refs.c\nindex b4e7cac7b2..62055ab091 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -791,8 +791,7 @@ struct ref_update *ref_transaction_add_update(\n \t\thashcpy(update->new_sha1, new_sha1);\n \tif (flags & REF_HAVE_OLD)\n \t\thashcpy(update->old_sha1, old_sha1);\n-\tif (msg)\n-\t\tupdate->msg = xstrdup(msg);\n+\tupdate->msg = xstrdup_or_null(msg);\n \treturn update;\n }\n \ndiff --git a/send-pack.c b/send-pack.c\nindex 90f2ac51a7..6195b43e9a 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -181,8 +181,7 @@ static int receive_status(int in, struct ref *refs)\n \t\t\thint->status = REF_STATUS_REMOTE_REJECT;\n \t\t\tret = -1;\n \t\t}\n-\t\tif (msg)\n-\t\t\thint->remote_status = xstrdup(msg);\n+\t\thint->remote_status = xstrdup_or_null(msg);\n \t\t/* start our next search from the next ref */\n \t\thint = hint->next;\n \t}\ndiff --git a/trailer.c b/trailer.c\nindex c6ea9ac64d..aecaf9232a 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -428,12 +428,9 @@ static int set_if_missing(struct conf_info *item, const char *value)\n static void duplicate_conf(struct conf_info *dst, struct conf_info *src)\n {\n \t*dst = *src;\n-\tif (src->name)\n-\t\tdst->name = xstrdup(src->name);\n-\tif (src->key)\n-\t\tdst->key = xstrdup(src->key);\n-\tif (src->command)\n-\t\tdst->command = xstrdup(src->command);\n+\tdst->name = xstrdup_or_null(src->name);\n+\tdst->key = xstrdup_or_null(src->key);\n+\tdst->command = xstrdup_or_null(src->command);\n }\n \n static struct trailer_item *get_conf_item(const char *name)\n"},{"id":"304026","messageId":"d24a3823-1ed0-ad97-f02d-febab7a97590@kdbg.org","threadId":"43954","inReplyTo":"e38bf77ff57d06ca3250bc3ec71a34088b49abd0.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 25/25] sequencer: mark all error messages for translation","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-10-12T20:46:15Z","receivedAt":"2016-10-12T20:46:23Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 10.10.2016 um 19:26 schrieb Johannes Schindelin:\n> There was actually only one error message that was not yet marked for\n> translation.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 23 +++++++++++++----------\n>  1 file changed, 13 insertions(+), 10 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 676f16c..86d86ce 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -515,16 +515,19 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\tif (!env) {\n>  \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n>  \n> -\t\t\treturn error(\"you have staged changes in your working \"\n> -\t\t\t\t\"tree. If these changes are meant to be\\n\"\n> -\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n> -\t\t\t\t\"  git commit --amend %s\\n\\n\"\n> -\t\t\t\t\"If they are meant to go into a new commit, \"\n> -\t\t\t\t\"run:\\n\\n\"\n> -\t\t\t\t\"  git commit %s\\n\\n\"\n> -\t\t\t\t\"In both cases, once you're done, continue \"\n> -\t\t\t\t\"with:\\n\\n\"\n> -\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n> +\t\t\treturn error(_(\"you have staged changes in your \"\n> +\t\t\t\t       \"working tree. If these changes are \"\n> +\t\t\t\t       \"meant to be\\n\"\n> +\t\t\t\t       \"squashed into the previous commit, \"\n> +\t\t\t\t       \"run:\\n\\n\"\n> +\t\t\t\t       \"  git commit --amend %s\\n\\n\"\n> +\t\t\t\t       \"If they are meant to go into a new \"\n> +\t\t\t\t       \"commit, run:\\n\\n\"\n> +\t\t\t\t       \"  git commit %s\\n\\n\"\n> +\t\t\t\t       \"In both cases, once you're done, \"\n> +\t\t\t\t       \"continue with:\\n\\n\"\n> +\t\t\t\t       \"  git rebase --continue\\n\"),\n> +\t\t\t\t     gpg_opt, gpg_opt);\n>  \t\t}\n>  \t}\n>  \n> \n\nCan we please have the following change instead? I think it makes sense\nto deviate from the usual conventions in a case like this.\n\nNote that this is an error() text, hence, there should not be a\nfullstop on the first line. That's now a good excuse to start the next\nsentence on a new line; hence, this is not a faithful conversion to _()\nanymore (a will happily take authorship and all blame if you don't\nwant to for this reason). Also note that _( is not moved to the\nbeginning of the line because it would be picked up as hunk header by\ngit diff.\n\n---- 8< ----\nFrom: Johannes Schindelin <johannes.schindelin@gmx.de>\nSubject: [PATCH] sequencer: mark all error messages for translation\n\nThere was actually only one error message that was not yet marked for\ntranslation.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n sequencer.c | 24 ++++++++++++++----------\n 1 file changed, 14 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 95a382e..79f7aa4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -515,16 +515,20 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"you have staged changes in your working \"\n-\t\t\t\t\"tree. If these changes are meant to be\\n\"\n-\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend %s\\n\\n\"\n-\t\t\t\t\"If they are meant to go into a new commit, \"\n-\t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit %s\\n\\n\"\n-\t\t\t\t\"In both cases, once you're done, continue \"\n-\t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t\treturn error(_(\n+\"you have staged changes in your working tree\\n\"\n+\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n+\"\\n\"\n+\"  git commit --amend %s\\n\"\n+\"\\n\"\n+\"If they are meant to go into a new commit, run:\\n\"\n+\"\\n\"\n+\"  git commit %s\\n\"\n+\"\\n\"\n+\"In both cases, once you're done, continue with:\\n\"\n+\"\\n\"\n+\"  git rebase --continue\\n\"),\n+\t\t\t\t     gpg_opt, gpg_opt);\n \t\t}\n \t}\n \n-- \n2.10.0.343.g37bc62b\n\n\n"},{"id":"304029","messageId":"xmqqlgxt2rch.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"d24a3823-1ed0-ad97-f02d-febab7a97590@kdbg.org","subject":"Re: [PATCH v3 25/25] sequencer: mark all error messages for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-12T21:24:30Z","receivedAt":"2016-10-12T21:24:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Can we please have the following change instead? I think it makes sense\n> to deviate from the usual conventions in a case like this.\n\nYou have at least two independent changes relative to Dscho's\nversion.  \n\n (1) Show line breaks more prominently by avoiding \"\\n\\n\" and\n     breaking the string at \"\\n\"; this matches the way how the\n     result would be displayed more closely to how the source looks\n     like.\n\n (2) Ignore the usual indentation rule and have messages start at\n     the left end of the source.\n\nWhich one are you saying \"makes sense\" to?  Both?\n\nI guess both can be grouped together into one theme: match the way\nthe final output and the source code look like.\n\nIf that is the motivation behind \"makes sense\", I'd prefer to see\nthe change explained explicitly with that rationale in the log\nmessage.\n\nThanks.  I personally agree with that motivation (if the one I\nguessed above is your motivation, that is).\n\n> Note that this is an error() text, hence, there should not be a\n> fullstop on the first line. That's now a good excuse to start the next\n> sentence on a new line; hence, this is not a faithful conversion to _()\n> anymore (a will happily take authorship and all blame if you don't\n> want to for this reason). Also note that _( is not moved to the\n> beginning of the line because it would be picked up as hunk header by\n> git diff.\n>\n> ---- 8< ----\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Subject: [PATCH] sequencer: mark all error messages for translation\n>\n> There was actually only one error message that was not yet marked for\n> translation.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Signed-off-by: Johannes Sixt <j6t@kdbg.org>\n> ---\n>  sequencer.c | 24 ++++++++++++++----------\n>  1 file changed, 14 insertions(+), 10 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 95a382e..79f7aa4 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -515,16 +515,20 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\tif (!env) {\n>  \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n>  \n> -\t\t\treturn error(\"you have staged changes in your working \"\n> -\t\t\t\t\"tree. If these changes are meant to be\\n\"\n> -\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n> -\t\t\t\t\"  git commit --amend %s\\n\\n\"\n> -\t\t\t\t\"If they are meant to go into a new commit, \"\n> -\t\t\t\t\"run:\\n\\n\"\n> -\t\t\t\t\"  git commit %s\\n\\n\"\n> -\t\t\t\t\"In both cases, once you're done, continue \"\n> -\t\t\t\t\"with:\\n\\n\"\n> -\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n> +\t\t\treturn error(_(\n> +\"you have staged changes in your working tree\\n\"\n> +\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n> +\"\\n\"\n> +\"  git commit --amend %s\\n\"\n> +\"\\n\"\n> +\"If they are meant to go into a new commit, run:\\n\"\n> +\"\\n\"\n> +\"  git commit %s\\n\"\n> +\"\\n\"\n> +\"In both cases, once you're done, continue with:\\n\"\n> +\"\\n\"\n> +\"  git rebase --continue\\n\"),\n> +\t\t\t\t     gpg_opt, gpg_opt);\n>  \t\t}\n>  \t}\n"},{"id":"304070","messageId":"alpine.DEB.2.20.1610131241030.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqbmyp5ycw.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-13T10:41:48Z","receivedAt":"2016-10-13T10:50:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 12 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> > +\tconst char *arg;\n> >> > +\tint arg_len;\n> >> >  \tsize_t offset_in_buf;\n> >> \n> >> micronit: you can make it to size_t and lose the cast below, no?\n> >\n> > No. The primary users of arg_len call a printf() style function with %.*s,\n> > expecting an int. So your suggestion would lose one cast, but introduce at\n> > least four casts in return.\n> \n> Actually my point was not the number of casts required, but more\n> about using the correct type to store things.  Granted, I do not\n> expect each of the lines would ever get too long to exceed \"int\"\n> (but fit in \"size_t\") in practice, and from that point of view, one\n> may be able to argue that \"int\" and \"size_t\" are both correct types,\n> but that argument applies equally to offset_in_buf, so...\n\nYou cannot make it a size_t without changing the printf() standard to\nexpect size_t for %.*s, because that is the intended usage of that field\nin these here patches.\n\nCiao,\nDscho\n"},{"id":"304071","messageId":"alpine.DEB.2.20.1610131242100.197091@virtualbox","threadId":"43954","inReplyTo":"xmqq60ox5wxb.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-13T10:50:16Z","receivedAt":"2016-10-13T10:57:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 12 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Hmph, didn't we recently add parse_key_value_squoted() to build\n> >> read_author_script() in builtin/am.c on top of it, so that this\n> >> piece of code can also take advantage of and share the parser?\n> >\n> > I already pointed out that the author-script file may *not* be quoted.\n> \n> I think my puzzlement comes from here.  What makes it OK for \"am\" to\n> expect the contents of author-script file to be quoted but it is not\n> OK to expect the same here?  What makes it not quoted for _this_\n> reader, in other words?\n\nThe `git am` command is inherently *not* interactive, while the\ninteractive rebase, well, is.\n\nAs such, we must assume that enterprisey users did come up with scripts\nthat edit, or create, author-script files, and exploited the fact that the\ninteractive rebase previously sourced them.\n\nCome to think of it, there is a bigger problem here, as users might have\nabused the author-script to execute commands in rebase -i's own context.\nNot sure we can do anything about that.\n\nBut the point stands, if anybody used unquoted, or differently quoted,\nvalues in author-script, we should at least attempt within reason to\nsupport that.\n\n> I am not sure what you meant by \"nominally related\", but the purpose\n> of the author-script in these two codepaths is the same, isn't it?\n\nThe purpose is, but the means aren't. As I pointed out above, the\ninteractive rebase is inherently much more interactive, and needs to be\nmuch more forgiving in its input, than `git am`.\n\n> Somebody leaves the author information from the source (either from\n> an e-mailed patch or an existing commit), so that a later step can\n> use that pieces of information left in the file when (re)creating a\n> commit to record the tree made by using pieces of information from\n> the source.\n> \n> Are our use in the author-script in these two codepaths _already_\n> inconsistent?  IOW, \"am\" never writes malformed unquoted values,\n> while the sequencer writes out in a way that is randomly quoted or\n> not quoted, iow, if you fed such an author-file to \"am\", it wouldn't\n> understand it?\n\nWe heed Postel's Law: what the sequencer writes is in a very strict\nformat, but what the sequencer accepts need not be.\n\n> I fully support your position to use different codepaths, if the\n> file that has the same name and that is used for the same purpose\n> uses different format in these two separate codepaths and the users\n> already expect them to be different.  We obviously need to have two\n> separate parsers.\n\nWell, traditionally we *do* have separate parsers. I do not say that we\nneed to keep that, but given what I said above, it might not be a bad idea\nto keep the lenient parser required by `git rebase -i` separate from the\none used by `git am` so that the latter can be faster (by making\nassumptions the other parser cannot).\n\n> But if that is not the case, IOW, if \"am\"'s author-script shares the\n> same issue (i.e. \"'am' initially writes the file properly quoted,\n> but this or that can happen to change its quoting and we need to\n> read from such a file\"), then perhaps sharing needs to happen the\n> other way around?  This patch may prepare \"rebase -i\" side for the\n> \"this or that\" (I still do not know what they are) to allow the\n> resulting file read correctly, but the same \"this or that\" can break\n> what \"am\" has used and is in use there if that is the case, no?\n> \n> What makes it OK for \"am\" to expect the contents of author-script\n> file to be quoted but it is not OK to expect the same here?  What\n> makes it not quoted for _this_ reader, and doesn't \"am\" share the\n> same issue?\n\nThe fact that `git am` is *non-interactive*.\n\nCiao,\nDscho\n"},{"id":"304072","messageId":"alpine.DEB.2.20.1610131251000.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqk2dd4efs.fsf_-_@gitster.mtv.corp.google.com","subject":"Re: Re* [PATCH v3 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-13T10:51:11Z","receivedAt":"2016-10-13T10:58:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 12 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 11 Oct 2016, Junio C Hamano wrote:\n> >\n> >> The only reason why the OPT_STRDUP appeared convenient was because\n> >> options[] element happened to use a field in the structure directly.\n> >> The patch under discussion does an equivalent of\n> >> \n> >>     app.x_field = xstrdup_or_null(opt_x);\n> >\n> > Oh, that xstrdup_or_null() function slipped by me. My local patches use it\n> > now.\n> \n> It has slipped many people ;-)\n\nThanks, I feel better now ;-)\n\nCiao,\nDscho\n"},{"id":"304077","messageId":"alpine.DEB.2.20.1610131518220.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqlgxt2rch.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 25/25] sequencer: mark all error messages for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-13T14:56:28Z","receivedAt":"2016-10-13T14:57:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 12 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Sixt <j6t@kdbg.org> writes:\n> \n> > Can we please have the following change instead? I think it makes sense\n> > to deviate from the usual conventions in a case like this.\n> \n> You have at least two independent changes relative to Dscho's\n> version.  \n> \n>  (1) Show line breaks more prominently by avoiding \"\\n\\n\" and\n>      breaking the string at \"\\n\"; this matches the way how the\n>      result would be displayed more closely to how the source looks\n>      like.\n> \n>  (2) Ignore the usual indentation rule and have messages start at\n>      the left end of the source.\n> \n> Which one are you saying \"makes sense\" to?  Both?\n> \n> I guess both can be grouped together into one theme: match the way\n> the final output and the source code look like.\n> \n> If that is the motivation behind \"makes sense\", I'd prefer to see\n> the change explained explicitly with that rationale in the log\n> message.\n> \n> Thanks.  I personally agree with that motivation (if the one I\n> guessed above is your motivation, that is).\n\nI agree with that motivation, but I decided to go about it in a way that\nis more in line with the existing source code:\n\n-- snipsnap --\ndiff --git a/sequencer.c b/sequencer.c\nindex 8e10bb5..1cf70f7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -483,6 +483,20 @@ static char **read_author_script(void)\n \treturn env;\n }\n \n+static const char staged_changes_advice[] =\n+N_(\"you have staged changes in your working tree\\n\"\n+\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n+\"\\n\"\n+\"  git commit --amend %s\\n\"\n+\"\\n\"\n+\"If they are meant to go into a new commit, run:\\n\"\n+\"\\n\"\n+\"  git commit %s\\n\"\n+\"\\n\"\n+\"In both cases, once you're done, continue with:\\n\"\n+\"\\n\"\n+\"  git rebase --continue\\n\");\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -509,18 +523,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(\"you have staged changes in your \"\n-\t\t\t\t       \"working tree. If these changes are \"\n-\t\t\t\t       \"meant to be\\n\"\n-\t\t\t\t       \"squashed into the previous commit, \"\n-\t\t\t\t       \"run:\\n\\n\"\n-\t\t\t\t       \"  git commit --amend %s\\n\\n\"\n-\t\t\t\t       \"If they are meant to go into a new \"\n-\t\t\t\t       \"commit, run:\\n\\n\"\n-\t\t\t\t       \"  git commit %s\\n\\n\"\n-\t\t\t\t       \"In both cases, once you're done, \"\n-\t\t\t\t       \"continue with:\\n\\n\"\n-\t\t\t\t       \"  git rebase --continue\\n\"),\n+\t\t\treturn error(_(staged_changes_advice),\n \t\t\t\t     gpg_opt, gpg_opt);\n \t\t}\n \t}\n"},{"id":"304093","messageId":"4f283639-7cca-c62a-b8dc-5e7dbcf8315f@kdbg.org","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610131518220.197091@virtualbox","subject":"Re: [PATCH v3 25/25] sequencer: mark all error messages for translation","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-10-13T20:35:15Z","receivedAt":"2016-10-13T20:36:43Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 13.10.2016 um 16:56 schrieb Johannes Schindelin:\n> On Wed, 12 Oct 2016, Junio C Hamano wrote:\n>> You have at least two independent changes relative to Dscho's\n>> version.\n>>\n>>  (1) Show line breaks more prominently by avoiding \"\\n\\n\" and\n>>      breaking the string at \"\\n\"; this matches the way how the\n>>      result would be displayed more closely to how the source looks\n>>      like.\n>>\n>>  (2) Ignore the usual indentation rule and have messages start at\n>>      the left end of the source.\n>>\n>> Which one are you saying \"makes sense\" to?  Both?\n>>\n>> I guess both can be grouped together into one theme: match the way\n>> the final output and the source code look like.\n\nYes, that summarizes it pretty well.\n\n> I agree with that motivation, but I decided to go about it in a way that\n> is more in line with the existing source code:\n>\n> -- snipsnap --\n> diff --git a/sequencer.c b/sequencer.c\n> index 8e10bb5..1cf70f7 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -483,6 +483,20 @@ static char **read_author_script(void)\n>  \treturn env;\n>  }\n>\n> +static const char staged_changes_advice[] =\n> +N_(\"you have staged changes in your working tree\\n\"\n> +\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n> +\"\\n\"\n> +\"  git commit --amend %s\\n\"\n> +\"\\n\"\n> +\"If they are meant to go into a new commit, run:\\n\"\n> +\"\\n\"\n> +\"  git commit %s\\n\"\n> +\"\\n\"\n> +\"In both cases, once you're done, continue with:\\n\"\n> +\"\\n\"\n> +\"  git rebase --continue\\n\");\n\nMuch better! Thank you.\n\n-- Hannes\n\n"},{"id":"304107","messageId":"38d5f853444f80c90713f7a6e4ef1f2382549b29.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 18/25] sequencer: do not try to commit when there were merge conflicts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:31Z","receivedAt":"2016-10-14T13:19:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The return value of do_recursive_merge() may be positive (indicating merge\nconflicts), or 0 (indicating success). It also may be negative, indicating\na fatal error that requires us to abort.\n\nNow, if the return value indicates that there are merge conflicts, we\nshould not try to commit those changes, of course.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cbc3742..9ffc090 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -787,7 +787,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tres = allow;\n \t\tgoto leave;\n \t}\n-\tif (!opts->no_commit)\n+\tif (!res && !opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n \t\t\t\t     opts, allow, opts->edit, 0, 0);\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304108","messageId":"4173eb7716e8f4fbd083961a05dc4329686a9912.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 17/25] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:28Z","receivedAt":"2016-10-14T13:19:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The run_git_commit() function already knows how to amend commits, and\nwith this new option, it can also clean up commit messages (i.e. strip\nout commented lines). This is needed to implement rebase -i's 'fixup'\nand 'squash' commands as sequencer commands.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex fa77c82..cbc3742 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -481,7 +481,8 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend)\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -518,9 +519,12 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (cleanup_commit_message)\n+\t\targv_array_push(&array, \"--cleanup=strip\");\n \tif (edit)\n \t\targv_array_push(&array, \"-e\");\n-\telse if (!opts->signoff && !opts->record_origin &&\n+\telse if (!cleanup_commit_message &&\n+\t\t !opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n \t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n@@ -785,7 +789,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit, 0);\n+\t\t\t\t     opts, allow, opts->edit, 0, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304109","messageId":"48167f26c68728e7df42244b07a4f4e17f6105f5.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 16/25] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:25Z","receivedAt":"2016-10-14T13:19:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This teaches the run_git_commit() function to take an argument that will\nallow us to implement \"todo\" commands that need to amend the commit\nmessages (\"fixup\", \"squash\" and \"reword\").\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 2ef80e7..fa77c82 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -481,7 +481,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit)\n+\t\t\t  int allow_empty, int edit, int amend)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -510,6 +510,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n \n+\tif (amend)\n+\t\targv_array_push(&array, \"--amend\");\n \tif (opts->gpg_sign)\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n@@ -783,7 +785,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit);\n+\t\t\t\t     opts, allow, opts->edit, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304110","messageId":"fab86d51e987682061bdeec75d1fcff832f970eb.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 19/25] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:34Z","receivedAt":"2016-10-14T13:19:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Interactive rebase's scripts may be indented; we need to handle this\ncase, too, now that we prepare the sequencer to process interactive\nrebases.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 9ffc090..914a576 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -871,6 +871,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tchar *end_of_object_name;\n \tint i, saved, status, padding;\n \n+\t/* left-trim */\n+\tbol += strspn(bol, \" \\t\");\n+\n \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n \t\t\titem->command = i;\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304111","messageId":"dbfd332f77b9077b03454fd7dc079fefb8d0c284.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:19Z","receivedAt":"2016-10-14T13:19:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As we are slowly teaching the sequencer to perform the hard work for\nthe interactive rebase, we need to read files that were written by\nshell scripts.\n\nThese files typically contain a single line and are invariably ended\nby a line feed (and possibly a carriage return before that). Let's use\na helper to read such files and to remove the line ending.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 31 +++++++++++++++++++++++++++++++\n 1 file changed, 31 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 99c39fb..de6b95f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,6 +234,37 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \treturn 0;\n }\n \n+/*\n+ * Reads a file that was presumably written by a shell script, i.e.\n+ * with an end-of-line marker that needs to be stripped.\n+ *\n+ * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n+ */\n+static int read_oneliner(struct strbuf *buf,\n+\tconst char *path, int skip_if_empty)\n+{\n+\tint orig_len = buf->len;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (strbuf_read_file(buf, path, 0) < 0) {\n+\t\twarning_errno(_(\"could not read '%s'\"), path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n+\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n+\t\t\t--buf->len;\n+\t\tbuf->buf[buf->len] = '\\0';\n+\t}\n+\n+\tif (skip_if_empty && buf->len == orig_len)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static struct tree *empty_tree(void)\n {\n \treturn lookup_tree(EMPTY_TREE_SHA1_BIN);\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304112","messageId":"e356ddc226718e496d11bd5de5670dcb9eb64c77.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 12/25] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:12Z","receivedAt":"2016-10-14T13:19:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The `git-rebase-todo` file contains a list of commands. Most of those\ncommands have the form\n\n\t<verb> <sha1> <oneline>\n\nThe <oneline> is displayed primarily for the user's convenience, as\nrebase -i really interprets only the <verb> <sha1> part. However, there\nare *some* places in interactive rebase where the <oneline> is used to\ndisplay messages, e.g. for reporting at which commit we stopped.\n\nSo let's just remember it when parsing the todo file; we keep a copy of\nthe entire todo file anyway (to write out the new `done` and\n`git-rebase-todo` file just before processing each command), so all we\nneed to do is remember the begin offsets and lengths.\n\nAs we will have to parse and remember the command-line for `exec` commands\nlater, we do not call the field \"oneline\" but rather \"arg\" (and will reuse\nthat for exec's command-line).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5e4bf23..caef51e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -706,6 +706,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n struct todo_item {\n \tenum todo_command command;\n \tstruct commit *commit;\n+\tconst char *arg;\n+\tint arg_len;\n \tsize_t offset_in_buf;\n };\n \n@@ -757,6 +759,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n+\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n+\titem->arg_len = (int)(eol - item->arg);\n+\n \tif (status < 0)\n \t\treturn -1;\n \n@@ -907,6 +912,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \n \t\titem->command = command;\n \t\titem->commit = commit;\n+\t\titem->arg = NULL;\n+\t\titem->arg_len = 0;\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304113","messageId":"344d5d872f32e796d39eb515ff034cfe704eea5a.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 15/25] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:22Z","receivedAt":"2016-10-14T13:19:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In the upcoming commits, we will implement more and more of rebase -i's\nfunctionality inside the sequencer. One particular feature of the\ncommands to come is that some of them allow editing the commit message\nwhile others don't, i.e. we cannot define in the replay_opts whether the\ncommit message should be edited or not.\n\nLet's add a new parameter to the run_git_commit() function. Previously,\nit was the duty of the caller to ensure that the opts->edit setting\nindicates whether to let the user edit the commit message or not,\nindicating that it is an \"all or nothing\" setting, i.e. that the\nsequencer wants to let the user edit *all* commit message, or none at\nall. In the upcoming rebase -i mode, it will depend on the particular\ncommand that is currently executed, though.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 48 ++++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 40 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex de6b95f..2ef80e7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -15,6 +15,7 @@\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n #include \"argv-array.h\"\n+#include \"quote.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n  * being rebased.\n  */\n static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+/*\n+ * The following files are written by git-rebase just after parsing the\n+ * command-line (and are only consumed, not modified, by the sequencer).\n+ */\n+static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n \n /* We will introduce the 'interactive rebase' mode later */\n static inline int is_rebase_i(const struct replay_opts *opts)\n@@ -132,6 +138,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n+{\n+\tstatic struct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_reset(&buf);\n+\tif (opts->gpg_sign)\n+\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n+\treturn buf.buf;\n+}\n+\n int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n@@ -465,7 +481,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty)\n+\t\t\t  int allow_empty, int edit)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -474,17 +490,20 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tif (is_rebase_i(opts)) {\n \t\tenv = read_author_script();\n-\t\tif (!env)\n+\t\tif (!env) {\n+\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\n \t\t\treturn error(\"You have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit --amend %s\\n\\n\"\n \t\t\t\t\"If they are meant to go into a new commit, \"\n \t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit %s\\n\\n\"\n \t\t\t\t\"In both cases, once you're done, continue \"\n \t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\");\n+\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t}\n \t}\n \n \targv_array_init(&array);\n@@ -497,7 +516,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n-\tif (opts->edit)\n+\tif (edit)\n \t\targv_array_push(&array, \"-e\");\n \telse if (!opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n@@ -764,7 +783,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow);\n+\t\t\t\t     opts, allow, opts->edit);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -986,8 +1005,21 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n-\tif (is_rebase_i(opts))\n+\tif (is_rebase_i(opts)) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n+\t\t\tif (!starts_with(buf.buf, \"-S\"))\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\telse {\n+\t\t\t\tfree(opts->gpg_sign);\n+\t\t\t\topts->gpg_sign = xstrdup(buf.buf + 2);\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\n \t\treturn 0;\n+\t}\n \n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304114","messageId":"131c4fa182879f1a20341f67cd0c82c7fe7be84b.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 11/25] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:00Z","receivedAt":"2016-10-14T13:19:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The subcommands are used exactly once, at the very beginning of\nsequencer_pick_revisions(), to determine what to do. This is an\nunnecessary level of indirection: we can simply call the correct\nfunction to begin with. So let's do that.\n\nWhile at it, ensure that the subcommands return an error code so that\nthey do not have to die() all over the place (bad practice for library\nfunctions...).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 36 ++++++++++++++++--------------------\n sequencer.c      | 35 +++++++++++------------------------\n sequencer.h      | 13 ++++---------\n 3 files changed, 31 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex ba5a88c..4ca5b51 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \t\tdie(_(\"%s: %s cannot be used with %s\"), me, this_opt, base_opt);\n }\n \n-static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n+static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tconst char *me = action_name(opts);\n@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n-\t/* Set the subcommand */\n-\tif (cmd == 'q')\n-\t\topts->subcommand = REPLAY_REMOVE_STATE;\n-\telse if (cmd == 'c')\n-\t\topts->subcommand = REPLAY_CONTINUE;\n-\telse if (cmd == 'a')\n-\t\topts->subcommand = REPLAY_ROLLBACK;\n-\telse\n-\t\topts->subcommand = REPLAY_NONE;\n-\n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\tchar *this_operation;\n-\t\tif (opts->subcommand == REPLAY_REMOVE_STATE)\n+\t\tif (cmd == 'q')\n \t\t\tthis_operation = \"--quit\";\n-\t\telse if (opts->subcommand == REPLAY_CONTINUE)\n+\t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n \t\telse {\n-\t\t\tassert(opts->subcommand == REPLAY_ROLLBACK);\n+\t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n \t\t}\n \n@@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--edit\", opts->edit,\n \t\t\t\tNULL);\n \n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\topts->revs = NULL;\n \t} else {\n \t\tstruct setup_revision_opt s_r_opt;\n@@ -178,6 +168,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t/* These option values will be free()d */\n \topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n \topts->strategy = xstrdup_or_null(opts->strategy);\n+\n+\tif (cmd == 'q')\n+\t\treturn sequencer_remove_state(opts);\n+\tif (cmd == 'c')\n+\t\treturn sequencer_continue(opts);\n+\tif (cmd == 'a')\n+\t\treturn sequencer_rollback(opts);\n+\treturn sequencer_pick_revisions(opts);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n@@ -189,8 +187,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -203,8 +200,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\ndiff --git a/sequencer.c b/sequencer.c\nindex 9bca056..5e4bf23 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -119,7 +119,7 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(const struct replay_opts *opts)\n+int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tint i;\n@@ -133,6 +133,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n+\n+\treturn 0;\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -975,7 +977,7 @@ static int rollback_single_pick(void)\n \treturn reset_for_rollback(head_sha1);\n }\n \n-static int sequencer_rollback(struct replay_opts *opts)\n+int sequencer_rollback(struct replay_opts *opts)\n {\n \tFILE *f;\n \tunsigned char sha1[20];\n@@ -1010,9 +1012,8 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n fail:\n \tstrbuf_release(&buf);\n \treturn -1;\n@@ -1097,8 +1098,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state(opts);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n }\n \n static int continue_single_pick(void)\n@@ -1111,11 +1111,14 @@ static int continue_single_pick(void)\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n \n-static int sequencer_continue(struct replay_opts *opts)\n+int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tint res;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts))\n@@ -1154,26 +1157,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tint i, res;\n \n-\tif (opts->subcommand == REPLAY_NONE)\n-\t\tassert(opts->revs);\n-\n+\tassert(opts->revs);\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\t/*\n-\t * Decide what to do depending on the arguments; a fresh\n-\t * cherry-pick should be handled differently from an existing\n-\t * one that is being continued\n-\t */\n-\tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state(opts);\n-\t\treturn 0;\n-\t}\n-\tif (opts->subcommand == REPLAY_ROLLBACK)\n-\t\treturn sequencer_rollback(opts);\n-\tif (opts->subcommand == REPLAY_CONTINUE)\n-\t\treturn sequencer_continue(opts);\n-\n \tfor (i = 0; i < opts->revs->pending.nr; i++) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = opts->revs->pending.objects[i].name;\ndiff --git a/sequencer.h b/sequencer.h\nindex 8453669..7a513c5 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -10,16 +10,8 @@ enum replay_action {\n \tREPLAY_PICK\n };\n \n-enum replay_subcommand {\n-\tREPLAY_NONE,\n-\tREPLAY_REMOVE_STATE,\n-\tREPLAY_CONTINUE,\n-\tREPLAY_ROLLBACK\n-};\n-\n struct replay_opts {\n \tenum replay_action action;\n-\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -44,9 +36,12 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n-#define REPLAY_OPTS_INIT { -1, -1 }\n+#define REPLAY_OPTS_INIT { -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n+int sequencer_continue(struct replay_opts *opts);\n+int sequencer_rollback(struct replay_opts *opts);\n+int sequencer_remove_state(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304115","messageId":"3ab64411bee7e90e9d4deb47d04709e416c17e9b.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:16Z","receivedAt":"2016-10-14T13:19:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In interactive rebases, we commit a little bit differently than the\nsequencer did so far: we heed the \"author-script\", the \"message\" and the\n\"amend\" files in the .git/rebase-merge/ subdirectory.\n\nLikewise, we may want to edit the commit message *even* when providing a\nfile containing the suggested commit message. Therefore we change the\ncode to not even provide a default message when we do not want any, and\nto call the editor explicitly.\n\nAlso, in \"interactive rebase\" mode we want to skip reading the options\nin the state directory of the cherry-pick/revert commands.\n\nFinally, as interactive rebase's GPG settings are configured differently\nfrom how cherry-pick (and therefore sequencer) handles them, we will\nleave support for that to the next commit.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 89 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex caef51e..99c39fb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+/*\n+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n+ * GIT_AUTHOR_DATE that will be used for the commit that is currently\n+ * being rebased.\n+ */\n+static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+\n+/* We will introduce the 'interactive rebase' mode later */\n+static inline int is_rebase_i(const struct replay_opts *opts)\n+{\n+\treturn 0;\n+}\n+\n static const char *get_dir(const struct replay_opts *opts)\n {\n \treturn git_path_seq_dir();\n@@ -370,19 +383,79 @@ static int is_index_unchanged(void)\n }\n \n /*\n+ * Read the author-script file into an environment block, ready for use in\n+ * run_command(), that can be free()d afterwards.\n+ */\n+static char **read_author_script(void)\n+{\n+\tstruct strbuf script = STRBUF_INIT;\n+\tint i, count = 0;\n+\tchar *p, *p2, **env;\n+\tsize_t env_size;\n+\n+\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n+\t\treturn NULL;\n+\n+\tfor (p = script.buf; *p; p++)\n+\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n+\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n+\t\telse if (*p == '\\'')\n+\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n+\t\telse if (*p == '\\n') {\n+\t\t\t*p = '\\0';\n+\t\t\tcount++;\n+\t\t}\n+\n+\tenv_size = (count + 1) * sizeof(*env);\n+\tstrbuf_grow(&script, env_size);\n+\tmemmove(script.buf + env_size, script.buf, script.len);\n+\tp = script.buf + env_size;\n+\tenv = (char **)strbuf_detach(&script, NULL);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tenv[i] = p;\n+\t\tp += strlen(p) + 1;\n+\t}\n+\tenv[count] = NULL;\n+\n+\treturn env;\n+}\n+\n+/*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n  * author date and name.\n+ *\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n+ *\n+ * An exception is when run_git_commit() is called during an\n+ * interactive rebase: in that case, we will want to retain the\n+ * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\t\t  int allow_empty)\n {\n+\tchar **env = NULL;\n \tstruct argv_array array;\n \tint rc;\n \tconst char *value;\n \n+\tif (is_rebase_i(opts)) {\n+\t\tenv = read_author_script();\n+\t\tif (!env)\n+\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\t\t\"tree. If these changes are meant to be\\n\"\n+\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n+\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"If they are meant to go into a new commit, \"\n+\t\t\t\t\"run:\\n\\n\"\n+\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"In both cases, once you're done, continue \"\n+\t\t\t\t\"with:\\n\\n\"\n+\t\t\t\t\"  git rebase --continue\\n\");\n+\t}\n+\n \targv_array_init(&array);\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n@@ -391,14 +464,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n \t\targv_array_push(&array, \"-s\");\n-\tif (!opts->edit) {\n-\t\targv_array_push(&array, \"-F\");\n-\t\targv_array_push(&array, defmsg);\n-\t\tif (!opts->signoff &&\n-\t\t    !opts->record_origin &&\n-\t\t    git_config_get_value(\"commit.cleanup\", &value))\n-\t\t\targv_array_push(&array, \"--cleanup=verbatim\");\n-\t}\n+\tif (defmsg)\n+\t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (opts->edit)\n+\t\targv_array_push(&array, \"-e\");\n+\telse if (!opts->signoff && !opts->record_origin &&\n+\t\t git_config_get_value(\"commit.cleanup\", &value))\n+\t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n \tif (allow_empty)\n \t\targv_array_push(&array, \"--allow-empty\");\n@@ -406,8 +478,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&array, \"--allow-empty-message\");\n \n-\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\trc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,\n+\t\t\t(const char *const *)env);\n \targv_array_clear(&array);\n+\tfree(env);\n+\n \treturn rc;\n }\n \n@@ -657,7 +732,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = run_git_commit(git_path_merge_msg(), opts, allow);\n+\t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\t\t\t     opts, allow);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -879,6 +955,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n+\tif (is_rebase_i(opts))\n+\t\treturn 0;\n+\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n \t/*\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304116","messageId":"9a66d53ebd86d35136597e534be03605bb1346bc.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:37Z","receivedAt":"2016-10-14T13:19:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The write_message() function safely writes an strbuf to a file.\nSometimes it is inconvenient to require an strbuf, though: the text to\nbe written may not be stored in a strbuf, or the strbuf should not be\nreleased after writing.\n\nLet's refactor \"safely writing string to a file\" into\nwrite_with_lock_file(), and make write_message() use it.\n\nThe new function will make it easy to create a new convenience function\nwrite_file_gently() that does not die(); as some of the upcoming callers\nof this new function will want to append a newline character, we already\nadd that flag as parameter to write_with_lock_file().\n\nWhile at it, roll back the locked files in case of failure, as pointed\nout by Hannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 25 ++++++++++++++++++++-----\n 1 file changed, 20 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 914a576..baccee9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,22 +234,37 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(struct strbuf *msgbuf, const char *filename)\n+static int write_with_lock_file(const char *filename,\n+\t\t\t\tconst void *buf, size_t len, int append_eol)\n {\n \tstatic struct lock_file msg_file;\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n-\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tstrbuf_release(msgbuf);\n-\tif (commit_lock_file(&msg_file) < 0)\n+\tif (write_in_full(msg_fd, buf, len) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t}\n+\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t}\n+\tif (commit_lock_file(&msg_file) < 0) {\n+\t\trollback_lock_file(&msg_file);\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t}\n \n \treturn 0;\n }\n \n+static int write_message(struct strbuf *msgbuf, const char *filename)\n+{\n+\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n+\tstrbuf_release(msgbuf);\n+\treturn res;\n+}\n+\n /*\n  * Reads a file that was presumably written by a shell script, i.e.\n  * with an end-of-line marker that needs to be stripped.\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304117","messageId":"09a7ffd519c860aac0c28526c644a425063e66a1.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 24/25] sequencer: start error messages consistently with lower case","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:19:22Z","receivedAt":"2016-10-14T13:20:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Quite a few error messages touched by this developer during the work to\nspeed up rebase -i started with an upper case letter, violating our\ncurrent conventions. Instead of sneaking in this fix (and forgetting\nquite a few error messages), let's just have one wholesale patch fixing\nall of the error messages in the sequencer.\n\nWhile at it, the funny \"error: Error wrapping up...\" was changed to a\nless funny, but more helpful, \"error: failed to finalize...\".\n\nPointed out by Junio Hamano.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c                   | 68 +++++++++++++++++++++----------------------\n t/t3501-revert-cherry-pick.sh |  2 +-\n 2 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 3e26631..57c5c0c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -241,18 +241,18 @@ static int write_with_lock_file(const char *filename,\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), filename);\n \tif (write_in_full(msg_fd, buf, len) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), filename);\n \t}\n \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t\treturn error_errno(_(\"could not write eol to '%s\"), filename);\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -306,11 +306,11 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(_(action_name(opts)));\n \n-\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\terror(_(\"your local changes would be overwritten by %s.\"),\n \t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n-\t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n+\t\tadvise(_(\"commit your changes or stash them to proceed.\"));\n \treturn -1;\n }\n \n@@ -419,7 +419,7 @@ static int is_index_unchanged(void)\n \tstruct commit *head_commit;\n \n \tif (!resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING, head_sha1, NULL))\n-\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\t\treturn error(_(\"could not resolve HEAD commit\\n\"));\n \n \thead_commit = lookup_commit(head_sha1);\n \n@@ -439,7 +439,7 @@ static int is_index_unchanged(void)\n \n \tif (!cache_tree_fully_valid(active_cache_tree))\n \t\tif (cache_tree_update(&the_index, 0))\n-\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\t\t\treturn error(_(\"unable to update cache tree\\n\"));\n \n \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n }\n@@ -509,7 +509,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\treturn error(\"you have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n \t\t\t\t\"  git commit --amend %s\\n\\n\"\n@@ -562,12 +562,12 @@ static int is_original_commit_empty(struct commit *commit)\n \tconst unsigned char *ptree_sha1;\n \n \tif (parse_commit(commit))\n-\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tif (commit->parents) {\n \t\tstruct commit *parent = commit->parents->item;\n \t\tif (parse_commit(parent))\n-\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\treturn error(_(\"could not parse parent commit %s\\n\"),\n \t\t\t\toid_to_hex(&parent->object.oid));\n \t\tptree_sha1 = parent->tree->object.oid.hash;\n \t} else {\n@@ -651,7 +651,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t * to work on.\n \t\t */\n \t\tif (write_cache_as_tree(head, 0, NULL))\n-\t\t\treturn error(_(\"Your index file is unmerged.\"));\n+\t\t\treturn error(_(\"your index file is unmerged.\"));\n \t} else {\n \t\tunborn = get_sha1(\"HEAD\", head);\n \t\tif (unborn)\n@@ -670,7 +670,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tstruct commit_list *p;\n \n \t\tif (!opts->mainline)\n-\t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n+\t\t\treturn error(_(\"commit %s is a merge but no -m option was given.\"),\n \t\t\t\toid_to_hex(&commit->object.oid));\n \n \t\tfor (cnt = 1, p = commit->parents;\n@@ -678,11 +678,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t     cnt++)\n \t\t\tp = p->next;\n \t\tif (cnt != opts->mainline || !p)\n-\t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n+\t\t\treturn error(_(\"commit %s does not have parent %d\"),\n \t\t\t\toid_to_hex(&commit->object.oid), opts->mainline);\n \t\tparent = p->item;\n \t} else if (0 < opts->mainline)\n-\t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n+\t\treturn error(_(\"mainline was specified but commit %s is not a merge.\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \telse\n \t\tparent = commit->parents->item;\n@@ -700,7 +700,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n-\t\treturn error(_(\"Cannot get commit message for %s\"),\n+\t\treturn error(_(\"cannot get commit message for %s\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \n \t/*\n@@ -936,13 +936,13 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\tres = error(_(\"invalid line %d: %.*s\"),\n \t\t\t\ti, (int)(eol - p), p);\n \t\t\titem->command = -1;\n \t\t}\n \t}\n \tif (!todo_list->nr)\n-\t\treturn error(_(\"No commits parsed.\"));\n+\t\treturn error(_(\"no commits parsed.\"));\n \treturn res;\n }\n \n@@ -955,16 +955,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n+\t\treturn error_errno(_(\"could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n+\t\treturn error(_(\"could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n+\t\treturn error(_(\"unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -975,9 +975,9 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tif (valid == todo_list->items[i].command)\n \t\t\t\tcontinue;\n \t\t\telse if (valid == TODO_PICK)\n-\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\t\treturn error(_(\"cannot cherry-pick during a revert.\"));\n \t\t\telse\n-\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t\t\t\treturn error(_(\"cannot revert during a cherry-pick.\"));\n \t}\n \n \treturn 0;\n@@ -1020,10 +1020,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n \t} else\n-\t\treturn error(_(\"Invalid key: %s\"), key);\n+\t\treturn error(_(\"invalid key: %s\"), key);\n \n \tif (!error_flag)\n-\t\treturn error(_(\"Invalid value for %s: %s\"), key, value);\n+\t\treturn error(_(\"invalid value for %s: %s\"), key, value);\n \n \treturn 0;\n }\n@@ -1055,7 +1055,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n+\t\treturn error(_(\"malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1098,7 +1098,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n+\t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1112,17 +1112,17 @@ static int save_head(const char *head)\n \tfd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);\n \tif (fd < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not lock HEAD\"));\n+\t\treturn error_errno(_(\"could not lock HEAD\"));\n \t}\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"),\n+\t\treturn error_errno(_(\"could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n+\t\treturn error(_(\"failed to finalize '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1201,14 +1201,14 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \n \tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), todo_path);\n \toffset = next < todo_list->nr ?\n \t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n \tif (write_in_full(fd, todo_list->buf.buf + offset,\n \t\t\ttodo_list->buf.len - offset) < 0)\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1383,7 +1383,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\t\tcreate_seq_dir() < 0)\n \t\treturn -1;\n \tif (get_sha1(\"HEAD\", sha1) && (opts->action == REPLAY_REVERT))\n-\t\treturn error(_(\"Can't revert as initial commit\"));\n+\t\treturn error(_(\"can't revert as initial commit\"));\n \tif (save_head(sha1_to_hex(sha1)))\n \t\treturn -1;\n \tif (save_opts(opts))\ndiff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh\nindex 51f3bbb..394f000 100755\n--- a/t/t3501-revert-cherry-pick.sh\n+++ b/t/t3501-revert-cherry-pick.sh\n@@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '\n \techo content >extra_file &&\n \tgit add extra_file &&\n \ttest_must_fail git revert HEAD 2>errors &&\n-\ttest_i18ngrep \"Your local changes would be overwritten by \" errors\n+\ttest_i18ngrep \"your local changes would be overwritten by \" errors\n \n '\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304118","messageId":"a6900b2ae43c92354d52a335facc4f931878f16d.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 22/25] sequencer: mark action_name() for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:19:15Z","receivedAt":"2016-10-14T13:20:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The definition of this function goes back all the way to 043a449\n(sequencer: factor code out of revert builtin, 2012-01-11), long before a\nserious effort was made to translate all the error messages.\n\nIt is slightly out of the context of the current patch series (whose\npurpose it is to re-implement the performance critical parts of the\ninteractive rebase in C) to make the error messages in the sequencer\ntranslatable, but what the heck. We'll just do it while we're looking at\nthis part of the code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 36c24b6..af88753 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -168,7 +168,7 @@ int sequencer_remove_state(struct replay_opts *opts)\n \n static const char *action_name(const struct replay_opts *opts)\n {\n-\treturn opts->action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\";\n+\treturn opts->action == REPLAY_REVERT ? N_(\"revert\") : N_(\"cherry-pick\");\n }\n \n struct commit_message {\n@@ -304,10 +304,10 @@ static struct tree *empty_tree(void)\n static int error_dirty_index(struct replay_opts *opts)\n {\n \tif (read_cache_unmerged())\n-\t\treturn error_resolve_conflict(action_name(opts));\n+\t\treturn error_resolve_conflict(_(action_name(opts)));\n \n \terror(_(\"Your local changes would be overwritten by %s.\"),\n-\t\taction_name(opts));\n+\t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n@@ -325,7 +325,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,\n \tif (checkout_fast_forward(from, to, 1))\n \t\treturn -1; /* the callee should have complained already */\n \n-\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), action_name(opts));\n+\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), _(action_name(opts)));\n \n \ttransaction = ref_transaction_begin(&err);\n \tif (!transaction ||\n@@ -401,7 +401,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \t    write_locked_index(&the_index, &index_lock, COMMIT_LOCK))\n \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n \t\treturn error(_(\"%s: Unable to write new index file\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \trollback_lock_file(&index_lock);\n \n \tif (opts->signoff)\n@@ -836,14 +836,14 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \tif (read_index_preload(&the_index, NULL) < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn error(_(\"git %s: failed to read the index\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \t}\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n \tif (the_index.cache_changed && index_fd >= 0) {\n \t\tif (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {\n \t\t\trollback_lock_file(&index_lock);\n \t\t\treturn error(_(\"git %s: failed to refresh the index\"),\n-\t\t\t\taction_name(opts));\n+\t\t\t\t_(action_name(opts)));\n \t\t}\n \t}\n \trollback_lock_file(&index_lock);\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304119","messageId":"a9e1ee4e2315a106337d598d17089304f4d93643.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 25/25] sequencer: mark all error messages for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:19:26Z","receivedAt":"2016-10-14T13:20:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There was actually only one error message that was not yet marked for\ntranslation.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 26 ++++++++++++++++----------\n 1 file changed, 16 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 57c5c0c..1cf70f7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -483,6 +483,20 @@ static char **read_author_script(void)\n \treturn env;\n }\n \n+static const char staged_changes_advice[] =\n+N_(\"you have staged changes in your working tree\\n\"\n+\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n+\"\\n\"\n+\"  git commit --amend %s\\n\"\n+\"\\n\"\n+\"If they are meant to go into a new commit, run:\\n\"\n+\"\\n\"\n+\"  git commit %s\\n\"\n+\"\\n\"\n+\"In both cases, once you're done, continue with:\\n\"\n+\"\\n\"\n+\"  git rebase --continue\\n\");\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -509,16 +523,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"you have staged changes in your working \"\n-\t\t\t\t\"tree. If these changes are meant to be\\n\"\n-\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend %s\\n\\n\"\n-\t\t\t\t\"If they are meant to go into a new commit, \"\n-\t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit %s\\n\\n\"\n-\t\t\t\t\"In both cases, once you're done, continue \"\n-\t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t\treturn error(_(staged_changes_advice),\n+\t\t\t\t     gpg_opt, gpg_opt);\n \t\t}\n \t}\n \n-- \n2.10.1.513.g00ef6dd\n"},{"id":"304120","messageId":"930ea31d6f10973807276c7a9f35f0d692d1ada6.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 23/25] sequencer: quote filenames in error messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:19:19Z","receivedAt":"2016-10-14T13:20:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This makes the code consistent by fixing quite a couple of error messages.\n\nSuggested by Jakub Narębski.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex af88753..3e26631 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -252,7 +252,7 @@ static int write_with_lock_file(const char *filename,\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -955,16 +955,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n+\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read %s.\"), todo_file);\n+\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -1055,7 +1055,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: %s\"),\n+\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1098,7 +1098,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory %s\"),\n+\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1117,12 +1117,12 @@ static int save_head(const char *head)\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n+\t\treturn error_errno(_(\"Could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_head_file());\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1167,9 +1167,9 @@ int sequencer_rollback(struct replay_opts *opts)\n \t\treturn rollback_single_pick();\n \t}\n \tif (!f)\n-\t\treturn error_errno(_(\"cannot open %s\"), git_path_head_file());\n+\t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n \tif (strbuf_getline_lf(&buf, f)) {\n-\t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n+\t\terror(_(\"cannot read '%s': %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\n \t\tgoto fail;\n@@ -1208,7 +1208,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t\ttodo_list->buf.len - offset) < 0)\n \t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n \treturn 0;\n }\n \n-- \n2.10.1.513.g00ef6dd\n\n"},{"id":"304121","messageId":"618bd6854c89534381be0956fca4e2468d66c330.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 21/25] sequencer: remove overzealous assumption in rebase -i mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:18:55Z","receivedAt":"2016-10-14T13:20:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer was introduced to make the cherry-pick and revert\nfunctionality available as library function, with the original idea\nbeing to extend the sequencer to also implement the rebase -i\nfunctionality.\n\nThe test to ensure that all of the commands in the script are identical\nto the overall operation does not mesh well with that.\n\nTherefore let's disable the test in rebase -i mode.\n\nWhile at it, error out early if the \"instruction sheet\" (i.e. the todo\nscript) could not be parsed.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex baccee9..36c24b6 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -963,7 +963,10 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n-\tif (!res) {\n+\tif (res)\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\n+\tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n \t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n \t\tint i;\n@@ -977,8 +980,6 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n \t}\n \n-\tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304122","messageId":"a5f5d784fcacc16555237b9750380d612387d0cb.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 08/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:50Z","receivedAt":"2016-10-14T13:20:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When we came up with the \"sequencer\" idea, we really wanted to have\nkind of a plumbing equivalent of the interactive rebase. Hence the\nchoice of words: the \"todo\" script, a \"pick\", etc.\n\nHowever, when it came time to implement the entire shebang, somehow this\nidea got lost and the sequencer was used as working horse for\ncherry-pick and revert instead. So as not to interfere with the\ninteractive rebase, it even uses a separate directory to store its\nstate.\n\nFurthermore, it also is stupidly strict about the \"todo\" script it\naccepts: while it parses commands in a way that was *designed* to be\nsimilar to the interactive rebase, it then goes on to *error out* if the\ncommands disagree with the overall action (cherry-pick or revert).\n\nFinally, the sequencer code chose to deviate from the interactive rebase\ncode insofar that when it comes to writing the file with the remaining\ncommands, it *reformats* the \"todo\" script instead of just writing the\npart of the parsed script that were not yet processed. This is not only\nunnecessary churn, but might well lose information that is valuable to\nthe user (i.e. comments after the commands).\n\nLet's just bite the bullet and rewrite the entire parser; the code now\nbecomes not only more elegant: it allows us to go on and teach the\nsequencer how to parse *true* \"todo\" scripts as used by the interactive\nrebase itself. In a way, the sequencer is about to grow up to do its\nolder brother's job. Better.\n\nIn particular, we choose to maintain the list of commands in an array\ninstead of a linked list: this is flexible enough to allow us later on to\neven implement rebase -i's reordering of fixup!/squash! commits very\neasily (and with a very nice speed bonus, at least on Windows).\n\nWhile at it, do not stop at the first problem, but list *all* of the\nproblems. This will help the user when the sequencer will do `rebase\n-i`'s work by allowing to address all issues in one go rather than going\nback and forth until the todo list is valid.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 284 ++++++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 163 insertions(+), 121 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 499f5ee..f797e8a 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -470,7 +470,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \t\treturn 1;\n }\n \n-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n+enum todo_command {\n+\tTODO_PICK = 0,\n+\tTODO_REVERT\n+};\n+\n+static const char *todo_command_strings[] = {\n+\t\"pick\",\n+\t\"revert\"\n+};\n+\n+static const char *command_to_string(const enum todo_command command)\n+{\n+\tif (command < ARRAY_SIZE(todo_command_strings))\n+\t\treturn todo_command_strings[command];\n+\tdie(\"Unknown command: %d\", command);\n+}\n+\n+\n+static int do_pick_commit(enum todo_command command, struct commit *commit,\n+\t\tstruct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -529,10 +548,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n \n \tif (parent && parse_commit(parent) < 0)\n-\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n-\t\t   \"cherry-pick\", the second %s a SHA1 */\n+\t\t/* TRANSLATORS: The first %s will be a \"todo\" command like\n+\t\t   \"revert\" or \"pick\", the second %s a SHA1. */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n-\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n+\t\t\tcommand_to_string(command),\n+\t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n@@ -545,7 +565,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * reverse of it if we are revert.\n \t */\n \n-\tif (opts->action == REPLAY_REVERT) {\n+\tif (command == TODO_REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -586,7 +606,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t}\n \t}\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n@@ -613,17 +633,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * However, if the merge did not even start, then we don't want to\n \t * write it at all.\n \t */\n-\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n+\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n-\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n+\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n \n \tif (res) {\n-\t\terror(opts->action == REPLAY_REVERT\n+\t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n \t\t      short_commit_name(commit), msg.subject);\n@@ -684,116 +704,122 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n-\t\tstruct replay_opts *opts)\n+struct todo_item {\n+\tenum todo_command command;\n+\tstruct commit *commit;\n+\tsize_t offset_in_buf;\n+};\n+\n+struct todo_list {\n+\tstruct strbuf buf;\n+\tstruct todo_item *items;\n+\tint nr, alloc, current;\n+};\n+\n+#define TODO_LIST_INIT { STRBUF_INIT }\n+\n+static void todo_list_release(struct todo_list *todo_list)\n {\n-\tstruct commit_list *cur = NULL;\n-\tconst char *sha1_abbrev = NULL;\n-\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n-\tconst char *subject;\n-\tint subject_len;\n+\tstrbuf_release(&todo_list->buf);\n+\tfree(todo_list->items);\n+\ttodo_list->items = NULL;\n+\ttodo_list->nr = todo_list->alloc = 0;\n+}\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n-\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n-\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n-\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n-\t\t\tsubject_len, subject);\n-\t\tunuse_commit_buffer(cur->item, commit_buffer);\n-\t}\n-\treturn 0;\n+static struct todo_item *append_new_todo(struct todo_list *todo_list)\n+{\n+\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n+\treturn todo_list->items + todo_list->nr++;\n }\n \n-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n {\n \tunsigned char commit_sha1[20];\n-\tenum replay_action action;\n \tchar *end_of_object_name;\n-\tint saved, status, padding;\n-\n-\tif (starts_with(bol, \"pick\")) {\n-\t\taction = REPLAY_PICK;\n-\t\tbol += strlen(\"pick\");\n-\t} else if (starts_with(bol, \"revert\")) {\n-\t\taction = REPLAY_REVERT;\n-\t\tbol += strlen(\"revert\");\n-\t} else\n-\t\treturn NULL;\n+\tint i, saved, status, padding;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n+\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n+\t\t\titem->command = i;\n+\t\t\tbreak;\n+\t\t}\n+\tif (i >= ARRAY_SIZE(todo_command_strings))\n+\t\treturn -1;\n \n \t/* Eat up extra spaces/ tabs before object name */\n \tpadding = strspn(bol, \" \\t\");\n \tif (!padding)\n-\t\treturn NULL;\n+\t\treturn -1;\n \tbol += padding;\n \n-\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n+\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n \tsaved = *end_of_object_name;\n \t*end_of_object_name = '\\0';\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n-\t/*\n-\t * Verify that the action matches up with the one in\n-\t * opts; we don't support arbitrary instructions\n-\t */\n-\tif (action != opts->action) {\n-\t\tif (action == REPLAY_REVERT)\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot revert during another revert.\")\n-\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n-\t\telse\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n-\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n-\t\treturn NULL;\n-\t}\n-\n \tif (status < 0)\n-\t\treturn NULL;\n+\t\treturn -1;\n \n-\treturn lookup_commit_reference(commit_sha1);\n+\titem->commit = lookup_commit_reference(commit_sha1);\n+\treturn !item->commit;\n }\n \n-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n-\t\t\tstruct replay_opts *opts)\n+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n {\n-\tstruct commit_list **next = todo_list;\n-\tstruct commit *commit;\n-\tchar *p = buf;\n-\tint i;\n+\tstruct todo_item *item;\n+\tchar *p = buf, *next_p;\n+\tint i, res = 0;\n \n-\tfor (i = 1; *p; i++) {\n+\tfor (i = 1; *p; i++, p = next_p) {\n \t\tchar *eol = strchrnul(p, '\\n');\n-\t\tcommit = parse_insn_line(p, eol, opts);\n-\t\tif (!commit)\n-\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n-\t\tnext = commit_list_append(commit, next);\n-\t\tp = *eol ? eol + 1 : eol;\n+\n+\t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n+\n+\t\titem = append_new_todo(todo_list);\n+\t\titem->offset_in_buf = p - todo_list->buf.buf;\n+\t\tif (parse_insn_line(item, p, eol)) {\n+\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\t\ti, (int)(eol - p), p);\n+\t\t\titem->command = -1;\n+\t\t}\n \t}\n-\tif (!*todo_list)\n+\tif (!todo_list->nr)\n \t\treturn error(_(\"No commits parsed.\"));\n-\treturn 0;\n+\treturn res;\n }\n \n-static int read_populate_todo(struct commit_list **todo_list,\n+static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n \tconst char *todo_file = get_todo_path(opts);\n-\tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n+\tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n-\tif (strbuf_read(&buf, fd, 0) < 0) {\n+\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\tstrbuf_release(&buf);\n \t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n-\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n-\tstrbuf_release(&buf);\n+\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n+\tif (!res) {\n+\t\tenum todo_command valid =\n+\t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < todo_list->nr; i++)\n+\t\t\tif (valid == todo_list->items[i].command)\n+\t\t\t\tcontinue;\n+\t\t\telse if (valid == TODO_PICK)\n+\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\telse\n+\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t}\n+\n \tif (res)\n \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n@@ -860,18 +886,31 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int walk_revs_populate_todo(struct commit_list **todo_list,\n+static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n+\tenum todo_command command = opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT;\n+\tconst char *command_string = todo_command_strings[command];\n \tstruct commit *commit;\n-\tstruct commit_list **next;\n \n \tif (prepare_revs(opts))\n \t\treturn -1;\n \n-\tnext = todo_list;\n-\twhile ((commit = get_revision(opts->revs)))\n-\t\tnext = commit_list_append(commit, next);\n+\twhile ((commit = get_revision(opts->revs))) {\n+\t\tstruct todo_item *item = append_new_todo(todo_list);\n+\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n+\t\tconst char *subject;\n+\t\tint subject_len;\n+\n+\t\titem->command = command;\n+\t\titem->commit = commit;\n+\t\titem->offset_in_buf = todo_list->buf.len;\n+\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n+\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n+\t\t\tshort_commit_name(commit), subject_len, subject);\n+\t\tunuse_commit_buffer(commit, commit_buffer);\n+\t}\n \treturn 0;\n }\n \n@@ -979,30 +1018,22 @@ static int sequencer_rollback(struct replay_opts *opts)\n \treturn -1;\n }\n \n-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstatic struct lock_file todo_lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint fd;\n+\tconst char *todo_path = get_todo_path(opts);\n+\tint next = todo_list->current, offset, fd;\n \n-\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n+\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"),\n-\t\t\t\t   git_path_todo_file());\n-\tif (format_todo(&buf, todo_list, opts) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n-\t}\n-\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n-\t\t\t\t   git_path_todo_file());\n-\t}\n-\tif (commit_lock_file(&todo_lock) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n-\t}\n-\tstrbuf_release(&buf);\n+\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\toffset = next < todo_list->nr ?\n+\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n+\tif (write_in_full(fd, todo_list->buf.buf + offset,\n+\t\t\ttodo_list->buf.len - offset) < 0)\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\tif (commit_lock_file(&todo_lock) < 0)\n+\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1041,9 +1072,8 @@ static int save_opts(struct replay_opts *opts)\n \treturn res;\n }\n \n-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *cur;\n \tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n@@ -1053,10 +1083,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tif (save_todo(cur, opts))\n+\twhile (todo_list->current < todo_list->nr) {\n+\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n+\t\tif (save_todo(todo_list, opts))\n \t\t\treturn -1;\n-\t\tres = do_pick_commit(cur->item, opts);\n+\t\tres = do_pick_commit(item->command, item->commit, opts);\n+\t\ttodo_list->current++;\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -1081,38 +1113,46 @@ static int continue_single_pick(void)\n \n static int sequencer_continue(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n \n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(opts) ||\n-\t\t\tread_populate_todo(&todo_list, opts))\n+\tif (read_populate_opts(opts))\n \t\treturn -1;\n+\tif ((res = read_populate_todo(&todo_list, opts)))\n+\t\tgoto release_todo_list;\n \n \t/* Verify that the conflict has been resolved */\n \tif (file_exists(git_path_cherry_pick_head()) ||\n \t    file_exists(git_path_revert_head())) {\n-\t\tint ret = continue_single_pick();\n-\t\tif (ret)\n-\t\t\treturn ret;\n+\t\tres = continue_single_pick();\n+\t\tif (res)\n+\t\t\tgoto release_todo_list;\n \t}\n-\tif (index_differs_from(\"HEAD\", 0))\n-\t\treturn error_dirty_index(opts);\n-\ttodo_list = todo_list->next;\n-\treturn pick_commits(todo_list, opts);\n+\tif (index_differs_from(\"HEAD\", 0)) {\n+\t\tres = error_dirty_index(opts);\n+\t\tgoto release_todo_list;\n+\t}\n+\ttodo_list.current++;\n+\tres = pick_commits(&todo_list, opts);\n+release_todo_list:\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n static int single_pick(struct commit *cmit, struct replay_opts *opts)\n {\n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(cmit, opts);\n+\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n }\n \n int sequencer_pick_revisions(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n \tunsigned char sha1[20];\n-\tint i;\n+\tint i, res;\n \n \tif (opts->subcommand == REPLAY_NONE)\n \t\tassert(opts->revs);\n@@ -1187,7 +1227,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\treturn -1;\n \tif (save_opts(opts))\n \t\treturn -1;\n-\treturn pick_commits(todo_list, opts);\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304123","messageId":"782293991f2ccbc2d0553d2e2e89d70c394901ff.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 09/25] sequencer: strip CR from the todo script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:53Z","receivedAt":"2016-10-14T13:20:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"It is not unheard of that editors on Windows write CR/LF even if the\nfile originally had only LF. This is particularly awkward for exec lines\nof a rebase -i todo sheet. Take for example the insn \"exec echo\": The\nshell script parser splits at the LF and leaves the CR attached to\n\"echo\", which leads to the unknown command \"echo\\r\".\n\nWork around that by stripping CR when reading the todo commands, as we\nalready do for LF.\n\nThis happens to fix t9903.14 and .15 in MSYS1 environments (with the\nrebase--helper patches based on this patch series): the todo script\nconstructed in such a setup contains CR/LF thanks to MSYS1 runtime's\ncleverness.\n\nBased on a report and a patch by Johannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f797e8a..eac531b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -776,6 +776,9 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \n \t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n \n+\t\tif (p != eol && eol[-1] == '\\r')\n+\t\t\teol--; /* strip Carriage Return */\n+\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304124","messageId":"5d5694fc202ad7e4b4255c3a460c8bb3d9cb3d9f.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 03/25] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:16Z","receivedAt":"2016-10-14T13:20:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We really do not need the *pointer to a* pointer to the options in\nthe read_populate_opts() function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb16cbd..c2fbf6f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -813,7 +813,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static int read_populate_opts(struct replay_opts **opts)\n+static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n@@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n \t * about this case, though, because we wrote that file ourselves, so we\n \t * are pretty certain that it is syntactically correct.\n \t */\n-\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n+\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n \t\treturn error(_(\"Malformed options sheet: %s\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n@@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n \n \tif (!file_exists(git_path_todo_file()))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(&opts) ||\n+\tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n \t\treturn -1;\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304125","messageId":"b771bfbc88734b74acda0c377446e984ca81fd9c.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:24Z","receivedAt":"2016-10-14T13:20:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\nlike a one-shot command when it reads its configuration: memory is\nallocated and released only when the command exits.\n\nThis is kind of okay for git-cherry-pick, which *is* a one-shot\ncommand. All the work to make the sequencer its work horse was\ndone to allow using the functionality as a library function, though,\nincluding proper clean-up after use.\n\nTo remedy that, we now take custody of the option values in question,\nrequiring those values to be malloc()ed or strdup()ed (an alternative\napproach, to add a list of pointers to malloc()ed data and to ask the\nsequencer to release all of them in the end, was proposed earlier but\nrejected during review).\n\nSadly, the current approach makes the code uglier, as we now have to\ntake care to strdup() the values passed via the command-line.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c |  4 ++++\n sequencer.c      | 26 ++++++++++++++++++++++----\n sequencer.h      |  6 +++---\n 3 files changed, 29 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 7365559..ba5a88c 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -174,6 +174,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n \tif (argc > 1)\n \t\tusage_with_options(usage_str, options);\n+\n+\t/* These option values will be free()d */\n+\topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n+\topts->strategy = xstrdup_or_null(opts->strategy);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d272fb..04c55f2 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -117,6 +117,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n static void remove_sequencer_state(const struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n+\tint i;\n+\n+\tfree(opts->gpg_sign);\n+\tfree(opts->strategy);\n+\tfor (i = 0; i < opts->xopts_nr; i++)\n+\t\tfree(opts->xopts[i]);\n+\tfree(opts->xopts);\n \n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n@@ -280,7 +287,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \tstruct merge_options o;\n \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n \tint clean;\n-\tconst char **xopt;\n+\tchar **xopt;\n \tstatic struct lock_file index_lock;\n \n \thold_locked_index(&index_lock, 1);\n@@ -583,7 +590,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-\t\tres |= try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,\n+\t\tres |= try_merge_command(opts->strategy,\n+\t\t\t\t\t opts->xopts_nr, (const char **)opts->xopts,\n \t\t\t\t\tcommon, sha1_to_hex(head), remotes);\n \t\tfree_commit_list(common);\n \t\tfree_commit_list(remotes);\n@@ -783,6 +791,16 @@ static int read_populate_todo(struct commit_list **todo_list,\n \treturn 0;\n }\n \n+static int git_config_string_dup(char **dest,\n+\t\t\t\t const char *var, const char *value)\n+{\n+\tif (!value)\n+\t\treturn config_error_nonbool(var);\n+\tfree(*dest);\n+\t*dest = xstrdup(value);\n+\treturn 0;\n+}\n+\n static int populate_opts_cb(const char *key, const char *value, void *data)\n {\n \tstruct replay_opts *opts = data;\n@@ -803,9 +821,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \telse if (!strcmp(key, \"options.mainline\"))\n \t\topts->mainline = git_config_int(key, value);\n \telse if (!strcmp(key, \"options.strategy\"))\n-\t\tgit_config_string(&opts->strategy, key, value);\n+\t\tgit_config_string_dup(&opts->strategy, key, value);\n \telse if (!strcmp(key, \"options.gpg-sign\"))\n-\t\tgit_config_string(&opts->gpg_sign, key, value);\n+\t\tgit_config_string_dup(&opts->gpg_sign, key, value);\n \telse if (!strcmp(key, \"options.strategy-option\")) {\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\ndiff --git a/sequencer.h b/sequencer.h\nindex dd4d33a..8453669 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -34,11 +34,11 @@ struct replay_opts {\n \n \tint mainline;\n \n-\tconst char *gpg_sign;\n+\tchar *gpg_sign;\n \n \t/* Merge strategy */\n-\tconst char *strategy;\n-\tconst char **xopts;\n+\tchar *strategy;\n+\tchar **xopts;\n \tsize_t xopts_nr, xopts_alloc;\n \n \t/* Only used by REPLAY_NONE */\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304126","messageId":"0ed2f56dac32bfc5fe1ef8eebdeb1ec4f13b2f47.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 04/25] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:20Z","receivedAt":"2016-10-14T13:20:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In a couple of commits, we will teach the sequencer to handle the\nnitty gritty of the interactive rebase, which keeps its state in a\ndifferent directory.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c2fbf6f..8d272fb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,11 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+static const char *get_dir(const struct replay_opts *opts)\n+{\n+\treturn git_path_seq_dir();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -109,13 +114,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(void)\n+static void remove_sequencer_state(const struct replay_opts *opts)\n {\n-\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n-\tremove_dir_recursively(&seq_dir, 0);\n-\tstrbuf_release(&seq_dir);\n+\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -940,7 +945,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n \treturn 0;\n fail:\n@@ -1034,7 +1039,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \treturn 0;\n }\n \n@@ -1095,7 +1100,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t * one that is being continued\n \t */\n \tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(opts);\n \t\treturn 0;\n \t}\n \tif (opts->subcommand == REPLAY_ROLLBACK)\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304127","messageId":"da12dda5acf5ac3c1c1d08c1a941de0f193909ea.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 07/25] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:46Z","receivedAt":"2016-10-14T13:20:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Not only does this DRY up the code (providing a better documentation what\nthe code is about, as well as allowing to change the behavior in a single\nplace), it also makes it substantially shorter to use the same\nfunctionality in functions to be introduced when we teach the sequencer to\nprocess interactive-rebase's git-rebase-todo file.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex fb0b94b..499f5ee 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -147,13 +147,18 @@ struct commit_message {\n \tconst char *message;\n };\n \n+static const char *short_commit_name(struct commit *commit)\n+{\n+\treturn find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+}\n+\n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n \tint subject_len;\n \n \tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n-\tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+\tabbrev = short_commit_name(commit);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n@@ -621,8 +626,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\terror(opts->action == REPLAY_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n-\t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n-\t\t      msg.subject);\n+\t\t      short_commit_name(commit), msg.subject);\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t\tgoto leave;\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304128","messageId":"e2d2ec17acd459f2f52476604ea564ed87e44228.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 02/25] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:12Z","receivedAt":"2016-10-14T13:20:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/commit.c |  2 +-\n sequencer.c      | 11 ++++++-----\n sequencer.h      |  5 +----\n 3 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1cba3b7..9fddb19 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)\n \t\twhence = FROM_MERGE;\n \telse if (file_exists(git_path_cherry_pick_head())) {\n \t\twhence = FROM_CHERRY_PICK;\n-\t\tif (file_exists(git_path(SEQ_DIR)))\n+\t\tif (file_exists(git_path_seq_dir()))\n \t\t\tsequencer_in_use = 1;\n \t}\n \telse\ndiff --git a/sequencer.c b/sequencer.c\nindex eec8a60..cb16cbd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -21,10 +21,11 @@\n const char sign_off_header[] = \"Signed-off-by: \";\n static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n \n-static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n-static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n-static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n-static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n+GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n+\n+static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n+static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n+static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n static int is_rfc2822_line(const char *buf, int len)\n {\n@@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n+\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n \tremove_dir_recursively(&seq_dir, 0);\n \tstrbuf_release(&seq_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex db425ad..dd4d33a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -1,10 +1,7 @@\n #ifndef SEQUENCER_H\n #define SEQUENCER_H\n \n-#define SEQ_DIR\t\t\"sequencer\"\n-#define SEQ_HEAD_FILE\t\"sequencer/head\"\n-#define SEQ_TODO_FILE\t\"sequencer/todo\"\n-#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n+const char *git_path_seq_dir(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304132","messageId":"21954fadd458bc4dab27e9eb6c31c29bcf21191e.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 10/25] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:57Z","receivedAt":"2016-10-14T13:21:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex eac531b..9bca056 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -229,11 +229,8 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(action_name(opts));\n \n-\t/* Different translation strings for cherry-pick and revert */\n-\tif (opts->action == REPLAY_PICK)\n-\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n-\telse\n-\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n+\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\t\taction_name(opts));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304133","messageId":"be30c373782e0022075c41541c15bf4ade026c3f.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 06/25] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:17:27Z","receivedAt":"2016-10-14T13:21:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Over the next commits, we will work on improving the sequencer to the\npoint where it can process the todo script of an interactive rebase. To\nthat end, we will need to teach the sequencer to read interactive\nrebase's todo file. In preparation, we consolidate all places where\nthat todo file is needed to call a function that we will later extend.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 04c55f2..fb0b94b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n \treturn git_path_seq_dir();\n }\n \n+static const char *get_todo_path(const struct replay_opts *opts)\n+{\n+\treturn git_path_todo_file();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -769,25 +774,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n static int read_populate_todo(struct commit_list **todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n+\tconst char *todo_file = get_todo_path(opts);\n \tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n-\tfd = open(git_path_todo_file(), O_RDONLY);\n+\tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"),\n-\t\t\t\t   git_path_todo_file());\n+\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n \tif (strbuf_read(&buf, fd, 0) < 0) {\n \t\tclose(fd);\n \t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n+\t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n \tstrbuf_release(&buf);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n-\t\t\tgit_path_todo_file());\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n@@ -1075,7 +1079,7 @@ static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n \n-\tif (!file_exists(git_path_todo_file()))\n+\tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304136","messageId":"a0441930fb5d0a0483a81dc6895056ca05336dbf.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 01/25] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:15:56Z","receivedAt":"2016-10-14T13:25:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This change is not completely faithful: instead of initializing all fields\nto 0, we choose to initialize command and subcommand to -1 (instead of\ndefaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\nit makes no difference at all, but future-proofs the code to require\nexplicit assignments for both fields.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 6 ++----\n sequencer.h      | 1 +\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4e69380..7365559 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -178,10 +178,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n@@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n \tparse_args(argc, argv, &opts);\ndiff --git a/sequencer.h b/sequencer.h\nindex 5ed5cb1..db425ad 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -47,6 +47,7 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n+#define REPLAY_OPTS_INIT { -1, -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.1.513.g00ef6dd\n\n\n"},{"id":"304137","messageId":"cover.1476450940.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476120229.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 00/25] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-14T13:15:51Z","receivedAt":"2016-10-14T13:25:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series marks the '4' in the countdown to speed up rebase -i\nby implementing large parts in C (read: there will be three more patch\nseries after that before the full benefit hits git.git: sequencer-i,\nrebase--helper and rebase-i-extra). It is based on the `libify-sequencer`\npatch series I submitted earlier.\n\nThe patches in this series merely prepare the sequencer code for the\nnext patch series that actually teaches the sequencer to run rebase -i's\ncommands.\n\nThe reason to split these two patch series is simple: to keep them at a\nsensible size.\n\nThe two patch series after that are much smaller: a two-patch \"series\"\nthat switches rebase -i to use the sequencer (except with --root or\n--preserve-merges), and a couple of patches to move several pretty\nexpensive script processing steps to C (think: autosquash).\n\nThe end game of this patch series is a git-rebase--helper that makes\nrebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\nthat even MacOSX and Linux benefit (4x and 3x, respectively).\n\nI have been working on this since early February, whenever time allowed,\nand it is time to put it into the users' hands. To that end, I already\nintegrated the whole shebang into Git for Windows 2.10.0 and 2.10.1\nwhere it has been running without complaints (and some quite positive\nfeedback).\n\nChanges vs v3:\n\n- fixed TRANSLATORS: comment to help the tool extracting those comments.\n\n- reordered the patch introducing the short_commit_name() function so it\n  can be used in the patch revamping the todo parsing right away, as\n  opposed to fixing up the find_unique_abbrev() ugliness in a later\n  patch.\n\n- backed out the write_message_gently() function of this patch series:\n  it is not used by the end of this patch series and would therefore let\n  the build fail with DEVELOPER=1. That function is now introduced as\n  part of the patch in the sequencer-i series that adds support for the\n  'edit' command.\n\n- edited \"skip CR/skip LF\" to say \"strip\" instead.\n\n- used xstrdup_or_null() where appropriate.\n\n- abstracted out git_config_string_dup() instead of adding\n  near-duplicate code.\n\n- marked the append_new_todo() function as file-local, pointed out by\n  Ramsay.\n\n- made the \"you have staged changes\" advice prettier by moving it out of\n  the run_git_commit() function, based on a suggestion by Hannes Sixt.\n\n\nJohannes Schindelin (25):\n  sequencer: use static initializers for replay_opts\n  sequencer: use memoized sequencer directory path\n  sequencer: avoid unnecessary indirection\n  sequencer: future-proof remove_sequencer_state()\n  sequencer: eventually release memory allocated for the option values\n  sequencer: future-proof read_populate_todo()\n  sequencer: refactor the code to obtain a short commit name\n  sequencer: completely revamp the \"todo\" script parsing\n  sequencer: strip CR from the todo script\n  sequencer: avoid completely different messages for different actions\n  sequencer: get rid of the subcommand field\n  sequencer: remember the onelines when parsing the todo file\n  sequencer: prepare for rebase -i's commit functionality\n  sequencer: introduce a helper to read files written by scripts\n  sequencer: allow editing the commit message on a case-by-case basis\n  sequencer: support amending commits\n  sequencer: support cleaning up commit messages\n  sequencer: do not try to commit when there were merge conflicts\n  sequencer: left-trim lines read from the script\n  sequencer: refactor write_message()\n  sequencer: remove overzealous assumption in rebase -i mode\n  sequencer: mark action_name() for translation\n  sequencer: quote filenames in error messages\n  sequencer: start error messages consistently with lower case\n  sequencer: mark all error messages for translation\n\n builtin/commit.c              |   2 +-\n builtin/revert.c              |  46 ++-\n sequencer.c                   | 679 ++++++++++++++++++++++++++++--------------\n sequencer.h                   |  23 +-\n t/t3501-revert-cherry-pick.sh |   2 +-\n 5 files changed, 492 insertions(+), 260 deletions(-)\n\n\nbase-commit: 3cdd5d19178a54d2e51b5098d43b57571241d0ab\nPublished-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v4\nFetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v4\n\nInterdiff vs v3:\n\n diff --git a/builtin/revert.c b/builtin/revert.c\n index 0a7b5f4..4ca5b51 100644\n --- a/builtin/revert.c\n +++ b/builtin/revert.c\n @@ -166,10 +166,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n  \t\tusage_with_options(usage_str, options);\n  \n  \t/* These option values will be free()d */\n -\tif (opts->gpg_sign)\n -\t\topts->gpg_sign = xstrdup(opts->gpg_sign);\n -\tif (opts->strategy)\n -\t\topts->strategy = xstrdup(opts->strategy);\n +\topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n +\topts->strategy = xstrdup_or_null(opts->strategy);\n  \n  \tif (cmd == 'q')\n  \t\treturn sequencer_remove_state(opts);\n diff --git a/sequencer.c b/sequencer.c\n index 86d86ce..1cf70f7 100644\n --- a/sequencer.c\n +++ b/sequencer.c\n @@ -265,12 +265,6 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n  \treturn res;\n  }\n  \n -static int write_file_gently(const char *filename,\n -\t\t\t     const char *text, int append_eol)\n -{\n -\treturn write_with_lock_file(filename, text, strlen(text), append_eol);\n -}\n -\n  /*\n   * Reads a file that was presumably written by a shell script, i.e.\n   * with an end-of-line marker that needs to be stripped.\n @@ -489,6 +483,20 @@ static char **read_author_script(void)\n  \treturn env;\n  }\n  \n +static const char staged_changes_advice[] =\n +N_(\"you have staged changes in your working tree\\n\"\n +\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n +\"\\n\"\n +\"  git commit --amend %s\\n\"\n +\"\\n\"\n +\"If they are meant to go into a new commit, run:\\n\"\n +\"\\n\"\n +\"  git commit %s\\n\"\n +\"\\n\"\n +\"In both cases, once you're done, continue with:\\n\"\n +\"\\n\"\n +\"  git rebase --continue\\n\");\n +\n  /*\n   * If we are cherry-pick, and if the merge did not result in\n   * hand-editing, we will hit this commit and inherit the original\n @@ -515,18 +523,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n  \t\tif (!env) {\n  \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n  \n -\t\t\treturn error(_(\"you have staged changes in your \"\n -\t\t\t\t       \"working tree. If these changes are \"\n -\t\t\t\t       \"meant to be\\n\"\n -\t\t\t\t       \"squashed into the previous commit, \"\n -\t\t\t\t       \"run:\\n\\n\"\n -\t\t\t\t       \"  git commit --amend %s\\n\\n\"\n -\t\t\t\t       \"If they are meant to go into a new \"\n -\t\t\t\t       \"commit, run:\\n\\n\"\n -\t\t\t\t       \"  git commit %s\\n\\n\"\n -\t\t\t\t       \"In both cases, once you're done, \"\n -\t\t\t\t       \"continue with:\\n\\n\"\n -\t\t\t\t       \"  git rebase --continue\\n\"),\n +\t\t\treturn error(_(staged_changes_advice),\n  \t\t\t\t     gpg_opt, gpg_opt);\n  \t\t}\n  \t}\n @@ -702,10 +699,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n  \n  \tif (parent && parse_commit(parent) < 0)\n -\t\t/*\n -\t\t * TRANSLATORS: The first %s will be a \"todo\" command like\n -\t\t * \"revert\" or \"pick\", the second %s a SHA1.\n -\t\t */\n +\t\t/* TRANSLATORS: The first %s will be a \"todo\" command like\n +\t\t   \"revert\" or \"pick\", the second %s a SHA1. */\n  \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n  \t\t\tcommand_to_string(command),\n  \t\t\toid_to_hex(&parent->object.oid));\n @@ -885,7 +880,7 @@ static void todo_list_release(struct todo_list *todo_list)\n  \ttodo_list->nr = todo_list->alloc = 0;\n  }\n  \n -struct todo_item *append_new_todo(struct todo_list *todo_list)\n +static struct todo_item *append_new_todo(struct todo_list *todo_list)\n  {\n  \tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n  \treturn todo_list->items + todo_list->nr++;\n @@ -939,10 +934,10 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n  \tfor (i = 1; *p; i++, p = next_p) {\n  \t\tchar *eol = strchrnul(p, '\\n');\n  \n -\t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n +\t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n  \n  \t\tif (p != eol && eol[-1] == '\\r')\n -\t\t\teol--; /* skip Carriage Return */\n +\t\t\teol--; /* strip Carriage Return */\n  \n  \t\titem = append_new_todo(todo_list);\n  \t\titem->offset_in_buf = p - todo_list->buf.buf;\n @@ -994,6 +989,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n  \treturn 0;\n  }\n  \n +static int git_config_string_dup(char **dest,\n +\t\t\t\t const char *var, const char *value)\n +{\n +\tif (!value)\n +\t\treturn config_error_nonbool(var);\n +\tfree(*dest);\n +\t*dest = xstrdup(value);\n +\treturn 0;\n +}\n +\n  static int populate_opts_cb(const char *key, const char *value, void *data)\n  {\n  \tstruct replay_opts *opts = data;\n @@ -1013,22 +1018,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n  \t\topts->allow_ff = git_config_bool_or_int(key, value, &error_flag);\n  \telse if (!strcmp(key, \"options.mainline\"))\n  \t\topts->mainline = git_config_int(key, value);\n -\telse if (!strcmp(key, \"options.strategy\")) {\n -\t\tif (!value)\n -\t\t\tconfig_error_nonbool(key);\n -\t\telse {\n -\t\t\tfree(opts->strategy);\n -\t\t\topts->strategy = xstrdup(value);\n -\t\t}\n -\t}\n -\telse if (!strcmp(key, \"options.gpg-sign\")) {\n -\t\tif (!value)\n -\t\t\tconfig_error_nonbool(key);\n -\t\telse {\n -\t\t\tfree(opts->gpg_sign);\n -\t\t\topts->gpg_sign = xstrdup(value);\n -\t\t}\n -\t}\n +\telse if (!strcmp(key, \"options.strategy\"))\n +\t\tgit_config_string_dup(&opts->strategy, key, value);\n +\telse if (!strcmp(key, \"options.gpg-sign\"))\n +\t\tgit_config_string_dup(&opts->gpg_sign, key, value);\n  \telse if (!strcmp(key, \"options.strategy-option\")) {\n  \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n  \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n\n-- \n2.10.1.513.g00ef6dd\n\n"},{"id":"304173","messageId":"xmqqvawuzxwd.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610131242100.197091@virtualbox","subject":"Re: [PATCH v3 13/25] sequencer: prepare for rebase -i's commit functionality","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-14T16:41:06Z","receivedAt":"2016-10-14T16:41:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I think my puzzlement comes from here.  What makes it OK for \"am\" to\n>> expect the contents of author-script file to be quoted but it is not\n>> OK to expect the same here?  What makes it not quoted for _this_\n>> reader, in other words?\n>\n> The `git am` command is inherently *not* interactive, while the\n> interactive rebase, well, is.\n>\n> As such, we must assume that enterprisey users did come up with scripts\n> that edit, or create, author-script files, and exploited the fact that the\n> interactive rebase previously sourced them.\n\nIt's like saying \"While the program is waiting for user interaction,\nthe user can attach a debugger to tweak the contents of this string\nvariable.  Hence we must not assume that the string is always NUL\nterminated to protect ourselves.\"\n\nA correct response to such a user is to tell them not to do that,\nand do so at two levels.  \n\nThe first level may be \"it may be physically possible to tweak the\nstring via debugger but don't do that in such a way that breaks the\ninvariants our program relies on, or you are on your own\", but more\nimportant is the response at the second level.  Why is the user\nfutzing with that string in the first place with the debugger?  In\nthe context of author-script, the question is \"Why is the user\nfutzing with the author-script file\"?  To attribute the resulting\ncommit to a different author, of course.  But we need to step back\nand think why the user needs to resort to editing that file to\nachieve that.\n\nIf that is a common thing users would want to do, then we should\noffer an official way to do so, and it should not be \"you can futz\nwith author-script file with your editor\".  Something like \"have\n'exec git commit --amend' in the todo file\" may be more appropriate\nand if it is important enough, the sequencer command language may\nwant to learn an extra verb to update the author.\n\nBesides, the opportunity easiest for the user to futz with the\ncontents of author-script file (or \"attach the debugger while we\nwait for user interaction\") arises when \"rebase -i\" or \"am\" stops\nwaiting for conflict resolution.  Even when you run \"am\" without its\n\"-i\" option, it is equally susceptible to the \"user futzing with the\nfile\", which means your \"am is not interactive but 'rebase -i' is\"\nis irrelevant to the issue.  Oh, also, did I say \"am\" has \"-i\"\noption, which is a short-hand for \"--interactive\"?\n\nWhat disturbs me the most is that I know you know the system well\nenough to realize how bogus your argument to claim that \"rebase -i\"\nand \"am\" are different was and to come up with what I wrote above\nyourself.  Which means that I need to conclude that you have some\nother reasons why you want to keep this parser different, but I\nstill do not know what they are.\n\nI guess it entirely is possible that one of the reasons is because\nsome later patches in the larger \"rebase-i to sequencer\" series\nwrites author-script file in a syntax that cannot be read by the\nrecently refactored code \"am\" uses to read the author-script file,\nand reusing the existing code may end up breaking the endgame\n\"rebase -i\" you have.\n\nAs I do not feel like arguing with you on this any longer, and as I\ncertainly do not want to be blamed for breaking your \"rebase -i\", I\ndo not insist the code to be refactored to share with the existing\ncodepath.  But still I do not see the need to keep them separate (as\nI already said in the previous message, I am OK if the one used in\n\"am\" is updated to match).\n\n\n\n\n\n"},{"id":"304195","messageId":"20161015171926.qgtvrjcaqwb436hx@sigill.intra.peff.net","threadId":"43954","inReplyTo":"933b13d6-5f24-c03a-a1a0-712ceb8ddcc8@web.de","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-10-15T17:19:26Z","receivedAt":"2016-10-16T00:33:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Oct 15, 2016 at 07:03:46PM +0200, Torsten Bögershausen wrote:\n\n> sequencer.c:633:14: warning: comparison of constant 2 with expression of type 'const enum todo_command' is always true [-Wtautological-constant-out-of-range-compare]\n>         if (command < ARRAY_SIZE(todo_command_strings))\n>             ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n> 1 warning generated.\n>\n> 53f8024e (Johannes Schindelin   2016-10-10 19:25:07 +0200  633)         if (command < ARRAY_SIZE(todo_command_strings))\n> \n\nInteresting. The compiler is right that this _should_ never happen, but\nI think the patch is quite reasonable to be defensive in case the enum\nhappens to get a value outside of its acceptable range (which is\nprobably undefined behavior, but...).\n\nI wonder if:\n\n  if ((int)command < ARRAY_SIZE(todo_command_strings))\n\nsilences the warning (I suppose size_t is probably an even better type,\nthough obviously it does not matter in practice).\n\n-Peff\n\n"},{"id":"304197","messageId":"933b13d6-5f24-c03a-a1a0-712ceb8ddcc8@web.de","threadId":"43954","inReplyTo":"4e73ba3e8c1700259ffcc3224d1f66e6a760142d.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-10-15T17:03:46Z","receivedAt":"2016-10-16T00:33:53Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\nNot sure is this has been reported before:\n\n\nsequencer.c:633:14: warning: comparison of constant 2 with expression of type 'const enum todo_command' is always true [-Wtautological-constant-out-of-range-compare]\n        if (command < ARRAY_SIZE(todo_command_strings))\n            ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n1 warning generated.\n\n\n53f8024e (Johannes Schindelin   2016-10-10 19:25:07 +0200  633)         if (command < ARRAY_SIZE(todo_command_strings))\n\n"},{"id":"304199","messageId":"d9f4f658-94fb-cb9e-7da8-3a2fac120a9e@web.de","threadId":"43954","inReplyTo":"20161015171926.qgtvrjcaqwb436hx@sigill.intra.peff.net","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-10-15T17:40:15Z","receivedAt":"2016-10-16T00:33:55Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 15.10.16 19:19, Jeff King wrote:\n> On Sat, Oct 15, 2016 at 07:03:46PM +0200, Torsten Bögershausen wrote:\n> \n>> sequencer.c:633:14: warning: comparison of constant 2 with expression of type 'const enum todo_command' is always true [-Wtautological-constant-out-of-range-compare]\n>>         if (command < ARRAY_SIZE(todo_command_strings))\n>>             ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n>> 1 warning generated.\n>>\n>> 53f8024e (Johannes Schindelin   2016-10-10 19:25:07 +0200  633)         if (command < ARRAY_SIZE(todo_command_strings))\n>>\n> \n> Interesting. The compiler is right that this _should_ never happen, but\n> I think the patch is quite reasonable to be defensive in case the enum\n> happens to get a value outside of its acceptable range (which is\n> probably undefined behavior, but...).\n> \n> I wonder if:\n> \n>   if ((int)command < ARRAY_SIZE(todo_command_strings))\n> \n> silences the warning (I suppose size_t is probably an even better type,\n> though obviously it does not matter in practice).\n> \n> -Peff\n> \nBoth do (silence the warning)\n\nenum may be signed or unsigned, right ?\nSo the size_t variant seams to be a better choice\n\n\n\n"},{"id":"304210","messageId":"20161015174656.fmgk3le2b34nnjpx@sigill.intra.peff.net","threadId":"43954","inReplyTo":"d9f4f658-94fb-cb9e-7da8-3a2fac120a9e@web.de","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-10-15T17:46:56Z","receivedAt":"2016-10-16T00:34:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Oct 15, 2016 at 07:40:15PM +0200, Torsten Bögershausen wrote:\n\n> > I wonder if:\n> > \n> >   if ((int)command < ARRAY_SIZE(todo_command_strings))\n> > \n> > silences the warning (I suppose size_t is probably an even better type,\n> > though obviously it does not matter in practice).\n> > \n> Both do (silence the warning)\n> \n> enum may be signed or unsigned, right ?\n> So the size_t variant seams to be a better choice\n\nGood catch. It technically needs to check the lower bound, too. In\ntheory, if somebody wanted to add an enum value that is negative, you'd\nuse a signed cast and check against both 0 and ARRAY_SIZE(). In\npractice, that is nonsense for this case, and using an unsigned type\nmeans that any negative values become large, and the check catches them.\n\n-Peff\n"},{"id":"304224","messageId":"alpine.DEB.2.20.1610161006080.197091@virtualbox","threadId":"43954","inReplyTo":"20161015174656.fmgk3le2b34nnjpx@sigill.intra.peff.net","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-16T08:09:12Z","receivedAt":"2016-10-16T08:09:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 15 Oct 2016, Jeff King wrote:\n\n> On Sat, Oct 15, 2016 at 07:40:15PM +0200, Torsten Bögershausen wrote:\n> \n> > > I wonder if:\n> > > \n> > >   if ((int)command < ARRAY_SIZE(todo_command_strings))\n> > > \n> > > silences the warning (I suppose size_t is probably an even better type,\n> > > though obviously it does not matter in practice).\n> > > \n> > Both do (silence the warning)\n> > \n> > enum may be signed or unsigned, right ?\n> > So the size_t variant seams to be a better choice\n> \n> Good catch. It technically needs to check the lower bound, too. In\n> theory, if somebody wanted to add an enum value that is negative, you'd\n> use a signed cast and check against both 0 and ARRAY_SIZE(). In\n> practice, that is nonsense for this case, and using an unsigned type\n> means that any negative values become large, and the check catches them.\n\nI am pretty certain that I disagree with that warning: enums have been\nused as equivalents of ints for a long time, and will be, for a long time\nto come.\n\nGiven that this test is modified to `if (command < TODO_NOOP)` later, I\nhope that you agree that it is not worth the trouble to appease that\ncompiler overreaction?\n\nCiao,\nDscho"},{"id":"304228","messageId":"20161016194238.wbge2pas5xr46av7@sigill.intra.peff.net","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610161006080.197091@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-10-16T19:42:38Z","receivedAt":"2016-10-16T19:43:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Oct 16, 2016 at 10:09:12AM +0200, Johannes Schindelin wrote:\n\n> > Good catch. It technically needs to check the lower bound, too. In\n> > theory, if somebody wanted to add an enum value that is negative, you'd\n> > use a signed cast and check against both 0 and ARRAY_SIZE(). In\n> > practice, that is nonsense for this case, and using an unsigned type\n> > means that any negative values become large, and the check catches them.\n> \n> I am pretty certain that I disagree with that warning: enums have been\n> used as equivalents of ints for a long time, and will be, for a long time\n> to come.\n\nI'm not sure I agree. IIRC, Assigning values outside the range of an enum has\nalways been fishy according to the standard, and a compiler really is\nallowed to allocate a single bit for storage for this enum.\n\n> Given that this test is modified to `if (command < TODO_NOOP)` later, I\n> hope that you agree that it is not worth the trouble to appease that\n> compiler overreaction?\n\nI don't mind if there are transient warnings on some compilers in the\nmiddle of a series, but I'm not sure when \"later\" is. The tip of \"pu\"\nhas this warning right now when built with clang.\n\nI'm happy to test the TODO_NOOP version against clang (and prepare a\npatch on top if it still complains), but that doesn't seem to have\nJunio's tree at all yet.\n\n-Peff\n"},{"id":"304260","messageId":"alpine.DEB.2.20.1610171025470.197091@virtualbox","threadId":"43954","inReplyTo":"20161016194238.wbge2pas5xr46av7@sigill.intra.peff.net","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-17T08:37:52Z","receivedAt":"2016-10-17T08:38:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Peff,\n\nOn Sun, 16 Oct 2016, Jeff King wrote:\n\n> On Sun, Oct 16, 2016 at 10:09:12AM +0200, Johannes Schindelin wrote:\n> \n> > > Good catch. It technically needs to check the lower bound, too. In\n> > > theory, if somebody wanted to add an enum value that is negative, you'd\n> > > use a signed cast and check against both 0 and ARRAY_SIZE(). In\n> > > practice, that is nonsense for this case, and using an unsigned type\n> > > means that any negative values become large, and the check catches them.\n> > \n> > I am pretty certain that I disagree with that warning: enums have been\n> > used as equivalents of ints for a long time, and will be, for a long time\n> > to come.\n> \n> I'm not sure I agree. IIRC, Assigning values outside the range of an enum has\n> always been fishy according to the standard, and a compiler really is\n> allowed to allocate a single bit for storage for this enum.\n\nReally? I did see my share of code that completely violated this freedom,\nby assuming that it was really okay to cast a -1 to an enum and then test\nfor that value later, when -1 was not a legal enum value.\n\nIn any case, the fact that even one compiler used to build Git *may*\nviolate that standard, and that we therefore need such safety guards as\nthe one under discussion, still makes me think that this warning, while\ncertainly well-intentioned, is poison for cross-platform projects.\n\n> > Given that this test is modified to `if (command < TODO_NOOP)` later, I\n> > hope that you agree that it is not worth the trouble to appease that\n> > compiler overreaction?\n> \n> I don't mind if there are transient warnings on some compilers in the\n> middle of a series, but I'm not sure when \"later\" is. The tip of \"pu\"\n> has this warning right now when built with clang.\n\n\"Later\" is the sequencer-i patch series I already sent out for review\n[*1*], in particular the patch titled \"sequencer (rebase -i):\ndifferentiate between comments and 'noop'\" [*2*].\n\n> I'm happy to test the TODO_NOOP version against clang (and prepare a\n> patch on top if it still complains), but that doesn't seem to have\n> Junio's tree at all yet.\n\nJunio chose to pick up only one patch series out of the rebase--helper\nthicket at a time, it seems. I did send out at least one revision per\npatch series prior to integrating them into Git for Windows v2.10.0,\nthough. Plus, I kept updating the `interactive-rebase` branch in my\nrepository on GitHub (https://github.com/dscho/git).\n\nCiao,\nDscho\n\nFootnote *1*:\nhttps://public-inbox.org/git/cover.1472633606.git.johannes.schindelin@gmx.de/\n\nFootnote *2*:\nhttps://public-inbox.org/git/736bcb8e860c876e32e8f89f68b0b901abedc187.1472633606.git.johannes.schindelin@gmx.de/t/#u\n\nP.S.: I cannot wait for the day when somebody with an artistic touch\nprovides .css for the public-inbox.org site so it stops threatening\ncausing eye cancer to me.\n"},{"id":"304266","messageId":"20161017093608.qfevdonb336mglgx@sigill.intra.peff.net","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610171025470.197091@virtualbox","subject":"Re: [PATCH v3 07/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-10-17T09:36:09Z","receivedAt":"2016-10-17T09:36:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"[tl;dr: the version in your repo is fine, and there's a trivial fix\n below if we want to silence the warning in the meantime]\n\nOn Mon, Oct 17, 2016 at 10:37:52AM +0200, Johannes Schindelin wrote:\n\n> > I'm not sure I agree. IIRC, Assigning values outside the range of an enum has\n> > always been fishy according to the standard, and a compiler really is\n> > allowed to allocate a single bit for storage for this enum.\n> \n> Really? I did see my share of code that completely violated this freedom,\n> by assuming that it was really okay to cast a -1 to an enum and then test\n> for that value later, when -1 was not a legal enum value.\n\nI poked around a bit, and it seems we're both half-wrong. C99 says:\n\n  6.7.2.2 Enumeration specifiers\n  [...]\n  The expression that defines the value of an enumeration constant shall\n  be an integer constant expression that has a value representable as an\n  int.\n  [...]\n  Each enumerated type shall be compatible with char, a signed integer\n  type, or an unsigned integer type. The choice of type is\n  implementation-defined, but shall be capable of representing the\n  values of all the members of the enumeration.\n\nMy reading is that it can't be a single-bit bitfield as I claimed, but\nit also isn't necessarily interchangeable with an int. But you get at\nleast a \"char\", and you can use all of those integer values even if they\naren't explicitly part of the set. And I'd assume that goes for values\neven beyond the largest tag as long as you don't need more bits, so\nthat:\n\n  enum { A = 1, B = 2, C = 4 } x = A | B | C;\n\nis OK (though I didn't see anything particularly about that in the\nstandard).\n\nAssigning \"-1\" works in the same way that normal \"unsigned x = -1\" works\n(and is defined by the standard), though of course it may unexpectedly\nconflict with an actual enum value if the compiler chooses a smaller\ntype (e.g., it may literally be 255 in many cases).\n\nAnyway. Enough language lawyering. It seems like clang is being overly\nstrict in its interpretation of the standard (it should be giving us at\nleast a char's worth of values). But it matters less what the standard\nsays and more what real compilers do, and we have to deal with clang's\nbehavior.\n\n> In any case, the fact that even one compiler used to build Git *may*\n> violate that standard, and that we therefore need such safety guards as\n> the one under discussion, still makes me think that this warning, while\n> certainly well-intentioned, is poison for cross-platform projects.\n\nOh, I agree that the warning is annoying, and the code should not go\naway. We just need to figure out how to silence clang.\n\n> > I'm happy to test the TODO_NOOP version against clang (and prepare a\n> > patch on top if it still complains), but that doesn't seem to have\n> > Junio's tree at all yet.\n> \n> Junio chose to pick up only one patch series out of the rebase--helper\n> thicket at a time, it seems. I did send out at least one revision per\n> patch series prior to integrating them into Git for Windows v2.10.0,\n> though. Plus, I kept updating the `interactive-rebase` branch in my\n> repository on GitHub (https://github.com/dscho/git).\n\nThanks, I was able to test that branch. It looks like clang is happy\nwith it because you compare against the max value. Unlike the\nARRAY_SIZE() check, this does mean if somebody modifies the enum without\ntouching the array, we might go out of bounds. But things would be\nseverely broken enough from the mismatch that I don't think it's worth\nworrying about too much (and I see you have a nice comment warning\npeople about this).\n\nIf the rest of your interactive-rebase branch is coming soon, I think we\ncan probably ignore it for now. Otherwise something like:\n\ndiff --git a/sequencer.c b/sequencer.c\nindex d662c6b..1fdc35e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -620,7 +620,8 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \n enum todo_command {\n \tTODO_PICK = 0,\n-\tTODO_REVERT\n+\tTODO_REVERT,\n+\tTODO_MAX\n };\n \n\nis probably the simplest portable fix.\n\nAs a more clever change, I wondered if switching the enum values from\n(0,1) to (1,2) would silence the warning, and indeed it does. Which I\nassume is because using bit-flags, we could now represent \"1|2\", or \"3\",\nwhich is larger than the array (well, obviously \"2\" is, but we'd need to\nsubtract 1 when indexing the array). I don't think that's a good route,\nthough, because it loses the 0-indexing, the benefits of\nzero-initialization, etc. I was mostly just poking at how clang\nperceives the enum values.\n\n> P.S.: I cannot wait for the day when somebody with an artistic touch\n> provides .css for the public-inbox.org site so it stops threatening\n> causing eye cancer to me.\n\nHeh. I gently hinted something similar to Eric in the past, but I think\nhe actually likes how it looks. He has invited others to mirror\npublic-inbox and make their own interface, though. I just lack the\n\"artistic touch\" you mentioned.\n\n-Peff\n"},{"id":"304284","messageId":"xmqqr37ex5ck.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"b554346c600fafa71d2a3461fda8402e377b596e.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T17:17:31Z","receivedAt":"2016-10-17T17:18:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> +/*\n> + * Reads a file that was presumably written by a shell script, i.e.\n> + * with an end-of-line marker that needs to be stripped.\n> + *\n> + * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n> + */\n> +static int read_oneliner(struct strbuf *buf,\n> +\tconst char *path, int skip_if_empty)\n> +...\n> +\tif (strbuf_read_file(buf, path, 0) < 0) {\n> +\t\twarning_errno(_(\"could not read '%s'\"), path);\n> +\t\treturn 0;\n> +\t}\n> +\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n> +\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n> +\t\t\t--buf->len;\n> +\t\tbuf->buf[buf->len] = '\\0';\n> +\t}\n\nThe name says \"oneliner\" but this reads the whole thing and trims\nonly the last line of the input.  Which is correct?\n\nDo we want to error out if we got more than one line?  That makes it\nmore strict.  Going in the other direction, do we want to just read\nthe first line and ignore the remainder?  That allows users to leave\ncruft after what matters.  I _think_ the existing code is closer to\nthe latter, i.e. something along the lines of ...\n\n\tstruct strbuf oneline = STRBUF_INIT;\n\tFILE *fp = fopen(path, \"r\");\n\tif (!fp) {\n\t\twarning_errno(_(\"could not open '%s'\"), path);\n\t\treturn 0;\n\t}\n\tif (strbuf_getline(&oneline, fp) < 0)\n\t\t; /* EOF - empty */\n\telse {\n\t\tstrbuf_addbuf(buf, &oneline);\n\t}\n"},{"id":"304285","messageId":"xmqqmvi2x5aq.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"0577f66a108dced07775e10b87292c0eabfcc514.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 15/25] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T17:18:37Z","receivedAt":"2016-10-17T17:19:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> In the upcoming commits, we will implement more and more of rebase -i's\n> functionality inside the sequencer. One particular feature of the\n> commands to come is that some of them allow editing the commit message\n> while others don't, i.e. we cannot define in the replay_opts whether the\n> commit message should be edited or not.\n>\n> Let's add a new parameter to the run_git_commit() function. Previously,\n> it was the duty of the caller to ensure that the opts->edit setting\n> indicates whether to let the user edit the commit message or not,\n> indicating that it is an \"all or nothing\" setting, i.e. that the\n> sequencer wants to let the user edit *all* commit message, or none at\n> all. In the upcoming rebase -i mode, it will depend on the particular\n> command that is currently executed, though.\n\nMakes tons of sense.\n"},{"id":"304287","messageId":"xmqqinsqx54y.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"ec146dc2f3a3698bd433bbec4d7ecbab762c1bfb.1476120229.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 16/25] sequencer: support amending commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T17:22:05Z","receivedAt":"2016-10-17T17:22:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This teaches the run_git_commit() function to take an argument that will\n> allow us to implement \"todo\" commands that need to amend the commit\n> messages (\"fixup\", \"squash\" and \"reword\").\n\nLikewise to 15/25, i.e. Good, though the growth by these two steps\nstarts to make me wonder if these three options should be crammed\ninto an unsigned \"flags\" bitword.\n\nI see you have v4, so I'll ignore the remainder of this stale round\nand start reading that updated one instead.\n\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 6 ++++--\n>  1 file changed, 4 insertions(+), 2 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index b621f4b..403a4f0 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -481,7 +481,7 @@ static char **read_author_script(void)\n>   * author metadata.\n>   */\n>  static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit)\n> +\t\t\t  int allow_empty, int edit, int amend)\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n> @@ -510,6 +510,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n>  \targv_array_push(&array, \"commit\");\n>  \targv_array_push(&array, \"-n\");\n>  \n> +\tif (amend)\n> +\t\targv_array_push(&array, \"--amend\");\n>  \tif (opts->gpg_sign)\n>  \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n>  \tif (opts->signoff)\n> @@ -785,7 +787,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\t\t     opts, allow, opts->edit);\n> +\t\t\t\t     opts, allow, opts->edit, 0);\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n"},{"id":"304298","messageId":"xmqq4m4avlr7.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"b771bfbc88734b74acda0c377446e984ca81fd9c.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T19:06:04Z","receivedAt":"2016-10-17T19:06:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> like a one-shot command when it reads its configuration: memory is\n> allocated and released only when the command exits.\n>\n> This is kind of okay for git-cherry-pick, which *is* a one-shot\n> command. All the work to make the sequencer its work horse was\n> done to allow using the functionality as a library function, though,\n> including proper clean-up after use.\n>\n> To remedy that, we now take custody of the option values in question,\n> requiring those values to be malloc()ed or strdup()ed\n\nThat is the approach this patch takes, so \"eventually release\" in\nthe title is no longer accurate, I would think.\n\n> Sadly, the current approach makes the code uglier, as we now have to\n> take care to strdup() the values passed via the command-line.\n\nI obviously disagree with that statement and the _entrust was too\nugly to live, but it is obviously subjective, and it boils down to\nwho has a better taste.  Let's not go there.\n\n> +\n> +\t/* These option values will be free()d */\n> +\topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n> +\topts->strategy = xstrdup_or_null(opts->strategy);\n\nxstrdup-or-null does make things cleaner.\n\n> +static int git_config_string_dup(char **dest,\n> +\t\t\t\t const char *var, const char *value)\n> +{\n> +\tif (!value)\n> +\t\treturn config_error_nonbool(var);\n> +\tfree(*dest);\n> +\t*dest = xstrdup(value);\n> +\treturn 0;\n> +}\n\nSo does this.\n"},{"id":"304299","messageId":"xmqqzim2u721.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 00/25] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T19:08:54Z","receivedAt":"2016-10-17T19:09:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This patch series marks the '4' in the countdown to speed up rebase -i\n> by implementing large parts in C (read: there will be three more patch\n> series after that before the full benefit hits git.git: sequencer-i,\n> rebase--helper and rebase-i-extra). It is based on the `libify-sequencer`\n> patch series I submitted earlier.\n\nThe difference between the end results of v3 and v4 looked OK\n(except the 08/25 \"strip LF\" change that is unneeded) to me, so I'll\nskip the early part of the series from my review that correspond to\nthe ones in v3 that I've already reviewed and found good, and\ncontinue from the later ones.\n\nThanks.\n"},{"id":"304316","messageId":"xmqqfunusj1d.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"a5f5d784fcacc16555237b9750380d612387d0cb.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 08/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-17T22:33:02Z","receivedAt":"2016-10-17T22:33:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> -\tfor (i = 1; *p; i++) {\n> +\tfor (i = 1; *p; i++, p = next_p) {\n>  \t\tchar *eol = strchrnul(p, '\\n');\n> -\t\tcommit = parse_insn_line(p, eol, opts);\n> -\t\tif (!commit)\n> -\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n> -\t\tnext = commit_list_append(commit, next);\n> -\t\tp = *eol ? eol + 1 : eol;\n> +\n> +\t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n\nThis one was explained as \"skip LF\" in the previous round, and that\nis more correct than \"strip\", I think.  The +1 here is not done to\n\"strip\" the LF out of the end result, but to \"skip\" one to move to\nthe beginning of the next line.\n\nThe one in v3 08/25 decremented the pointer to denote the end of the\nline with the explicit purpose of not including the CR in the end\nresult, which was explained as \"skip CR\", but it was stripping CR.\nCorrecting that explanation to \"strip\" was a right fix and I think\nyour v4 09/25 still has it, which is good.\n\nOther than this unnecessary change since the previous round, I\ndidn't spot a difference in this step, which was already good.\n\nThanks.\n\n\n"},{"id":"304331","messageId":"alpine.DEB.2.20.1610181339550.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqr37ex5ck.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-18T11:42:36Z","receivedAt":"2016-10-18T11:42:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 17 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > +/*\n> > + * Reads a file that was presumably written by a shell script, i.e.\n> > + * with an end-of-line marker that needs to be stripped.\n> > + *\n> > + * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n> > + */\n> > +static int read_oneliner(struct strbuf *buf,\n> > +\tconst char *path, int skip_if_empty)\n> > +...\n> > +\tif (strbuf_read_file(buf, path, 0) < 0) {\n> > +\t\twarning_errno(_(\"could not read '%s'\"), path);\n> > +\t\treturn 0;\n> > +\t}\n> > +\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n> > +\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n> > +\t\t\t--buf->len;\n> > +\t\tbuf->buf[buf->len] = '\\0';\n> > +\t}\n> \n> The name says \"oneliner\" but this reads the whole thing and trims\n> only the last line of the input.  Which is correct?\n\nThe latter. Basically, `read_oneliner()` is short-hand for \"that thing\nthat shell does when you use `cat file` with backticks.\n\nI do not like `read_stripping_last_eol()`, `read_what_the_shell_wrote()`\nnor `read_skipping_last_lf()`. So if you come up with any brilliant idea,\nI am all ears.\n\nIn the meantime, I'd be happy to just add a comment that this function is\nintended for oneliners, but that it will also read multi-line files and\nonly strip off the EOL marker from the last line.\n\nWould that work for you?\nDscho\n"},{"id":"304332","messageId":"alpine.DEB.2.20.1610181352010.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqinsqx54y.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 16/25] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-18T11:53:10Z","receivedAt":"2016-10-18T11:53:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 17 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This teaches the run_git_commit() function to take an argument that will\n> > allow us to implement \"todo\" commands that need to amend the commit\n> > messages (\"fixup\", \"squash\" and \"reword\").\n> \n> Likewise to 15/25, i.e. Good, though the growth by these two steps\n> starts to make me wonder if these three options should be crammed\n> into an unsigned \"flags\" bitword.\n\nAfter looking at the diff with the added complications of ORing and ANDing\nthe flags, I'd much rather prefer to stay with the three flags being kept\nseparately. It's not like we need to save bits, but we need to preserve\nreadability as much as possible, I'd wager.\n\n> I see you have v4, so I'll ignore the remainder of this stale round\n> and start reading that updated one instead.\n\nThanks,\nDscho\n"},{"id":"304333","messageId":"alpine.DEB.2.20.1610181356460.197091@virtualbox","threadId":"43954","inReplyTo":"xmqq4m4avlr7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-18T12:03:58Z","receivedAt":"2016-10-18T12:04:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 17 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\n> > like a one-shot command when it reads its configuration: memory is\n> > allocated and released only when the command exits.\n> >\n> > This is kind of okay for git-cherry-pick, which *is* a one-shot\n> > command. All the work to make the sequencer its work horse was\n> > done to allow using the functionality as a library function, though,\n> > including proper clean-up after use.\n> >\n> > To remedy that, we now take custody of the option values in question,\n> > requiring those values to be malloc()ed or strdup()ed\n> \n> That is the approach this patch takes, so \"eventually release\" in\n> the title is no longer accurate, I would think.\n\nTo the contrary, we now free() things in remove_state(), so we still\n\"eventually release\" the memory.\n\n> > Sadly, the current approach makes the code uglier, as we now have to\n> > take care to strdup() the values passed via the command-line.\n> \n> I obviously disagree with that statement and the _entrust was too\n> ugly to live, but it is obviously subjective, and it boils down to\n> who has a better taste.  Let's not go there.\n\nChanged.\n\nThanks,\nDscho\n"},{"id":"304334","messageId":"alpine.DEB.2.20.1610181425440.197091@virtualbox","threadId":"43954","inReplyTo":"xmqqfunusj1d.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 08/25] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-18T12:25:57Z","receivedAt":"2016-10-18T12:26:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 17 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > -\tfor (i = 1; *p; i++) {\n> > +\tfor (i = 1; *p; i++, p = next_p) {\n> >  \t\tchar *eol = strchrnul(p, '\\n');\n> > -\t\tcommit = parse_insn_line(p, eol, opts);\n> > -\t\tif (!commit)\n> > -\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n> > -\t\tnext = commit_list_append(commit, next);\n> > -\t\tp = *eol ? eol + 1 : eol;\n> > +\n> > +\t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n> \n> This one was explained as \"skip LF\" in the previous round, and that\n> is more correct than \"strip\", I think.  The +1 here is not done to\n> \"strip\" the LF out of the end result, but to \"skip\" one to move to\n> the beginning of the next line.\n\nChanged,\nDscho\n"},{"id":"304342","messageId":"xmqqpomxr6t6.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610181339550.197091@virtualbox","subject":"Re: [PATCH v3 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-18T15:54:45Z","receivedAt":"2016-10-18T15:55:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> In the meantime, I'd be happy to just add a comment that this function is\n> intended for oneliners, but that it will also read multi-line files and\n> only strip off the EOL marker from the last line.\n>\n> Would that work for you?\n\nThat would be ideal, I would think.\n"},{"id":"304343","messageId":"xmqqlgxlr6q0.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610181352010.197091@virtualbox","subject":"Re: [PATCH v3 16/25] sequencer: support amending commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-18T15:56:39Z","receivedAt":"2016-10-18T15:56:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Mon, 17 Oct 2016, Junio C Hamano wrote:\n>\n>> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>> \n>> > This teaches the run_git_commit() function to take an argument that will\n>> > allow us to implement \"todo\" commands that need to amend the commit\n>> > messages (\"fixup\", \"squash\" and \"reword\").\n>> \n>> Likewise to 15/25, i.e. Good, though the growth by these two steps\n>> starts to make me wonder if these three options should be crammed\n>> into an unsigned \"flags\" bitword.\n>\n> After looking at the diff with the added complications of ORing and ANDing\n> the flags, I'd much rather prefer to stay with the three flags being kept\n> separately. It's not like we need to save bits, but we need to preserve\n> readability as much as possible, I'd wager.\n\nThat's OK.  I just wanted to make sure pros-and-cons have been\nalready considered.\n\nThe primary merit of using flags bitword is not to save bits; it is\ndone to limit the damage to the codebase when we need to add yet\nanother knob, by the way.\n"},{"id":"304373","messageId":"xmqq1szdnnvc.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610181356460.197091@virtualbox","subject":"Re: [PATCH v4 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-19T01:12:07Z","receivedAt":"2016-10-19T01:12:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > To remedy that, we now take custody of the option values in question,\n>> > requiring those values to be malloc()ed or strdup()ed\n>> \n>> That is the approach this patch takes, so \"eventually release\" in\n>> the title is no longer accurate, I would think.\n>\n> To the contrary, we now free() things in remove_state(), so we still\n> \"eventually release\" the memory.\n\nOK.  We call a change to teach remove_state() to free the resource\ndoes more commonly as \"plug leaks\"; the word \"eventually\" gave me an\nimpression that we are emphasizing the fact that we do not free(3)\nimmediately but lazily do so at the end, hence my response.\n"},{"id":"304463","messageId":"alpine.DEB.2.20.1610201406560.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqpomxr6t6.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 14/25] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-20T12:07:03Z","receivedAt":"2016-10-20T12:07:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 18 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > In the meantime, I'd be happy to just add a comment that this function is\n> > intended for oneliners, but that it will also read multi-line files and\n> > only strip off the EOL marker from the last line.\n> >\n> > Would that work for you?\n> \n> That would be ideal, I would think.\n\nDone,\nDscho\n"},{"id":"304464","messageId":"alpine.DEB.2.20.1610201415570.3264@virtualbox","threadId":"43954","inReplyTo":"xmqq1szdnnvc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 05/25] sequencer: eventually release memory allocated for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-20T12:16:11Z","receivedAt":"2016-10-20T12:16:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 18 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> > To remedy that, we now take custody of the option values in question,\n> >> > requiring those values to be malloc()ed or strdup()ed\n> >> \n> >> That is the approach this patch takes, so \"eventually release\" in\n> >> the title is no longer accurate, I would think.\n> >\n> > To the contrary, we now free() things in remove_state(), so we still\n> > \"eventually release\" the memory.\n> \n> OK.  We call a change to teach remove_state() to free the resource\n> does more commonly as \"plug leaks\"; the word \"eventually\" gave me an\n> impression that we are emphasizing the fact that we do not free(3)\n> immediately but lazily do so at the end, hence my response.\n\nI changed the commit subject, hopefully to your liking,\nDscho\n"},{"id":"304507","messageId":"xmqqr37ag4zo.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"4173eb7716e8f4fbd083961a05dc4329686a9912.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 17/25] sequencer: support cleaning up commit messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:06:19Z","receivedAt":"2016-10-20T20:06:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The run_git_commit() function already knows how to amend commits, and\n> with this new option, it can also clean up commit messages (i.e. strip\n> out commented lines). This is needed to implement rebase -i's 'fixup'\n> and 'squash' commands as sequencer commands.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 10 +++++++---\n>  1 file changed, 7 insertions(+), 3 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index fa77c82..cbc3742 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -481,7 +481,8 @@ static char **read_author_script(void)\n>   * author metadata.\n>   */\n>  static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n> -\t\t\t  int allow_empty, int edit, int amend)\n> +\t\t\t  int allow_empty, int edit, int amend,\n> +\t\t\t  int cleanup_commit_message)\n>  {\n>  \tchar **env = NULL;\n>  \tstruct argv_array array;\n\nLooks OK to me.  \n\nThis starts to look like calling for a single flag word even more,\nbut it is a file-local helper so we can clean it up if it becomes\nnecessary without affecting too many things later.\n\n> @@ -518,9 +519,12 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n>  \t\targv_array_push(&array, \"-s\");\n>  \tif (defmsg)\n>  \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n> +\tif (cleanup_commit_message)\n> +\t\targv_array_push(&array, \"--cleanup=strip\");\n>  \tif (edit)\n>  \t\targv_array_push(&array, \"-e\");\n> -\telse if (!opts->signoff && !opts->record_origin &&\n> +\telse if (!cleanup_commit_message &&\n> +\t\t !opts->signoff && !opts->record_origin &&\n>  \t\t git_config_get_value(\"commit.cleanup\", &value))\n>  \t\targv_array_push(&array, \"--cleanup=verbatim\");\n>  \n> @@ -785,7 +789,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t}\n>  \tif (!opts->no_commit)\n>  \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n> -\t\t\t\t     opts, allow, opts->edit, 0);\n> +\t\t\t\t     opts, allow, opts->edit, 0, 0);\n>  \n>  leave:\n>  \tfree_message(commit, &msg);\n"},{"id":"304508","messageId":"xmqqmvhyg4ru.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"38d5f853444f80c90713f7a6e4ef1f2382549b29.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 18/25] sequencer: do not try to commit when there were merge conflicts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:11:01Z","receivedAt":"2016-10-20T20:11:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The return value of do_recursive_merge() may be positive (indicating merge\n> conflicts), or 0 (indicating success). It also may be negative, indicating\n> a fatal error that requires us to abort.\n>\n> Now, if the return value indicates that there are merge conflicts, we\n> should not try to commit those changes, of course.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index cbc3742..9ffc090 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -787,7 +787,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t\tres = allow;\n>  \t\tgoto leave;\n>  \t}\n> -\tif (!opts->no_commit)\n> +\tif (!res && !opts->no_commit)\n>  \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n>  \t\t\t\t     opts, allow, opts->edit, 0, 0);\n\nThis by itself looks more like a bugfix than preparation for later\nsteps.  The only reason why it is not a bugfix is because there is\nnothing in this function that makes res a non-zero value and reach\nthis if statement at this step.  We would have been caught by an \n\"if (res) { ... rerere(); goto leave; }\" or \n\"if (allow < 0) { res = allow; goto leave; }\" \nthat appear before this part of the code.\n\nSo while it is not wrong per-se, I think this should be part of an\nactual change that makes it possible for the control flow to reach\nhere with non-zero res.\n\n\n"},{"id":"304509","messageId":"xmqqh986g49i.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"9a66d53ebd86d35136597e534be03605bb1346bc.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:22:01Z","receivedAt":"2016-10-20T20:22:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The write_message() function safely writes an strbuf to a file.\n> Sometimes it is inconvenient to require an strbuf, though: the text to\n> be written may not be stored in a strbuf, or the strbuf should not be\n> released after writing.\n>\n> Let's refactor \"safely writing string to a file\" into\n> write_with_lock_file(), and make write_message() use it.\n>\n> The new function will make it easy to create a new convenience function\n> write_file_gently() that does not die(); as some of the upcoming callers\n> of this new function will want to append a newline character, we already\n> add that flag as parameter to write_with_lock_file().\n>\n> While at it, roll back the locked files in case of failure, as pointed\n> out by Hannes Sixt.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  sequencer.c | 25 ++++++++++++++++++++-----\n>  1 file changed, 20 insertions(+), 5 deletions(-)\n\nOnce a helper function starts taking <buf, len> pair, not a strbuf,\nit becomes obvious that it does not make much sense to calling\nstrbuf_release() from the helper.  It is caller's job to do the\nmemory management of the strbuf it uses to pass information to the\nhelper, and the current api into write_message() is klunky.\n\nIf I were doing this, I would make this into three separate steps:\n\n    - move the strbuf_release(msgbuf) to the caller in\n      do_pick_commit();\n\n    - add the missing rollback_lock_file(), which is a bugfix; and\n      then finally\n\n    - allow the helper to take not a strbuf but <buf, len> pair as\n      parameters.\n\nThe end result of this patch achieves two thirds of the above, but\nespecially given that write_message() only has two call sites in a\nsingle function, I think it is OK and preferrable even to do all\nthree.\n"},{"id":"304510","messageId":"xmqqd1iug42f.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"xmqqh986g49i.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:26:16Z","receivedAt":"2016-10-20T20:26:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> If I were doing this, I would make this into three separate steps:\n>\n>     - move the strbuf_release(msgbuf) to the caller in\n>       do_pick_commit();\n>\n>     - add the missing rollback_lock_file(), which is a bugfix; and\n>       then finally\n>\n>     - allow the helper to take not a strbuf but <buf, len> pair as\n>       parameters.\n>\n> The end result of this patch achieves two thirds of the above, but\n> especially given that write_message() only has two call sites in a\n> single function, I think it is OK and preferrable even to do all\n> three.\n\nAh, make that four steps.  The final one is:\n\n    - add append_eol parameter that nobody uses at this step in the\n      series.\n\nThis is a new feature to the helper.  While it is OK to have it as a\npreparatory step in this series, it is easier to understand if it\nkept as a separate step.  It is even more preferrable if it is made\nas a preparatory step in a series that adds a caller that passes\ntrue to append_eol to this helper, or if that real change is small\nenough, part of that patch that adds such a caller, not as a\nseparate step.\n\n\n"},{"id":"304511","messageId":"xmqq8ttig3zn.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"930ea31d6f10973807276c7a9f35f0d692d1ada6.1476450940.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 23/25] sequencer: quote filenames in error messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:27:56Z","receivedAt":"2016-10-20T20:28:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This makes the code consistent by fixing quite a couple of error messages.\n>\n> Suggested by Jakub Narębski.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nThese finishing touches in 21-23 look all sensible to me.\n"},{"id":"304512","messageId":"xmqq4m46g3y3.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"xmqq8ttig3zn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 23/25] sequencer: quote filenames in error messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-20T20:28:52Z","receivedAt":"2016-10-20T20:29:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>\n>> This makes the code consistent by fixing quite a couple of error messages.\n>>\n>> Suggested by Jakub Narębski.\n>>\n>> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> ---\n>\n> These finishing touches in 21-23 look all sensible to me.\n\nMake that 21-25.  I finished reading to the end and it was mostly a\npleasnt read, except for a few things I noticed and sent reviews\nseparately.\n\nThanks.\n"},{"id":"304573","messageId":"alpine.DEB.2.20.1610211304240.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqmvhyg4ru.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 18/25] sequencer: do not try to commit when there were merge conflicts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T11:10:50Z","receivedAt":"2016-10-21T11:11:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 20 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > The return value of do_recursive_merge() may be positive (indicating merge\n> > conflicts), or 0 (indicating success). It also may be negative, indicating\n> > a fatal error that requires us to abort.\n> >\n> > Now, if the return value indicates that there are merge conflicts, we\n> > should not try to commit those changes, of course.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  sequencer.c | 2 +-\n> >  1 file changed, 1 insertion(+), 1 deletion(-)\n> >\n> > diff --git a/sequencer.c b/sequencer.c\n> > index cbc3742..9ffc090 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -787,7 +787,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n> >  \t\tres = allow;\n> >  \t\tgoto leave;\n> >  \t}\n> > -\tif (!opts->no_commit)\n> > +\tif (!res && !opts->no_commit)\n> >  \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n> >  \t\t\t\t     opts, allow, opts->edit, 0, 0);\n> \n> This by itself looks more like a bugfix than preparation for later\n> steps.  The only reason why it is not a bugfix is because there is\n> nothing in this function that makes res a non-zero value and reach\n> this if statement at this step.  We would have been caught by an \n> \"if (res) { ... rerere(); goto leave; }\" or \n> \"if (allow < 0) { res = allow; goto leave; }\" \n> that appear before this part of the code.\n> \n> So while it is not wrong per-se, I think this should be part of an\n> actual change that makes it possible for the control flow to reach\n> here with non-zero res.\n\nIt looks like it is no longer needed (I *think* that it was made obsolete\nby the change where I now \"goto fast_forward_edit\" only in case there were\nno errors).\n\nIn any case, the patch's gone now,\nDscho\n"},{"id":"304574","messageId":"alpine.DEB.2.20.1610211343310.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqd1iug42f.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T11:43:41Z","receivedAt":"2016-10-21T11:43:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 20 Oct 2016, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > If I were doing this, I would make this into three separate steps:\n> >\n> >     - move the strbuf_release(msgbuf) to the caller in\n> >       do_pick_commit();\n> >\n> >     - add the missing rollback_lock_file(), which is a bugfix; and\n> >       then finally\n> >\n> >     - allow the helper to take not a strbuf but <buf, len> pair as\n> >       parameters.\n> >\n> > The end result of this patch achieves two thirds of the above, but\n> > especially given that write_message() only has two call sites in a\n> > single function, I think it is OK and preferrable even to do all\n> > three.\n> \n> Ah, make that four steps.  The final one is:\n> \n>     - add append_eol parameter that nobody uses at this step in the\n>       series.\n\nDone,\nDscho\n"},{"id":"304576","messageId":"cover.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1476450940.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:23:45Z","receivedAt":"2016-10-21T12:24:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series marks the '4' in the countdown to speed up rebase -i\nby implementing large parts in C (read: there will be three more patch\nseries after that before the full benefit hits git.git: sequencer-i,\nrebase--helper and rebase-i-extra). It is based on the `libify-sequencer`\npatch series I submitted earlier.\n\nThe patches in this series merely prepare the sequencer code for the\nnext patch series that actually teaches the sequencer to run rebase -i's\ncommands.\n\nThe reason to split these two patch series is simple: to keep them at a\nsensible size.\n\nThe two patch series after that are much smaller: a two-patch \"series\"\nthat switches rebase -i to use the sequencer (except with --root or\n--preserve-merges), and a couple of patches to move several pretty\nexpensive script processing steps to C (think: autosquash).\n\nThe end game of this patch series is a git-rebase--helper that makes\nrebase -i 5x faster on Windows (according to t/perf/p3404). Travis says\nthat even MacOSX and Linux benefit (4x and 3x, respectively).\n\nI have been working on this since early February, whenever time allowed,\nand it is time to put it into the users' hands. To that end, I already\nintegrated the whole shebang into Git for Windows 2.10.0 and 2.10.1\nwhere it has been running without complaints (and some quite positive\nfeedback).\n\nIt would be *really* nice if we could get this patch series at least into\n`next` soon, as it gets late and later for the rest of the patches to make\nit into `master` in time for v2.11 (and it is not for lack of trying on my\nend...).\n\nChanges vs v4:\n\n- clarified in a code comment that read_oneliner() is lenient when it\n  comes to multi-line files: it still reads the entire file, but strips\n  off only the final EOL (if any).\n\n- rephrased a commit message to stop judging Junio's taste ;-)\n\n- changed \"strip LF\" to \"skip LF\", as requested.\n\n- rephrased a commit message to talk about pluggin memory leaks instead\n  of stating that the memory is now eventually released.\n\n- dropped the \"sequencer: do not try to commit when there were merge\n  conflicts\" patch that appears to be no longer necessary.\n\n- split and modified the commit refactoring write_message() according to\n  Junio's suggestions.\n\n\nJohannes Schindelin (27):\n  sequencer: use static initializers for replay_opts\n  sequencer: use memoized sequencer directory path\n  sequencer: avoid unnecessary indirection\n  sequencer: future-proof remove_sequencer_state()\n  sequencer: plug memory leaks for the option values\n  sequencer: future-proof read_populate_todo()\n  sequencer: refactor the code to obtain a short commit name\n  sequencer: completely revamp the \"todo\" script parsing\n  sequencer: strip CR from the todo script\n  sequencer: avoid completely different messages for different actions\n  sequencer: get rid of the subcommand field\n  sequencer: remember the onelines when parsing the todo file\n  sequencer: prepare for rebase -i's commit functionality\n  sequencer: introduce a helper to read files written by scripts\n  sequencer: allow editing the commit message on a case-by-case basis\n  sequencer: support amending commits\n  sequencer: support cleaning up commit messages\n  sequencer: left-trim lines read from the script\n  sequencer: stop releasing the strbuf in write_message()\n  sequencer: roll back lock file if write_message() failed\n  sequencer: refactor write_message() to take a pointer/length\n  sequencer: teach write_message() to append an optional LF\n  sequencer: remove overzealous assumption in rebase -i mode\n  sequencer: mark action_name() for translation\n  sequencer: quote filenames in error messages\n  sequencer: start error messages consistently with lower case\n  sequencer: mark all error messages for translation\n\n builtin/commit.c              |   2 +-\n builtin/revert.c              |  46 ++-\n sequencer.c                   | 680 ++++++++++++++++++++++++++++--------------\n sequencer.h                   |  23 +-\n t/t3501-revert-cherry-pick.sh |   2 +-\n 5 files changed, 492 insertions(+), 261 deletions(-)\n\n\nbase-commit: 659889482ac63411daea38b2c3d127842ea04e4d\nPublished-As: https://github.com/dscho/git/releases/tag/prepare-sequencer-v5\nFetch-It-Via: git fetch https://github.com/dscho/git prepare-sequencer-v5\n\nInterdiff vs v4:\n\n diff --git a/sequencer.c b/sequencer.c\n index 1cf70f7..a61fe76 100644\n --- a/sequencer.c\n +++ b/sequencer.c\n @@ -234,8 +234,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n  \t}\n  }\n  \n -static int write_with_lock_file(const char *filename,\n -\t\t\t\tconst void *buf, size_t len, int append_eol)\n +static int write_message(const void *buf, size_t len, const char *filename,\n +\t\t\t int append_eol)\n  {\n  \tstatic struct lock_file msg_file;\n  \n @@ -258,16 +258,12 @@ static int write_with_lock_file(const char *filename,\n  \treturn 0;\n  }\n  \n -static int write_message(struct strbuf *msgbuf, const char *filename)\n -{\n -\tint res = write_with_lock_file(filename, msgbuf->buf, msgbuf->len, 0);\n -\tstrbuf_release(msgbuf);\n -\treturn res;\n -}\n -\n  /*\n - * Reads a file that was presumably written by a shell script, i.e.\n - * with an end-of-line marker that needs to be stripped.\n + * Reads a file that was presumably written by a shell script, i.e. with an\n + * end-of-line marker that needs to be stripped.\n + *\n + * Note that only the last end-of-line marker is stripped, consistent with the\n + * behavior of \"$(cat path)\" in a shell script.\n   *\n   * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n   */\n @@ -762,12 +758,14 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\t\t\t\t head, &msgbuf, opts);\n  \t\tif (res < 0)\n  \t\t\treturn res;\n -\t\tres |= write_message(&msgbuf, git_path_merge_msg());\n +\t\tres |= write_message(msgbuf.buf, msgbuf.len,\n +\t\t\t\t     git_path_merge_msg(), 0);\n  \t} else {\n  \t\tstruct commit_list *common = NULL;\n  \t\tstruct commit_list *remotes = NULL;\n  \n -\t\tres = write_message(&msgbuf, git_path_merge_msg());\n +\t\tres = write_message(msgbuf.buf, msgbuf.len,\n +\t\t\t\t    git_path_merge_msg(), 0);\n  \n  \t\tcommit_list_insert(base, &common);\n  \t\tcommit_list_insert(next, &remotes);\n @@ -777,6 +775,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\tfree_commit_list(common);\n  \t\tfree_commit_list(remotes);\n  \t}\n +\tstrbuf_release(&msgbuf);\n  \n  \t/*\n  \t * If the merge was clean or if it failed due to conflict, we write\n @@ -808,7 +807,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n  \t\tres = allow;\n  \t\tgoto leave;\n  \t}\n -\tif (!res && !opts->no_commit)\n +\tif (!opts->no_commit)\n  \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n  \t\t\t\t     opts, allow, opts->edit, 0, 0);\n  \n @@ -934,7 +933,7 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n  \tfor (i = 1; *p; i++, p = next_p) {\n  \t\tchar *eol = strchrnul(p, '\\n');\n  \n -\t\tnext_p = *eol ? eol + 1 /* strip LF */ : eol;\n +\t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n  \n  \t\tif (p != eol && eol[-1] == '\\r')\n  \t\t\teol--; /* strip Carriage Return */\n\n-- \n2.10.1.583.g721a9e0\n\n"},{"id":"304577","messageId":"5da5d267fe291070af0e7a98b811dbfbced2d7ca.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 02/27] sequencer: use memoized sequencer directory path","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:23:57Z","receivedAt":"2016-10-21T12:24:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/commit.c |  2 +-\n sequencer.c      | 11 ++++++-----\n sequencer.h      |  5 +----\n 3 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1cba3b7..9fddb19 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -183,7 +183,7 @@ static void determine_whence(struct wt_status *s)\n \t\twhence = FROM_MERGE;\n \telse if (file_exists(git_path_cherry_pick_head())) {\n \t\twhence = FROM_CHERRY_PICK;\n-\t\tif (file_exists(git_path(SEQ_DIR)))\n+\t\tif (file_exists(git_path_seq_dir()))\n \t\t\tsequencer_in_use = 1;\n \t}\n \telse\ndiff --git a/sequencer.c b/sequencer.c\nindex eec8a60..cb16cbd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -21,10 +21,11 @@\n const char sign_off_header[] = \"Signed-off-by: \";\n static const char cherry_picked_prefix[] = \"(cherry picked from commit \";\n \n-static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)\n-static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)\n-static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)\n-static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)\n+GIT_PATH_FUNC(git_path_seq_dir, \"sequencer\")\n+\n+static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n+static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n+static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n static int is_rfc2822_line(const char *buf, int len)\n {\n@@ -112,7 +113,7 @@ static void remove_sequencer_state(void)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path(SEQ_DIR));\n+\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n \tremove_dir_recursively(&seq_dir, 0);\n \tstrbuf_release(&seq_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex db425ad..dd4d33a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -1,10 +1,7 @@\n #ifndef SEQUENCER_H\n #define SEQUENCER_H\n \n-#define SEQ_DIR\t\t\"sequencer\"\n-#define SEQ_HEAD_FILE\t\"sequencer/head\"\n-#define SEQ_TODO_FILE\t\"sequencer/todo\"\n-#define SEQ_OPTS_FILE\t\"sequencer/opts\"\n+const char *git_path_seq_dir(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304578","messageId":"412aae8842d0a33e1da72107540a7edea810fd54.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 01/27] sequencer: use static initializers for replay_opts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:23:52Z","receivedAt":"2016-10-21T12:24:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This change is not completely faithful: instead of initializing all fields\nto 0, we choose to initialize command and subcommand to -1 (instead of\ndefaulting to REPLAY_REVERT and REPLAY_NONE, respectively). Practically,\nit makes no difference at all, but future-proofs the code to require\nexplicit assignments for both fields.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 6 ++----\n sequencer.h      | 1 +\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4e69380..7365559 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -178,10 +178,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n@@ -195,10 +194,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts;\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n \n-\tmemset(&opts, 0, sizeof(opts));\n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n \tparse_args(argc, argv, &opts);\ndiff --git a/sequencer.h b/sequencer.h\nindex 5ed5cb1..db425ad 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -47,6 +47,7 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n+#define REPLAY_OPTS_INIT { -1, -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304579","messageId":"45451bc8b0bd49a1de83ab5c32e2b4f5b63a2df5.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 04/27] sequencer: future-proof remove_sequencer_state()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:07Z","receivedAt":"2016-10-21T12:24:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In a couple of commits, we will teach the sequencer to handle the\nnitty gritty of the interactive rebase, which keeps its state in a\ndifferent directory.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c2fbf6f..8d272fb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,11 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+static const char *get_dir(const struct replay_opts *opts)\n+{\n+\treturn git_path_seq_dir();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -109,13 +114,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(void)\n+static void remove_sequencer_state(const struct replay_opts *opts)\n {\n-\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf dir = STRBUF_INIT;\n \n-\tstrbuf_addstr(&seq_dir, git_path_seq_dir());\n-\tremove_dir_recursively(&seq_dir, 0);\n-\tstrbuf_release(&seq_dir);\n+\tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -940,7 +945,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n \treturn 0;\n fail:\n@@ -1034,7 +1039,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state();\n+\tremove_sequencer_state(opts);\n \treturn 0;\n }\n \n@@ -1095,7 +1100,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t * one that is being continued\n \t */\n \tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(opts);\n \t\treturn 0;\n \t}\n \tif (opts->subcommand == REPLAY_ROLLBACK)\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304581","messageId":"2c79d34e66b1f2b1a4b0f30445996c6c1a89d39a.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 03/27] sequencer: avoid unnecessary indirection","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:03Z","receivedAt":"2016-10-21T12:24:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We really do not need the *pointer to a* pointer to the options in\nthe read_populate_opts() function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb16cbd..c2fbf6f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -813,7 +813,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static int read_populate_opts(struct replay_opts **opts)\n+static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n@@ -823,7 +823,7 @@ static int read_populate_opts(struct replay_opts **opts)\n \t * about this case, though, because we wrote that file ourselves, so we\n \t * are pretty certain that it is syntactically correct.\n \t */\n-\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)\n+\tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n \t\treturn error(_(\"Malformed options sheet: %s\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n@@ -1054,7 +1054,7 @@ static int sequencer_continue(struct replay_opts *opts)\n \n \tif (!file_exists(git_path_todo_file()))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(&opts) ||\n+\tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n \t\treturn -1;\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304582","messageId":"2adce611dc9157167d715b5985ebb492bb880b37.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 05/27] sequencer: plug memory leaks for the option values","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:13Z","receivedAt":"2016-10-21T12:24:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer is our attempt to lib-ify cherry-pick. Yet it behaves\nlike a one-shot command when it reads its configuration: memory is\nallocated and released only when the command exits.\n\nThis is kind of okay for git-cherry-pick, which *is* a one-shot\ncommand. All the work to make the sequencer its work horse was\ndone to allow using the functionality as a library function, though,\nincluding proper clean-up after use.\n\nTo remedy that, we now take custody of the option values in question,\nrequiring those values to be malloc()ed or strdup()ed (an alternative\napproach, to add a list of pointers to malloc()ed data and to ask the\nsequencer to release all of them in the end, was proposed earlier but\nrejected during review).\n\nNote: this means that we now have to take care to strdup() the values\npassed via the command-line.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c |  4 ++++\n sequencer.c      | 26 ++++++++++++++++++++++----\n sequencer.h      |  6 +++---\n 3 files changed, 29 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 7365559..ba5a88c 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -174,6 +174,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \n \tif (argc > 1)\n \t\tusage_with_options(usage_str, options);\n+\n+\t/* These option values will be free()d */\n+\topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n+\topts->strategy = xstrdup_or_null(opts->strategy);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\ndiff --git a/sequencer.c b/sequencer.c\nindex 8d272fb..04c55f2 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -117,6 +117,13 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n static void remove_sequencer_state(const struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n+\tint i;\n+\n+\tfree(opts->gpg_sign);\n+\tfree(opts->strategy);\n+\tfor (i = 0; i < opts->xopts_nr; i++)\n+\t\tfree(opts->xopts[i]);\n+\tfree(opts->xopts);\n \n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n@@ -280,7 +287,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \tstruct merge_options o;\n \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n \tint clean;\n-\tconst char **xopt;\n+\tchar **xopt;\n \tstatic struct lock_file index_lock;\n \n \thold_locked_index(&index_lock, 1);\n@@ -583,7 +590,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-\t\tres |= try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,\n+\t\tres |= try_merge_command(opts->strategy,\n+\t\t\t\t\t opts->xopts_nr, (const char **)opts->xopts,\n \t\t\t\t\tcommon, sha1_to_hex(head), remotes);\n \t\tfree_commit_list(common);\n \t\tfree_commit_list(remotes);\n@@ -783,6 +791,16 @@ static int read_populate_todo(struct commit_list **todo_list,\n \treturn 0;\n }\n \n+static int git_config_string_dup(char **dest,\n+\t\t\t\t const char *var, const char *value)\n+{\n+\tif (!value)\n+\t\treturn config_error_nonbool(var);\n+\tfree(*dest);\n+\t*dest = xstrdup(value);\n+\treturn 0;\n+}\n+\n static int populate_opts_cb(const char *key, const char *value, void *data)\n {\n \tstruct replay_opts *opts = data;\n@@ -803,9 +821,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \telse if (!strcmp(key, \"options.mainline\"))\n \t\topts->mainline = git_config_int(key, value);\n \telse if (!strcmp(key, \"options.strategy\"))\n-\t\tgit_config_string(&opts->strategy, key, value);\n+\t\tgit_config_string_dup(&opts->strategy, key, value);\n \telse if (!strcmp(key, \"options.gpg-sign\"))\n-\t\tgit_config_string(&opts->gpg_sign, key, value);\n+\t\tgit_config_string_dup(&opts->gpg_sign, key, value);\n \telse if (!strcmp(key, \"options.strategy-option\")) {\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\ndiff --git a/sequencer.h b/sequencer.h\nindex dd4d33a..8453669 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -34,11 +34,11 @@ struct replay_opts {\n \n \tint mainline;\n \n-\tconst char *gpg_sign;\n+\tchar *gpg_sign;\n \n \t/* Merge strategy */\n-\tconst char *strategy;\n-\tconst char **xopts;\n+\tchar *strategy;\n+\tchar **xopts;\n \tsize_t xopts_nr, xopts_alloc;\n \n \t/* Only used by REPLAY_NONE */\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304583","messageId":"59de82a36f93a38acaa72c59c794c59604b507d2.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 06/27] sequencer: future-proof read_populate_todo()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:32Z","receivedAt":"2016-10-21T12:25:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Over the next commits, we will work on improving the sequencer to the\npoint where it can process the todo script of an interactive rebase. To\nthat end, we will need to teach the sequencer to read interactive\nrebase's todo file. In preparation, we consolidate all places where\nthat todo file is needed to call a function that we will later extend.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 04c55f2..fb0b94b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -32,6 +32,11 @@ static const char *get_dir(const struct replay_opts *opts)\n \treturn git_path_seq_dir();\n }\n \n+static const char *get_todo_path(const struct replay_opts *opts)\n+{\n+\treturn git_path_todo_file();\n+}\n+\n static int is_rfc2822_line(const char *buf, int len)\n {\n \tint i;\n@@ -769,25 +774,24 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n static int read_populate_todo(struct commit_list **todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n+\tconst char *todo_file = get_todo_path(opts);\n \tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n-\tfd = open(git_path_todo_file(), O_RDONLY);\n+\tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"),\n-\t\t\t\t   git_path_todo_file());\n+\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n \tif (strbuf_read(&buf, fd, 0) < 0) {\n \t\tclose(fd);\n \t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not read %s.\"), git_path_todo_file());\n+\t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(buf.buf, todo_list, opts);\n \tstrbuf_release(&buf);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"),\n-\t\t\tgit_path_todo_file());\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n@@ -1075,7 +1079,7 @@ static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n \n-\tif (!file_exists(git_path_todo_file()))\n+\tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts) ||\n \t\t\tread_populate_todo(&todo_list, opts))\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304584","messageId":"c0d106125e1b6ba107b1ef06fb60dd710d184d29.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 08/27] sequencer: completely revamp the \"todo\" script parsing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:41Z","receivedAt":"2016-10-21T12:25:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"When we came up with the \"sequencer\" idea, we really wanted to have\nkind of a plumbing equivalent of the interactive rebase. Hence the\nchoice of words: the \"todo\" script, a \"pick\", etc.\n\nHowever, when it came time to implement the entire shebang, somehow this\nidea got lost and the sequencer was used as working horse for\ncherry-pick and revert instead. So as not to interfere with the\ninteractive rebase, it even uses a separate directory to store its\nstate.\n\nFurthermore, it also is stupidly strict about the \"todo\" script it\naccepts: while it parses commands in a way that was *designed* to be\nsimilar to the interactive rebase, it then goes on to *error out* if the\ncommands disagree with the overall action (cherry-pick or revert).\n\nFinally, the sequencer code chose to deviate from the interactive rebase\ncode insofar that when it comes to writing the file with the remaining\ncommands, it *reformats* the \"todo\" script instead of just writing the\npart of the parsed script that were not yet processed. This is not only\nunnecessary churn, but might well lose information that is valuable to\nthe user (i.e. comments after the commands).\n\nLet's just bite the bullet and rewrite the entire parser; the code now\nbecomes not only more elegant: it allows us to go on and teach the\nsequencer how to parse *true* \"todo\" scripts as used by the interactive\nrebase itself. In a way, the sequencer is about to grow up to do its\nolder brother's job. Better.\n\nIn particular, we choose to maintain the list of commands in an array\ninstead of a linked list: this is flexible enough to allow us later on to\neven implement rebase -i's reordering of fixup!/squash! commits very\neasily (and with a very nice speed bonus, at least on Windows).\n\nWhile at it, do not stop at the first problem, but list *all* of the\nproblems. This will help the user when the sequencer will do `rebase\n-i`'s work by allowing to address all issues in one go rather than going\nback and forth until the todo list is valid.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 284 ++++++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 163 insertions(+), 121 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 499f5ee..145de78 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -470,7 +470,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n \t\treturn 1;\n }\n \n-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n+enum todo_command {\n+\tTODO_PICK = 0,\n+\tTODO_REVERT\n+};\n+\n+static const char *todo_command_strings[] = {\n+\t\"pick\",\n+\t\"revert\"\n+};\n+\n+static const char *command_to_string(const enum todo_command command)\n+{\n+\tif (command < ARRAY_SIZE(todo_command_strings))\n+\t\treturn todo_command_strings[command];\n+\tdie(\"Unknown command: %d\", command);\n+}\n+\n+\n+static int do_pick_commit(enum todo_command command, struct commit *commit,\n+\t\tstruct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -529,10 +548,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\treturn fast_forward_to(commit->object.oid.hash, head, unborn, opts);\n \n \tif (parent && parse_commit(parent) < 0)\n-\t\t/* TRANSLATORS: The first %s will be \"revert\" or\n-\t\t   \"cherry-pick\", the second %s a SHA1 */\n+\t\t/* TRANSLATORS: The first %s will be a \"todo\" command like\n+\t\t   \"revert\" or \"pick\", the second %s a SHA1. */\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n-\t\t\taction_name(opts), oid_to_hex(&parent->object.oid));\n+\t\t\tcommand_to_string(command),\n+\t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n@@ -545,7 +565,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * reverse of it if we are revert.\n \t */\n \n-\tif (opts->action == REPLAY_REVERT) {\n+\tif (command == TODO_REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -586,7 +606,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\t}\n \t}\n \n-\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REPLAY_REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || command == TODO_REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n@@ -613,17 +633,17 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t * However, if the merge did not even start, then we don't want to\n \t * write it at all.\n \t */\n-\tif (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n+\tif (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&\n \t    update_ref(NULL, \"CHERRY_PICK_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n-\tif (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n+\tif (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&\n \t    update_ref(NULL, \"REVERT_HEAD\", commit->object.oid.hash, NULL,\n \t\t       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))\n \t\tres = -1;\n \n \tif (res) {\n-\t\terror(opts->action == REPLAY_REVERT\n+\t\terror(command == TODO_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n \t\t      short_commit_name(commit), msg.subject);\n@@ -684,116 +704,122 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,\n-\t\tstruct replay_opts *opts)\n+struct todo_item {\n+\tenum todo_command command;\n+\tstruct commit *commit;\n+\tsize_t offset_in_buf;\n+};\n+\n+struct todo_list {\n+\tstruct strbuf buf;\n+\tstruct todo_item *items;\n+\tint nr, alloc, current;\n+};\n+\n+#define TODO_LIST_INIT { STRBUF_INIT }\n+\n+static void todo_list_release(struct todo_list *todo_list)\n {\n-\tstruct commit_list *cur = NULL;\n-\tconst char *sha1_abbrev = NULL;\n-\tconst char *action_str = opts->action == REPLAY_REVERT ? \"revert\" : \"pick\";\n-\tconst char *subject;\n-\tint subject_len;\n+\tstrbuf_release(&todo_list->buf);\n+\tfree(todo_list->items);\n+\ttodo_list->items = NULL;\n+\ttodo_list->nr = todo_list->alloc = 0;\n+}\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tconst char *commit_buffer = get_commit_buffer(cur->item, NULL);\n-\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);\n-\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n-\t\tstrbuf_addf(buf, \"%s %s %.*s\\n\", action_str, sha1_abbrev,\n-\t\t\tsubject_len, subject);\n-\t\tunuse_commit_buffer(cur->item, commit_buffer);\n-\t}\n-\treturn 0;\n+static struct todo_item *append_new_todo(struct todo_list *todo_list)\n+{\n+\tALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);\n+\treturn todo_list->items + todo_list->nr++;\n }\n \n-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)\n+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n {\n \tunsigned char commit_sha1[20];\n-\tenum replay_action action;\n \tchar *end_of_object_name;\n-\tint saved, status, padding;\n-\n-\tif (starts_with(bol, \"pick\")) {\n-\t\taction = REPLAY_PICK;\n-\t\tbol += strlen(\"pick\");\n-\t} else if (starts_with(bol, \"revert\")) {\n-\t\taction = REPLAY_REVERT;\n-\t\tbol += strlen(\"revert\");\n-\t} else\n-\t\treturn NULL;\n+\tint i, saved, status, padding;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n+\t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n+\t\t\titem->command = i;\n+\t\t\tbreak;\n+\t\t}\n+\tif (i >= ARRAY_SIZE(todo_command_strings))\n+\t\treturn -1;\n \n \t/* Eat up extra spaces/ tabs before object name */\n \tpadding = strspn(bol, \" \\t\");\n \tif (!padding)\n-\t\treturn NULL;\n+\t\treturn -1;\n \tbol += padding;\n \n-\tend_of_object_name = bol + strcspn(bol, \" \\t\\n\");\n+\tend_of_object_name = (char *) bol + strcspn(bol, \" \\t\\n\");\n \tsaved = *end_of_object_name;\n \t*end_of_object_name = '\\0';\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n-\t/*\n-\t * Verify that the action matches up with the one in\n-\t * opts; we don't support arbitrary instructions\n-\t */\n-\tif (action != opts->action) {\n-\t\tif (action == REPLAY_REVERT)\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot revert during another revert.\")\n-\t\t\t    : _(\"Cannot revert during a cherry-pick.\"));\n-\t\telse\n-\t\t      error((opts->action == REPLAY_REVERT)\n-\t\t\t    ? _(\"Cannot cherry-pick during a revert.\")\n-\t\t\t    : _(\"Cannot cherry-pick during another cherry-pick.\"));\n-\t\treturn NULL;\n-\t}\n-\n \tif (status < 0)\n-\t\treturn NULL;\n+\t\treturn -1;\n \n-\treturn lookup_commit_reference(commit_sha1);\n+\titem->commit = lookup_commit_reference(commit_sha1);\n+\treturn !item->commit;\n }\n \n-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,\n-\t\t\tstruct replay_opts *opts)\n+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n {\n-\tstruct commit_list **next = todo_list;\n-\tstruct commit *commit;\n-\tchar *p = buf;\n-\tint i;\n+\tstruct todo_item *item;\n+\tchar *p = buf, *next_p;\n+\tint i, res = 0;\n \n-\tfor (i = 1; *p; i++) {\n+\tfor (i = 1; *p; i++, p = next_p) {\n \t\tchar *eol = strchrnul(p, '\\n');\n-\t\tcommit = parse_insn_line(p, eol, opts);\n-\t\tif (!commit)\n-\t\t\treturn error(_(\"Could not parse line %d.\"), i);\n-\t\tnext = commit_list_append(commit, next);\n-\t\tp = *eol ? eol + 1 : eol;\n+\n+\t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n+\n+\t\titem = append_new_todo(todo_list);\n+\t\titem->offset_in_buf = p - todo_list->buf.buf;\n+\t\tif (parse_insn_line(item, p, eol)) {\n+\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\t\ti, (int)(eol - p), p);\n+\t\t\titem->command = -1;\n+\t\t}\n \t}\n-\tif (!*todo_list)\n+\tif (!todo_list->nr)\n \t\treturn error(_(\"No commits parsed.\"));\n-\treturn 0;\n+\treturn res;\n }\n \n-static int read_populate_todo(struct commit_list **todo_list,\n+static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n \tconst char *todo_file = get_todo_path(opts);\n-\tstruct strbuf buf = STRBUF_INIT;\n \tint fd, res;\n \n+\tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n \t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n-\tif (strbuf_read(&buf, fd, 0) < 0) {\n+\tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\tstrbuf_release(&buf);\n \t\treturn error(_(\"Could not read %s.\"), todo_file);\n \t}\n \tclose(fd);\n \n-\tres = parse_insn_buffer(buf.buf, todo_list, opts);\n-\tstrbuf_release(&buf);\n+\tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n+\tif (!res) {\n+\t\tenum todo_command valid =\n+\t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < todo_list->nr; i++)\n+\t\t\tif (valid == todo_list->items[i].command)\n+\t\t\t\tcontinue;\n+\t\t\telse if (valid == TODO_PICK)\n+\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\telse\n+\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t}\n+\n \tif (res)\n \t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n@@ -860,18 +886,31 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n-static int walk_revs_populate_todo(struct commit_list **todo_list,\n+static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n+\tenum todo_command command = opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT;\n+\tconst char *command_string = todo_command_strings[command];\n \tstruct commit *commit;\n-\tstruct commit_list **next;\n \n \tif (prepare_revs(opts))\n \t\treturn -1;\n \n-\tnext = todo_list;\n-\twhile ((commit = get_revision(opts->revs)))\n-\t\tnext = commit_list_append(commit, next);\n+\twhile ((commit = get_revision(opts->revs))) {\n+\t\tstruct todo_item *item = append_new_todo(todo_list);\n+\t\tconst char *commit_buffer = get_commit_buffer(commit, NULL);\n+\t\tconst char *subject;\n+\t\tint subject_len;\n+\n+\t\titem->command = command;\n+\t\titem->commit = commit;\n+\t\titem->offset_in_buf = todo_list->buf.len;\n+\t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n+\t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n+\t\t\tshort_commit_name(commit), subject_len, subject);\n+\t\tunuse_commit_buffer(commit, commit_buffer);\n+\t}\n \treturn 0;\n }\n \n@@ -979,30 +1018,22 @@ static int sequencer_rollback(struct replay_opts *opts)\n \treturn -1;\n }\n \n-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstatic struct lock_file todo_lock;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tint fd;\n+\tconst char *todo_path = get_todo_path(opts);\n+\tint next = todo_list->current, offset, fd;\n \n-\tfd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);\n+\tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"),\n-\t\t\t\t   git_path_todo_file());\n-\tif (format_todo(&buf, todo_list, opts) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Could not format %s.\"), git_path_todo_file());\n-\t}\n-\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n-\t\t\t\t   git_path_todo_file());\n-\t}\n-\tif (commit_lock_file(&todo_lock) < 0) {\n-\t\tstrbuf_release(&buf);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_todo_file());\n-\t}\n-\tstrbuf_release(&buf);\n+\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\toffset = next < todo_list->nr ?\n+\t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n+\tif (write_in_full(fd, todo_list->buf.buf + offset,\n+\t\t\ttodo_list->buf.len - offset) < 0)\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\tif (commit_lock_file(&todo_lock) < 0)\n+\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1041,9 +1072,8 @@ static int save_opts(struct replay_opts *opts)\n \treturn res;\n }\n \n-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *cur;\n \tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n@@ -1053,10 +1083,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\tfor (cur = todo_list; cur; cur = cur->next) {\n-\t\tif (save_todo(cur, opts))\n+\twhile (todo_list->current < todo_list->nr) {\n+\t\tstruct todo_item *item = todo_list->items + todo_list->current;\n+\t\tif (save_todo(todo_list, opts))\n \t\t\treturn -1;\n-\t\tres = do_pick_commit(cur->item, opts);\n+\t\tres = do_pick_commit(item->command, item->commit, opts);\n+\t\ttodo_list->current++;\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -1081,38 +1113,46 @@ static int continue_single_pick(void)\n \n static int sequencer_continue(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n \n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n-\tif (read_populate_opts(opts) ||\n-\t\t\tread_populate_todo(&todo_list, opts))\n+\tif (read_populate_opts(opts))\n \t\treturn -1;\n+\tif ((res = read_populate_todo(&todo_list, opts)))\n+\t\tgoto release_todo_list;\n \n \t/* Verify that the conflict has been resolved */\n \tif (file_exists(git_path_cherry_pick_head()) ||\n \t    file_exists(git_path_revert_head())) {\n-\t\tint ret = continue_single_pick();\n-\t\tif (ret)\n-\t\t\treturn ret;\n+\t\tres = continue_single_pick();\n+\t\tif (res)\n+\t\t\tgoto release_todo_list;\n \t}\n-\tif (index_differs_from(\"HEAD\", 0))\n-\t\treturn error_dirty_index(opts);\n-\ttodo_list = todo_list->next;\n-\treturn pick_commits(todo_list, opts);\n+\tif (index_differs_from(\"HEAD\", 0)) {\n+\t\tres = error_dirty_index(opts);\n+\t\tgoto release_todo_list;\n+\t}\n+\ttodo_list.current++;\n+\tres = pick_commits(&todo_list, opts);\n+release_todo_list:\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n static int single_pick(struct commit *cmit, struct replay_opts *opts)\n {\n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(cmit, opts);\n+\treturn do_pick_commit(opts->action == REPLAY_PICK ?\n+\t\tTODO_PICK : TODO_REVERT, cmit, opts);\n }\n \n int sequencer_pick_revisions(struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n \tunsigned char sha1[20];\n-\tint i;\n+\tint i, res;\n \n \tif (opts->subcommand == REPLAY_NONE)\n \t\tassert(opts->revs);\n@@ -1187,7 +1227,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\treturn -1;\n \tif (save_opts(opts))\n \t\treturn -1;\n-\treturn pick_commits(todo_list, opts);\n+\tres = pick_commits(&todo_list, opts);\n+\ttodo_list_release(&todo_list);\n+\treturn res;\n }\n \n void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304585","messageId":"090369749f8bc0a45c94198cd20fa0da5d0afddf.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 09/27] sequencer: strip CR from the todo script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:46Z","receivedAt":"2016-10-21T12:25:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"It is not unheard of that editors on Windows write CR/LF even if the\nfile originally had only LF. This is particularly awkward for exec lines\nof a rebase -i todo sheet. Take for example the insn \"exec echo\": The\nshell script parser splits at the LF and leaves the CR attached to\n\"echo\", which leads to the unknown command \"echo\\r\".\n\nWork around that by stripping CR when reading the todo commands, as we\nalready do for LF.\n\nThis happens to fix t9903.14 and .15 in MSYS1 environments (with the\nrebase--helper patches based on this patch series): the todo script\nconstructed in such a setup contains CR/LF thanks to MSYS1 runtime's\ncleverness.\n\nBased on a report and a patch by Johannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 145de78..04fcfd8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -776,6 +776,9 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \n \t\tnext_p = *eol ? eol + 1 /* skip LF */ : eol;\n \n+\t\tif (p != eol && eol[-1] == '\\r')\n+\t\t\teol--; /* strip Carriage Return */\n+\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304586","messageId":"79f2fb5e2de8158db6516f4e9c8eb0f5cce6ddb6.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 07/27] sequencer: refactor the code to obtain a short commit name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:37Z","receivedAt":"2016-10-21T12:25:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Not only does this DRY up the code (providing a better documentation what\nthe code is about, as well as allowing to change the behavior in a single\nplace), it also makes it substantially shorter to use the same\nfunctionality in functions to be introduced when we teach the sequencer to\nprocess interactive-rebase's git-rebase-todo file.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex fb0b94b..499f5ee 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -147,13 +147,18 @@ struct commit_message {\n \tconst char *message;\n };\n \n+static const char *short_commit_name(struct commit *commit)\n+{\n+\treturn find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+}\n+\n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n \tint subject_len;\n \n \tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n-\tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n+\tabbrev = short_commit_name(commit);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n@@ -621,8 +626,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\terror(opts->action == REPLAY_REVERT\n \t\t      ? _(\"could not revert %s... %s\")\n \t\t      : _(\"could not apply %s... %s\"),\n-\t\t      find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),\n-\t\t      msg.subject);\n+\t\t      short_commit_name(commit), msg.subject);\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t\tgoto leave;\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304587","messageId":"b83fef6d57a766f2d27f86efb8ce1f088ab51ebe.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 11/27] sequencer: get rid of the subcommand field","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:55Z","receivedAt":"2016-10-21T12:25:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The subcommands are used exactly once, at the very beginning of\nsequencer_pick_revisions(), to determine what to do. This is an\nunnecessary level of indirection: we can simply call the correct\nfunction to begin with. So let's do that.\n\nWhile at it, ensure that the subcommands return an error code so that\nthey do not have to die() all over the place (bad practice for library\nfunctions...).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/revert.c | 36 ++++++++++++++++--------------------\n sequencer.c      | 35 +++++++++++------------------------\n sequencer.h      | 13 ++++---------\n 3 files changed, 31 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex ba5a88c..4ca5b51 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -71,7 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \t\tdie(_(\"%s: %s cannot be used with %s\"), me, this_opt, base_opt);\n }\n \n-static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n+static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tconst char *me = action_name(opts);\n@@ -115,25 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n-\t/* Set the subcommand */\n-\tif (cmd == 'q')\n-\t\topts->subcommand = REPLAY_REMOVE_STATE;\n-\telse if (cmd == 'c')\n-\t\topts->subcommand = REPLAY_CONTINUE;\n-\telse if (cmd == 'a')\n-\t\topts->subcommand = REPLAY_ROLLBACK;\n-\telse\n-\t\topts->subcommand = REPLAY_NONE;\n-\n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\tchar *this_operation;\n-\t\tif (opts->subcommand == REPLAY_REMOVE_STATE)\n+\t\tif (cmd == 'q')\n \t\t\tthis_operation = \"--quit\";\n-\t\telse if (opts->subcommand == REPLAY_CONTINUE)\n+\t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n \t\telse {\n-\t\t\tassert(opts->subcommand == REPLAY_ROLLBACK);\n+\t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n \t\t}\n \n@@ -156,7 +146,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--edit\", opts->edit,\n \t\t\t\tNULL);\n \n-\tif (opts->subcommand != REPLAY_NONE) {\n+\tif (cmd) {\n \t\topts->revs = NULL;\n \t} else {\n \t\tstruct setup_revision_opt s_r_opt;\n@@ -178,6 +168,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t/* These option values will be free()d */\n \topts->gpg_sign = xstrdup_or_null(opts->gpg_sign);\n \topts->strategy = xstrdup_or_null(opts->strategy);\n+\n+\tif (cmd == 'q')\n+\t\treturn sequencer_remove_state(opts);\n+\tif (cmd == 'c')\n+\t\treturn sequencer_continue(opts);\n+\tif (cmd == 'a')\n+\t\treturn sequencer_rollback(opts);\n+\treturn sequencer_pick_revisions(opts);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n@@ -189,8 +187,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\topts.edit = 1;\n \topts.action = REPLAY_REVERT;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -203,8 +200,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \topts.action = REPLAY_PICK;\n \tgit_config(git_default_config, NULL);\n-\tparse_args(argc, argv, &opts);\n-\tres = sequencer_pick_revisions(&opts);\n+\tres = run_sequencer(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\ndiff --git a/sequencer.c b/sequencer.c\nindex 120a8ee..9f22c5e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -119,7 +119,7 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n-static void remove_sequencer_state(const struct replay_opts *opts)\n+int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tint i;\n@@ -133,6 +133,8 @@ static void remove_sequencer_state(const struct replay_opts *opts)\n \tstrbuf_addf(&dir, \"%s\", get_dir(opts));\n \tremove_dir_recursively(&dir, 0);\n \tstrbuf_release(&dir);\n+\n+\treturn 0;\n }\n \n static const char *action_name(const struct replay_opts *opts)\n@@ -975,7 +977,7 @@ static int rollback_single_pick(void)\n \treturn reset_for_rollback(head_sha1);\n }\n \n-static int sequencer_rollback(struct replay_opts *opts)\n+int sequencer_rollback(struct replay_opts *opts)\n {\n \tFILE *f;\n \tunsigned char sha1[20];\n@@ -1010,9 +1012,8 @@ static int sequencer_rollback(struct replay_opts *opts)\n \t}\n \tif (reset_for_rollback(sha1))\n \t\tgoto fail;\n-\tremove_sequencer_state(opts);\n \tstrbuf_release(&buf);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n fail:\n \tstrbuf_release(&buf);\n \treturn -1;\n@@ -1097,8 +1098,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t * Sequence of picks finished successfully; cleanup by\n \t * removing the .git/sequencer directory\n \t */\n-\tremove_sequencer_state(opts);\n-\treturn 0;\n+\treturn sequencer_remove_state(opts);\n }\n \n static int continue_single_pick(void)\n@@ -1111,11 +1111,14 @@ static int continue_single_pick(void)\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n \n-static int sequencer_continue(struct replay_opts *opts)\n+int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tint res;\n \n+\tif (read_and_refresh_cache(opts))\n+\t\treturn -1;\n+\n \tif (!file_exists(get_todo_path(opts)))\n \t\treturn continue_single_pick();\n \tif (read_populate_opts(opts))\n@@ -1154,26 +1157,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \tunsigned char sha1[20];\n \tint i, res;\n \n-\tif (opts->subcommand == REPLAY_NONE)\n-\t\tassert(opts->revs);\n-\n+\tassert(opts->revs);\n \tif (read_and_refresh_cache(opts))\n \t\treturn -1;\n \n-\t/*\n-\t * Decide what to do depending on the arguments; a fresh\n-\t * cherry-pick should be handled differently from an existing\n-\t * one that is being continued\n-\t */\n-\tif (opts->subcommand == REPLAY_REMOVE_STATE) {\n-\t\tremove_sequencer_state(opts);\n-\t\treturn 0;\n-\t}\n-\tif (opts->subcommand == REPLAY_ROLLBACK)\n-\t\treturn sequencer_rollback(opts);\n-\tif (opts->subcommand == REPLAY_CONTINUE)\n-\t\treturn sequencer_continue(opts);\n-\n \tfor (i = 0; i < opts->revs->pending.nr; i++) {\n \t\tunsigned char sha1[20];\n \t\tconst char *name = opts->revs->pending.objects[i].name;\ndiff --git a/sequencer.h b/sequencer.h\nindex 8453669..7a513c5 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -10,16 +10,8 @@ enum replay_action {\n \tREPLAY_PICK\n };\n \n-enum replay_subcommand {\n-\tREPLAY_NONE,\n-\tREPLAY_REMOVE_STATE,\n-\tREPLAY_CONTINUE,\n-\tREPLAY_ROLLBACK\n-};\n-\n struct replay_opts {\n \tenum replay_action action;\n-\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -44,9 +36,12 @@ struct replay_opts {\n \t/* Only used by REPLAY_NONE */\n \tstruct rev_info *revs;\n };\n-#define REPLAY_OPTS_INIT { -1, -1 }\n+#define REPLAY_OPTS_INIT { -1 }\n \n int sequencer_pick_revisions(struct replay_opts *opts);\n+int sequencer_continue(struct replay_opts *opts);\n+int sequencer_rollback(struct replay_opts *opts);\n+int sequencer_remove_state(struct replay_opts *opts);\n \n extern const char sign_off_header[];\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304588","messageId":"f04cdced2060e8c813db0de513856206a72cb921.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 12/27] sequencer: remember the onelines when parsing the todo file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:00Z","receivedAt":"2016-10-21T12:25:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The `git-rebase-todo` file contains a list of commands. Most of those\ncommands have the form\n\n\t<verb> <sha1> <oneline>\n\nThe <oneline> is displayed primarily for the user's convenience, as\nrebase -i really interprets only the <verb> <sha1> part. However, there\nare *some* places in interactive rebase where the <oneline> is used to\ndisplay messages, e.g. for reporting at which commit we stopped.\n\nSo let's just remember it when parsing the todo file; we keep a copy of\nthe entire todo file anyway (to write out the new `done` and\n`git-rebase-todo` file just before processing each command), so all we\nneed to do is remember the begin offsets and lengths.\n\nAs we will have to parse and remember the command-line for `exec` commands\nlater, we do not call the field \"oneline\" but rather \"arg\" (and will reuse\nthat for exec's command-line).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 9f22c5e..3d1fdac 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -706,6 +706,8 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n struct todo_item {\n \tenum todo_command command;\n \tstruct commit *commit;\n+\tconst char *arg;\n+\tint arg_len;\n \tsize_t offset_in_buf;\n };\n \n@@ -757,6 +759,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tstatus = get_sha1(bol, commit_sha1);\n \t*end_of_object_name = saved;\n \n+\titem->arg = end_of_object_name + strspn(end_of_object_name, \" \\t\");\n+\titem->arg_len = (int)(eol - item->arg);\n+\n \tif (status < 0)\n \t\treturn -1;\n \n@@ -907,6 +912,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \n \t\titem->command = command;\n \t\titem->commit = commit;\n+\t\titem->arg = NULL;\n+\t\titem->arg_len = 0;\n \t\titem->offset_in_buf = todo_list->buf.len;\n \t\tsubject_len = find_commit_subject(commit_buffer, &subject);\n \t\tstrbuf_addf(&todo_list->buf, \"%s %s %.*s\\n\", command_string,\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304589","messageId":"7020e27fab4f8d190dec2ab4cbb7e6483161dffc.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 13/27] sequencer: prepare for rebase -i's commit functionality","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:04Z","receivedAt":"2016-10-21T12:25:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In interactive rebases, we commit a little bit differently than the\nsequencer did so far: we heed the \"author-script\", the \"message\" and the\n\"amend\" files in the .git/rebase-merge/ subdirectory.\n\nLikewise, we may want to edit the commit message *even* when providing a\nfile containing the suggested commit message. Therefore we change the\ncode to not even provide a default message when we do not want any, and\nto call the editor explicitly.\n\nAlso, in \"interactive rebase\" mode we want to skip reading the options\nin the state directory of the cherry-pick/revert commands.\n\nFinally, as interactive rebase's GPG settings are configured differently\nfrom how cherry-pick (and therefore sequencer) handles them, we will\nleave support for that to the next commit.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 89 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 3d1fdac..6d5fe94 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -27,6 +27,19 @@ static GIT_PATH_FUNC(git_path_todo_file, \"sequencer/todo\")\n static GIT_PATH_FUNC(git_path_opts_file, \"sequencer/opts\")\n static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n \n+/*\n+ * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n+ * GIT_AUTHOR_DATE that will be used for the commit that is currently\n+ * being rebased.\n+ */\n+static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+\n+/* We will introduce the 'interactive rebase' mode later */\n+static inline int is_rebase_i(const struct replay_opts *opts)\n+{\n+\treturn 0;\n+}\n+\n static const char *get_dir(const struct replay_opts *opts)\n {\n \treturn git_path_seq_dir();\n@@ -370,19 +383,79 @@ static int is_index_unchanged(void)\n }\n \n /*\n+ * Read the author-script file into an environment block, ready for use in\n+ * run_command(), that can be free()d afterwards.\n+ */\n+static char **read_author_script(void)\n+{\n+\tstruct strbuf script = STRBUF_INIT;\n+\tint i, count = 0;\n+\tchar *p, *p2, **env;\n+\tsize_t env_size;\n+\n+\tif (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)\n+\t\treturn NULL;\n+\n+\tfor (p = script.buf; *p; p++)\n+\t\tif (skip_prefix(p, \"'\\\\\\\\''\", (const char **)&p2))\n+\t\t\tstrbuf_splice(&script, p - script.buf, p2 - p, \"'\", 1);\n+\t\telse if (*p == '\\'')\n+\t\t\tstrbuf_splice(&script, p-- - script.buf, 1, \"\", 0);\n+\t\telse if (*p == '\\n') {\n+\t\t\t*p = '\\0';\n+\t\t\tcount++;\n+\t\t}\n+\n+\tenv_size = (count + 1) * sizeof(*env);\n+\tstrbuf_grow(&script, env_size);\n+\tmemmove(script.buf + env_size, script.buf, script.len);\n+\tp = script.buf + env_size;\n+\tenv = (char **)strbuf_detach(&script, NULL);\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tenv[i] = p;\n+\t\tp += strlen(p) + 1;\n+\t}\n+\tenv[count] = NULL;\n+\n+\treturn env;\n+}\n+\n+/*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n  * author date and name.\n+ *\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n+ *\n+ * An exception is when run_git_commit() is called during an\n+ * interactive rebase: in that case, we will want to retain the\n+ * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\t\t  int allow_empty)\n {\n+\tchar **env = NULL;\n \tstruct argv_array array;\n \tint rc;\n \tconst char *value;\n \n+\tif (is_rebase_i(opts)) {\n+\t\tenv = read_author_script();\n+\t\tif (!env)\n+\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\t\t\"tree. If these changes are meant to be\\n\"\n+\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n+\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"If they are meant to go into a new commit, \"\n+\t\t\t\t\"run:\\n\\n\"\n+\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"In both cases, once you're done, continue \"\n+\t\t\t\t\"with:\\n\\n\"\n+\t\t\t\t\"  git rebase --continue\\n\");\n+\t}\n+\n \targv_array_init(&array);\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n@@ -391,14 +464,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n \t\targv_array_push(&array, \"-s\");\n-\tif (!opts->edit) {\n-\t\targv_array_push(&array, \"-F\");\n-\t\targv_array_push(&array, defmsg);\n-\t\tif (!opts->signoff &&\n-\t\t    !opts->record_origin &&\n-\t\t    git_config_get_value(\"commit.cleanup\", &value))\n-\t\t\targv_array_push(&array, \"--cleanup=verbatim\");\n-\t}\n+\tif (defmsg)\n+\t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (opts->edit)\n+\t\targv_array_push(&array, \"-e\");\n+\telse if (!opts->signoff && !opts->record_origin &&\n+\t\t git_config_get_value(\"commit.cleanup\", &value))\n+\t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n \tif (allow_empty)\n \t\targv_array_push(&array, \"--allow-empty\");\n@@ -406,8 +478,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&array, \"--allow-empty-message\");\n \n-\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\trc = run_command_v_opt_cd_env(array.argv, RUN_GIT_CMD, NULL,\n+\t\t\t(const char *const *)env);\n \targv_array_clear(&array);\n+\tfree(env);\n+\n \treturn rc;\n }\n \n@@ -657,7 +732,8 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tgoto leave;\n \t}\n \tif (!opts->no_commit)\n-\t\tres = run_git_commit(git_path_merge_msg(), opts, allow);\n+\t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n+\t\t\t\t     opts, allow);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -879,6 +955,9 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n+\tif (is_rebase_i(opts))\n+\t\treturn 0;\n+\n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n \t/*\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304590","messageId":"72139cb119aaf28454b141572f5cb46843f5f3e9.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 10/27] sequencer: avoid completely different messages for different actions","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:24:50Z","receivedAt":"2016-10-21T12:25:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 04fcfd8..120a8ee 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -229,11 +229,8 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(action_name(opts));\n \n-\t/* Different translation strings for cherry-pick and revert */\n-\tif (opts->action == REPLAY_PICK)\n-\t\terror(_(\"Your local changes would be overwritten by cherry-pick.\"));\n-\telse\n-\t\terror(_(\"Your local changes would be overwritten by revert.\"));\n+\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\t\taction_name(opts));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304591","messageId":"0ffa14bdac0c6be9ccc4cf3852e3b8a1a0c828b2.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 15/27] sequencer: allow editing the commit message on a case-by-case basis","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:12Z","receivedAt":"2016-10-21T12:25:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In the upcoming commits, we will implement more and more of rebase -i's\nfunctionality inside the sequencer. One particular feature of the\ncommands to come is that some of them allow editing the commit message\nwhile others don't, i.e. we cannot define in the replay_opts whether the\ncommit message should be edited or not.\n\nLet's add a new parameter to the run_git_commit() function. Previously,\nit was the duty of the caller to ensure that the opts->edit setting\nindicates whether to let the user edit the commit message or not,\nindicating that it is an \"all or nothing\" setting, i.e. that the\nsequencer wants to let the user edit *all* commit message, or none at\nall. In the upcoming rebase -i mode, it will depend on the particular\ncommand that is currently executed, though.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 48 ++++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 40 insertions(+), 8 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 282c4d1..c0a0aa0 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -15,6 +15,7 @@\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n #include \"argv-array.h\"\n+#include \"quote.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -33,6 +34,11 @@ static GIT_PATH_FUNC(git_path_head_file, \"sequencer/head\")\n  * being rebased.\n  */\n static GIT_PATH_FUNC(rebase_path_author_script, \"rebase-merge/author-script\")\n+/*\n+ * The following files are written by git-rebase just after parsing the\n+ * command-line (and are only consumed, not modified, by the sequencer).\n+ */\n+static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n \n /* We will introduce the 'interactive rebase' mode later */\n static inline int is_rebase_i(const struct replay_opts *opts)\n@@ -132,6 +138,16 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,\n \treturn 1;\n }\n \n+static const char *gpg_sign_opt_quoted(struct replay_opts *opts)\n+{\n+\tstatic struct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_reset(&buf);\n+\tif (opts->gpg_sign)\n+\t\tsq_quotef(&buf, \"-S%s\", opts->gpg_sign);\n+\treturn buf.buf;\n+}\n+\n int sequencer_remove_state(struct replay_opts *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n@@ -468,7 +484,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty)\n+\t\t\t  int allow_empty, int edit)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -477,17 +493,20 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tif (is_rebase_i(opts)) {\n \t\tenv = read_author_script();\n-\t\tif (!env)\n+\t\tif (!env) {\n+\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\n \t\t\treturn error(\"You have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit --amend %s\\n\\n\"\n \t\t\t\t\"If they are meant to go into a new commit, \"\n \t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit $gpg_sign_opt_quoted\\n\\n\"\n+\t\t\t\t\"  git commit %s\\n\\n\"\n \t\t\t\t\"In both cases, once you're done, continue \"\n \t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\");\n+\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t}\n \t}\n \n \targv_array_init(&array);\n@@ -500,7 +519,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n-\tif (opts->edit)\n+\tif (edit)\n \t\targv_array_push(&array, \"-e\");\n \telse if (!opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n@@ -767,7 +786,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow);\n+\t\t\t\t     opts, allow, opts->edit);\n \n leave:\n \tfree_message(commit, &msg);\n@@ -989,8 +1008,21 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \n static int read_populate_opts(struct replay_opts *opts)\n {\n-\tif (is_rebase_i(opts))\n+\tif (is_rebase_i(opts)) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (read_oneliner(&buf, rebase_path_gpg_sign_opt(), 1)) {\n+\t\t\tif (!starts_with(buf.buf, \"-S\"))\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\telse {\n+\t\t\t\tfree(opts->gpg_sign);\n+\t\t\t\topts->gpg_sign = xstrdup(buf.buf + 2);\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\n \t\treturn 0;\n+\t}\n \n \tif (!file_exists(git_path_opts_file()))\n \t\treturn 0;\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304592","messageId":"33b991f51d58ca092b972259d80bf11bacfd843d.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 14/27] sequencer: introduce a helper to read files written by scripts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:08Z","receivedAt":"2016-10-21T12:25:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As we are slowly teaching the sequencer to perform the hard work for\nthe interactive rebase, we need to read files that were written by\nshell scripts.\n\nThese files typically contain a single line and are invariably ended\nby a line feed (and possibly a carriage return before that). Let's use\na helper to read such files and to remove the line ending.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 6d5fe94..282c4d1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,6 +234,40 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \treturn 0;\n }\n \n+/*\n+ * Reads a file that was presumably written by a shell script, i.e. with an\n+ * end-of-line marker that needs to be stripped.\n+ *\n+ * Note that only the last end-of-line marker is stripped, consistent with the\n+ * behavior of \"$(cat path)\" in a shell script.\n+ *\n+ * Returns 1 if the file was read, 0 if it could not be read or does not exist.\n+ */\n+static int read_oneliner(struct strbuf *buf,\n+\tconst char *path, int skip_if_empty)\n+{\n+\tint orig_len = buf->len;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (strbuf_read_file(buf, path, 0) < 0) {\n+\t\twarning_errno(_(\"could not read '%s'\"), path);\n+\t\treturn 0;\n+\t}\n+\n+\tif (buf->len > orig_len && buf->buf[buf->len - 1] == '\\n') {\n+\t\tif (--buf->len > orig_len && buf->buf[buf->len - 1] == '\\r')\n+\t\t\t--buf->len;\n+\t\tbuf->buf[buf->len] = '\\0';\n+\t}\n+\n+\tif (skip_if_empty && buf->len == orig_len)\n+\t\treturn 0;\n+\n+\treturn 1;\n+}\n+\n static struct tree *empty_tree(void)\n {\n \treturn lookup_tree(EMPTY_TREE_SHA1_BIN);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304593","messageId":"6df19ad36240580e8717d4adafaf7b6e039fe2d6.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 16/27] sequencer: support amending commits","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:17Z","receivedAt":"2016-10-21T12:25:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This teaches the run_git_commit() function to take an argument that will\nallow us to implement \"todo\" commands that need to amend the commit\nmessages (\"fixup\", \"squash\" and \"reword\").\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c0a0aa0..1ef50a0 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -484,7 +484,7 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit)\n+\t\t\t  int allow_empty, int edit, int amend)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -513,6 +513,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \targv_array_push(&array, \"commit\");\n \targv_array_push(&array, \"-n\");\n \n+\tif (amend)\n+\t\targv_array_push(&array, \"--amend\");\n \tif (opts->gpg_sign)\n \t\targv_array_pushf(&array, \"-S%s\", opts->gpg_sign);\n \tif (opts->signoff)\n@@ -786,7 +788,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit);\n+\t\t\t\t     opts, allow, opts->edit, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304594","messageId":"8417e4f871cad36e558feaaea79c76f7b9d1ff18.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 17/27] sequencer: support cleaning up commit messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:28Z","receivedAt":"2016-10-21T12:25:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The run_git_commit() function already knows how to amend commits, and\nwith this new option, it can also clean up commit messages (i.e. strip\nout commented lines). This is needed to implement rebase -i's 'fixup'\nand 'squash' commands as sequencer commands.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 1ef50a0..8646ca5 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -484,7 +484,8 @@ static char **read_author_script(void)\n  * author metadata.\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n-\t\t\t  int allow_empty, int edit, int amend)\n+\t\t\t  int allow_empty, int edit, int amend,\n+\t\t\t  int cleanup_commit_message)\n {\n \tchar **env = NULL;\n \tstruct argv_array array;\n@@ -521,9 +522,12 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\targv_array_push(&array, \"-s\");\n \tif (defmsg)\n \t\targv_array_pushl(&array, \"-F\", defmsg, NULL);\n+\tif (cleanup_commit_message)\n+\t\targv_array_push(&array, \"--cleanup=strip\");\n \tif (edit)\n \t\targv_array_push(&array, \"-e\");\n-\telse if (!opts->signoff && !opts->record_origin &&\n+\telse if (!cleanup_commit_message &&\n+\t\t !opts->signoff && !opts->record_origin &&\n \t\t git_config_get_value(\"commit.cleanup\", &value))\n \t\targv_array_push(&array, \"--cleanup=verbatim\");\n \n@@ -788,7 +792,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t}\n \tif (!opts->no_commit)\n \t\tres = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),\n-\t\t\t\t     opts, allow, opts->edit, 0);\n+\t\t\t\t     opts, allow, opts->edit, 0, 0);\n \n leave:\n \tfree_message(commit, &msg);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304595","messageId":"a63b65b1191a5147d0924d72759bf355b0a91323.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 18/27] sequencer: left-trim lines read from the script","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:36Z","receivedAt":"2016-10-21T12:26:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Interactive rebase's scripts may be indented; we need to handle this\ncase, too, now that we prepare the sequencer to process interactive\nrebases.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8646ca5..d74fdce 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -874,6 +874,9 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)\n \tchar *end_of_object_name;\n \tint i, saved, status, padding;\n \n+\t/* left-trim */\n+\tbol += strspn(bol, \" \\t\");\n+\n \tfor (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)\n \t\tif (skip_prefix(bol, todo_command_strings[i], &bol)) {\n \t\t\titem->command = i;\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304596","messageId":"f4df322de90cfa5cb399ba6f471e33b27e09f4d7.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 21/27] sequencer: refactor write_message() to take a pointer/length","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:05Z","receivedAt":"2016-10-21T12:26:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we required an strbuf. But that limits the use case too much.\nIn the upcoming patch series (for which the current patch series prepares\nthe sequencer), we will want to write content to a file for which we have\na pointer and a length, not an strbuf.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 ++++++----\n 1 file changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 9fced42..300952f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,14 +234,14 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(struct strbuf *msgbuf, const char *filename)\n+static int write_message(const void *buf, size_t len, const char *filename)\n {\n \tstatic struct lock_file msg_file;\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0) {\n+\tif (write_in_full(msg_fd, buf, len) < 0) {\n \t\trollback_lock_file(&msg_file);\n \t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n \t}\n@@ -747,12 +747,14 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t\t\t\t head, &msgbuf, opts);\n \t\tif (res < 0)\n \t\t\treturn res;\n-\t\tres |= write_message(&msgbuf, git_path_merge_msg());\n+\t\tres |= write_message(msgbuf.buf, msgbuf.len,\n+\t\t\t\t     git_path_merge_msg());\n \t} else {\n \t\tstruct commit_list *common = NULL;\n \t\tstruct commit_list *remotes = NULL;\n \n-\t\tres = write_message(&msgbuf, git_path_merge_msg());\n+\t\tres = write_message(msgbuf.buf, msgbuf.len,\n+\t\t\t\t    git_path_merge_msg());\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304597","messageId":"c89508366501c17e7363a7d5c631fce9b3750cd2.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 19/27] sequencer: stop releasing the strbuf in write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:25:41Z","receivedAt":"2016-10-21T12:26:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Nothing in the name \"write_message()\" suggests that the function\nreleases the strbuf passed to it. So let's release the strbuf in the\ncaller instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex d74fdce..745c86f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -243,7 +243,6 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n \tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n \t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tstrbuf_release(msgbuf);\n \tif (commit_lock_file(&msg_file) < 0)\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n \n@@ -759,6 +758,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tfree_commit_list(common);\n \t\tfree_commit_list(remotes);\n \t}\n+\tstrbuf_release(&msgbuf);\n \n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304598","messageId":"cf906a605dbd2f1c5ffe06877b1fa4602ff4a1f5.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 23/27] sequencer: remove overzealous assumption in rebase -i mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:13Z","receivedAt":"2016-10-21T12:26:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The sequencer was introduced to make the cherry-pick and revert\nfunctionality available as library function, with the original idea\nbeing to extend the sequencer to also implement the rebase -i\nfunctionality.\n\nThe test to ensure that all of the commands in the script are identical\nto the overall operation does not mesh well with that.\n\nTherefore let's disable the test in rebase -i mode.\n\nWhile at it, error out early if the \"instruction sheet\" (i.e. the todo\nscript) could not be parsed.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 000ce3e..bd11db4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -962,7 +962,10 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n-\tif (!res) {\n+\tif (res)\n+\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\n+\tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n \t\t\topts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;\n \t\tint i;\n@@ -976,8 +979,6 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n \t}\n \n-\tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n \treturn 0;\n }\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304599","messageId":"8490f9cf3c6ff6b453064175e5fe8cfecadb9600.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 25/27] sequencer: quote filenames in error messages","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:21Z","receivedAt":"2016-10-21T12:26:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This makes the code consistent by fixing quite a couple of error messages.\n\nSuggested by Jakub Narębski.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ff76b6f..340d0ed 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -252,7 +252,7 @@ static int write_message(const void *buf, size_t len, const char *filename,\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -954,16 +954,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open %s\"), todo_file);\n+\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read %s.\"), todo_file);\n+\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: %s\"), todo_file);\n+\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -1054,7 +1054,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: %s\"),\n+\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1097,7 +1097,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory %s\"),\n+\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1116,12 +1116,12 @@ static int save_head(const char *head)\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to %s\"),\n+\t\treturn error_errno(_(\"Could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up %s.\"), git_path_head_file());\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1166,9 +1166,9 @@ int sequencer_rollback(struct replay_opts *opts)\n \t\treturn rollback_single_pick();\n \t}\n \tif (!f)\n-\t\treturn error_errno(_(\"cannot open %s\"), git_path_head_file());\n+\t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n \tif (strbuf_getline_lf(&buf, f)) {\n-\t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n+\t\terror(_(\"cannot read '%s': %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\n \t\tgoto fail;\n@@ -1207,7 +1207,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t\ttodo_list->buf.len - offset) < 0)\n \t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up %s.\"), todo_path);\n+\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n \treturn 0;\n }\n \n-- \n2.10.1.583.g721a9e0\n\n"},{"id":"304600","messageId":"d858bd99a3ad3dea807f38b8bd42a221a9f7924c.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 22/27] sequencer: teach write_message() to append an optional LF","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:09Z","receivedAt":"2016-10-21T12:26:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This commit prepares for future callers that will have a pointer/length\nto some text to be written that lacks an LF, yet an LF is desired.\nInstead of requiring the caller to append an LF to the buffer (and\npotentially allocate memory to do so), the write_message() function\nlearns to append an LF at the end of the file.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 300952f..000ce3e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -234,7 +234,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(const void *buf, size_t len, const char *filename)\n+static int write_message(const void *buf, size_t len, const char *filename,\n+\t\t\t int append_eol)\n {\n \tstatic struct lock_file msg_file;\n \n@@ -245,6 +246,10 @@ static int write_message(const void *buf, size_t len, const char *filename)\n \t\trollback_lock_file(&msg_file);\n \t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n \t}\n+\tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n@@ -748,13 +753,13 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tif (res < 0)\n \t\t\treturn res;\n \t\tres |= write_message(msgbuf.buf, msgbuf.len,\n-\t\t\t\t     git_path_merge_msg());\n+\t\t\t\t     git_path_merge_msg(), 0);\n \t} else {\n \t\tstruct commit_list *common = NULL;\n \t\tstruct commit_list *remotes = NULL;\n \n \t\tres = write_message(msgbuf.buf, msgbuf.len,\n-\t\t\t\t    git_path_merge_msg());\n+\t\t\t\t    git_path_merge_msg(), 0);\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304601","messageId":"27c06023494d7719a4c7bc29542cfd299b9afcaf.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 26/27] sequencer: start error messages consistently with lower case","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:25Z","receivedAt":"2016-10-21T12:26:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Quite a few error messages touched by this developer during the work to\nspeed up rebase -i started with an upper case letter, violating our\ncurrent conventions. Instead of sneaking in this fix (and forgetting\nquite a few error messages), let's just have one wholesale patch fixing\nall of the error messages in the sequencer.\n\nWhile at it, the funny \"error: Error wrapping up...\" was changed to a\nless funny, but more helpful, \"error: failed to finalize...\".\n\nPointed out by Junio Hamano.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c                   | 68 +++++++++++++++++++++----------------------\n t/t3501-revert-cherry-pick.sh |  2 +-\n 2 files changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 340d0ed..4c10c93 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -241,18 +241,18 @@ static int write_message(const void *buf, size_t len, const char *filename,\n \n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), filename);\n \tif (write_in_full(msg_fd, buf, len) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), filename);\n \t}\n \tif (append_eol && write(msg_fd, \"\\n\", 1) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error_errno(_(\"Could not write eol to '%s\"), filename);\n+\t\treturn error_errno(_(\"could not write eol to '%s\"), filename);\n \t}\n \tif (commit_lock_file(&msg_file) < 0) {\n \t\trollback_lock_file(&msg_file);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), filename);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), filename);\n \t}\n \n \treturn 0;\n@@ -302,11 +302,11 @@ static int error_dirty_index(struct replay_opts *opts)\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(_(action_name(opts)));\n \n-\terror(_(\"Your local changes would be overwritten by %s.\"),\n+\terror(_(\"your local changes would be overwritten by %s.\"),\n \t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n-\t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n+\t\tadvise(_(\"commit your changes or stash them to proceed.\"));\n \treturn -1;\n }\n \n@@ -415,7 +415,7 @@ static int is_index_unchanged(void)\n \tstruct commit *head_commit;\n \n \tif (!resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING, head_sha1, NULL))\n-\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\t\treturn error(_(\"could not resolve HEAD commit\\n\"));\n \n \thead_commit = lookup_commit(head_sha1);\n \n@@ -435,7 +435,7 @@ static int is_index_unchanged(void)\n \n \tif (!cache_tree_fully_valid(active_cache_tree))\n \t\tif (cache_tree_update(&the_index, 0))\n-\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\t\t\treturn error(_(\"unable to update cache tree\\n\"));\n \n \treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);\n }\n@@ -505,7 +505,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"You have staged changes in your working \"\n+\t\t\treturn error(\"you have staged changes in your working \"\n \t\t\t\t\"tree. If these changes are meant to be\\n\"\n \t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n \t\t\t\t\"  git commit --amend %s\\n\\n\"\n@@ -558,12 +558,12 @@ static int is_original_commit_empty(struct commit *commit)\n \tconst unsigned char *ptree_sha1;\n \n \tif (parse_commit(commit))\n-\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tif (commit->parents) {\n \t\tstruct commit *parent = commit->parents->item;\n \t\tif (parse_commit(parent))\n-\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\treturn error(_(\"could not parse parent commit %s\\n\"),\n \t\t\t\toid_to_hex(&parent->object.oid));\n \t\tptree_sha1 = parent->tree->object.oid.hash;\n \t} else {\n@@ -647,7 +647,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t * to work on.\n \t\t */\n \t\tif (write_cache_as_tree(head, 0, NULL))\n-\t\t\treturn error(_(\"Your index file is unmerged.\"));\n+\t\t\treturn error(_(\"your index file is unmerged.\"));\n \t} else {\n \t\tunborn = get_sha1(\"HEAD\", head);\n \t\tif (unborn)\n@@ -666,7 +666,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\tstruct commit_list *p;\n \n \t\tif (!opts->mainline)\n-\t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n+\t\t\treturn error(_(\"commit %s is a merge but no -m option was given.\"),\n \t\t\t\toid_to_hex(&commit->object.oid));\n \n \t\tfor (cnt = 1, p = commit->parents;\n@@ -674,11 +674,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t     cnt++)\n \t\t\tp = p->next;\n \t\tif (cnt != opts->mainline || !p)\n-\t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n+\t\t\treturn error(_(\"commit %s does not have parent %d\"),\n \t\t\t\toid_to_hex(&commit->object.oid), opts->mainline);\n \t\tparent = p->item;\n \t} else if (0 < opts->mainline)\n-\t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n+\t\treturn error(_(\"mainline was specified but commit %s is not a merge.\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \telse\n \t\tparent = commit->parents->item;\n@@ -696,7 +696,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n \t\t\toid_to_hex(&parent->object.oid));\n \n \tif (get_message(commit, &msg) != 0)\n-\t\treturn error(_(\"Cannot get commit message for %s\"),\n+\t\treturn error(_(\"cannot get commit message for %s\"),\n \t\t\toid_to_hex(&commit->object.oid));\n \n \t/*\n@@ -935,13 +935,13 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)\n \t\titem = append_new_todo(todo_list);\n \t\titem->offset_in_buf = p - todo_list->buf.buf;\n \t\tif (parse_insn_line(item, p, eol)) {\n-\t\t\tres = error(_(\"Invalid line %d: %.*s\"),\n+\t\t\tres = error(_(\"invalid line %d: %.*s\"),\n \t\t\t\ti, (int)(eol - p), p);\n \t\t\titem->command = -1;\n \t\t}\n \t}\n \tif (!todo_list->nr)\n-\t\treturn error(_(\"No commits parsed.\"));\n+\t\treturn error(_(\"no commits parsed.\"));\n \treturn res;\n }\n \n@@ -954,16 +954,16 @@ static int read_populate_todo(struct todo_list *todo_list,\n \tstrbuf_reset(&todo_list->buf);\n \tfd = open(todo_file, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not open '%s'\"), todo_file);\n+\t\treturn error_errno(_(\"could not open '%s'\"), todo_file);\n \tif (strbuf_read(&todo_list->buf, fd, 0) < 0) {\n \t\tclose(fd);\n-\t\treturn error(_(\"Could not read '%s'.\"), todo_file);\n+\t\treturn error(_(\"could not read '%s'.\"), todo_file);\n \t}\n \tclose(fd);\n \n \tres = parse_insn_buffer(todo_list->buf.buf, todo_list);\n \tif (res)\n-\t\treturn error(_(\"Unusable instruction sheet: '%s'\"), todo_file);\n+\t\treturn error(_(\"unusable instruction sheet: '%s'\"), todo_file);\n \n \tif (!is_rebase_i(opts)) {\n \t\tenum todo_command valid =\n@@ -974,9 +974,9 @@ static int read_populate_todo(struct todo_list *todo_list,\n \t\t\tif (valid == todo_list->items[i].command)\n \t\t\t\tcontinue;\n \t\t\telse if (valid == TODO_PICK)\n-\t\t\t\treturn error(_(\"Cannot cherry-pick during a revert.\"));\n+\t\t\t\treturn error(_(\"cannot cherry-pick during a revert.\"));\n \t\t\telse\n-\t\t\t\treturn error(_(\"Cannot revert during a cherry-pick.\"));\n+\t\t\t\treturn error(_(\"cannot revert during a cherry-pick.\"));\n \t}\n \n \treturn 0;\n@@ -1019,10 +1019,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \t\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n \t\topts->xopts[opts->xopts_nr++] = xstrdup(value);\n \t} else\n-\t\treturn error(_(\"Invalid key: %s\"), key);\n+\t\treturn error(_(\"invalid key: %s\"), key);\n \n \tif (!error_flag)\n-\t\treturn error(_(\"Invalid value for %s: %s\"), key, value);\n+\t\treturn error(_(\"invalid value for %s: %s\"), key, value);\n \n \treturn 0;\n }\n@@ -1054,7 +1054,7 @@ static int read_populate_opts(struct replay_opts *opts)\n \t * are pretty certain that it is syntactically correct.\n \t */\n \tif (git_config_from_file(populate_opts_cb, git_path_opts_file(), opts) < 0)\n-\t\treturn error(_(\"Malformed options sheet: '%s'\"),\n+\t\treturn error(_(\"malformed options sheet: '%s'\"),\n \t\t\tgit_path_opts_file());\n \treturn 0;\n }\n@@ -1097,7 +1097,7 @@ static int create_seq_dir(void)\n \t\treturn -1;\n \t}\n \telse if (mkdir(git_path_seq_dir(), 0777) < 0)\n-\t\treturn error_errno(_(\"Could not create sequencer directory '%s'\"),\n+\t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n \treturn 0;\n }\n@@ -1111,17 +1111,17 @@ static int save_head(const char *head)\n \tfd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);\n \tif (fd < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not lock HEAD\"));\n+\t\treturn error_errno(_(\"could not lock HEAD\"));\n \t}\n \tstrbuf_addf(&buf, \"%s\\n\", head);\n \tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error_errno(_(\"Could not write to '%s'\"),\n+\t\treturn error_errno(_(\"could not write to '%s'\"),\n \t\t\t\t   git_path_head_file());\n \t}\n \tif (commit_lock_file(&head_lock) < 0) {\n \t\trollback_lock_file(&head_lock);\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), git_path_head_file());\n+\t\treturn error(_(\"failed to finalize '%s'.\"), git_path_head_file());\n \t}\n \treturn 0;\n }\n@@ -1200,14 +1200,14 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n \n \tfd = hold_lock_file_for_update(&todo_lock, todo_path, 0);\n \tif (fd < 0)\n-\t\treturn error_errno(_(\"Could not lock '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not lock '%s'\"), todo_path);\n \toffset = next < todo_list->nr ?\n \t\ttodo_list->items[next].offset_in_buf : todo_list->buf.len;\n \tif (write_in_full(fd, todo_list->buf.buf + offset,\n \t\t\ttodo_list->buf.len - offset) < 0)\n-\t\treturn error_errno(_(\"Could not write to '%s'\"), todo_path);\n+\t\treturn error_errno(_(\"could not write to '%s'\"), todo_path);\n \tif (commit_lock_file(&todo_lock) < 0)\n-\t\treturn error(_(\"Error wrapping up '%s'.\"), todo_path);\n+\t\treturn error(_(\"failed to finalize '%s'.\"), todo_path);\n \treturn 0;\n }\n \n@@ -1382,7 +1382,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)\n \t\t\tcreate_seq_dir() < 0)\n \t\treturn -1;\n \tif (get_sha1(\"HEAD\", sha1) && (opts->action == REPLAY_REVERT))\n-\t\treturn error(_(\"Can't revert as initial commit\"));\n+\t\treturn error(_(\"can't revert as initial commit\"));\n \tif (save_head(sha1_to_hex(sha1)))\n \t\treturn -1;\n \tif (save_opts(opts))\ndiff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh\nindex 51f3bbb..394f000 100755\n--- a/t/t3501-revert-cherry-pick.sh\n+++ b/t/t3501-revert-cherry-pick.sh\n@@ -96,7 +96,7 @@ test_expect_success 'revert forbidden on dirty working tree' '\n \techo content >extra_file &&\n \tgit add extra_file &&\n \ttest_must_fail git revert HEAD 2>errors &&\n-\ttest_i18ngrep \"Your local changes would be overwritten by \" errors\n+\ttest_i18ngrep \"your local changes would be overwritten by \" errors\n \n '\n \n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304602","messageId":"ff044c6d0215b9391411a953a7e114022adb4c35.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 20/27] sequencer: roll back lock file if write_message() failed","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:00Z","receivedAt":"2016-10-21T12:26:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There is no need to wait until the atexit() handler kicks in at the end.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 745c86f..9fced42 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -241,10 +241,14 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n \tint msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);\n \tif (msg_fd < 0)\n \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n-\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n-\t\treturn error_errno(_(\"Could not write to %s\"), filename);\n-\tif (commit_lock_file(&msg_file) < 0)\n+\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0) {\n+\t\trollback_lock_file(&msg_file);\n+\t\treturn error_errno(_(\"Could not write to '%s'\"), filename);\n+\t}\n+\tif (commit_lock_file(&msg_file) < 0) {\n+\t\trollback_lock_file(&msg_file);\n \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n+\t}\n \n \treturn 0;\n }\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304603","messageId":"a53f60adceaba6fc02192931c37cc97a40617153.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 24/27] sequencer: mark action_name() for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:17Z","receivedAt":"2016-10-21T12:26:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"The definition of this function goes back all the way to 043a449\n(sequencer: factor code out of revert builtin, 2012-01-11), long before a\nserious effort was made to translate all the error messages.\n\nIt is slightly out of the context of the current patch series (whose\npurpose it is to re-implement the performance critical parts of the\ninteractive rebase in C) to make the error messages in the sequencer\ntranslatable, but what the heck. We'll just do it while we're looking at\nthis part of the code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex bd11db4..ff76b6f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -168,7 +168,7 @@ int sequencer_remove_state(struct replay_opts *opts)\n \n static const char *action_name(const struct replay_opts *opts)\n {\n-\treturn opts->action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\";\n+\treturn opts->action == REPLAY_REVERT ? N_(\"revert\") : N_(\"cherry-pick\");\n }\n \n struct commit_message {\n@@ -300,10 +300,10 @@ static struct tree *empty_tree(void)\n static int error_dirty_index(struct replay_opts *opts)\n {\n \tif (read_cache_unmerged())\n-\t\treturn error_resolve_conflict(action_name(opts));\n+\t\treturn error_resolve_conflict(_(action_name(opts)));\n \n \terror(_(\"Your local changes would be overwritten by %s.\"),\n-\t\taction_name(opts));\n+\t\t_(action_name(opts)));\n \n \tif (advice_commit_before_merge)\n \t\tadvise(_(\"Commit your changes or stash them to proceed.\"));\n@@ -321,7 +321,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,\n \tif (checkout_fast_forward(from, to, 1))\n \t\treturn -1; /* the callee should have complained already */\n \n-\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), action_name(opts));\n+\tstrbuf_addf(&sb, _(\"%s: fast-forward\"), _(action_name(opts)));\n \n \ttransaction = ref_transaction_begin(&err);\n \tif (!transaction ||\n@@ -397,7 +397,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \t    write_locked_index(&the_index, &index_lock, COMMIT_LOCK))\n \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n \t\treturn error(_(\"%s: Unable to write new index file\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \trollback_lock_file(&index_lock);\n \n \tif (opts->signoff)\n@@ -835,14 +835,14 @@ static int read_and_refresh_cache(struct replay_opts *opts)\n \tif (read_index_preload(&the_index, NULL) < 0) {\n \t\trollback_lock_file(&index_lock);\n \t\treturn error(_(\"git %s: failed to read the index\"),\n-\t\t\taction_name(opts));\n+\t\t\t_(action_name(opts)));\n \t}\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n \tif (the_index.cache_changed && index_fd >= 0) {\n \t\tif (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {\n \t\t\trollback_lock_file(&index_lock);\n \t\t\treturn error(_(\"git %s: failed to refresh the index\"),\n-\t\t\t\taction_name(opts));\n+\t\t\t\t_(action_name(opts)));\n \t\t}\n \t}\n \trollback_lock_file(&index_lock);\n-- \n2.10.1.583.g721a9e0\n\n\n"},{"id":"304604","messageId":"b343290202b5cb3df1595ccbfbec3e18e4faf2c9.1477052405.git.johannes.schindelin@gmx.de","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 27/27] sequencer: mark all error messages for translation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-21T12:26:32Z","receivedAt":"2016-10-21T12:26:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There was actually only one error message that was not yet marked for\ntranslation.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n sequencer.c | 26 ++++++++++++++++----------\n 1 file changed, 16 insertions(+), 10 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 4c10c93..a61fe76 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -479,6 +479,20 @@ static char **read_author_script(void)\n \treturn env;\n }\n \n+static const char staged_changes_advice[] =\n+N_(\"you have staged changes in your working tree\\n\"\n+\"If these changes are meant to be squashed into the previous commit, run:\\n\"\n+\"\\n\"\n+\"  git commit --amend %s\\n\"\n+\"\\n\"\n+\"If they are meant to go into a new commit, run:\\n\"\n+\"\\n\"\n+\"  git commit %s\\n\"\n+\"\\n\"\n+\"In both cases, once you're done, continue with:\\n\"\n+\"\\n\"\n+\"  git rebase --continue\\n\");\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -505,16 +519,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \t\tif (!env) {\n \t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(\"you have staged changes in your working \"\n-\t\t\t\t\"tree. If these changes are meant to be\\n\"\n-\t\t\t\t\"squashed into the previous commit, run:\\n\\n\"\n-\t\t\t\t\"  git commit --amend %s\\n\\n\"\n-\t\t\t\t\"If they are meant to go into a new commit, \"\n-\t\t\t\t\"run:\\n\\n\"\n-\t\t\t\t\"  git commit %s\\n\\n\"\n-\t\t\t\t\"In both cases, once you're done, continue \"\n-\t\t\t\t\"with:\\n\\n\"\n-\t\t\t\t\"  git rebase --continue\\n\", gpg_opt, gpg_opt);\n+\t\t\treturn error(_(staged_changes_advice),\n+\t\t\t\t     gpg_opt, gpg_opt);\n \t\t}\n \t}\n \n-- \n2.10.1.583.g721a9e0\n"},{"id":"304613","messageId":"xmqqr379d82b.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610211343310.3264@virtualbox","subject":"Re: [PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-21T15:40:28Z","receivedAt":"2016-10-21T15:40:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Ah, make that four steps.  The final one is:\n>> \n>>     - add append_eol parameter that nobody uses at this step in the\n>>       series.\n>>\n>> This is a new feature to the helper.  While it is OK to have it as a\n>> preparatory step in this series, it is easier to understand if it\n>> kept as a separate step.  It is even more preferrable if it is made\n>> as a preparatory step in a series that adds a caller that passes\n>> true to append_eol to this helper...\n>\n> Done,\n> Dscho\n\nHmm, what has been done exactly?  I still see append_eol in v5 where\nnobody uses it yet.  Confused...\n\n"},{"id":"304636","messageId":"xmqqr379blls.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"c89508366501c17e7363a7d5c631fce9b3750cd2.1477052405.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 19/27] sequencer: stop releasing the strbuf in write_message()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-21T18:30:55Z","receivedAt":"2016-10-21T18:31:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Nothing in the name \"write_message()\" suggests that the function\n> releases the strbuf passed to it. So let's release the strbuf in the\n> caller instead.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nI agree that it makes quite a lot of sense from the point of view of\n\"taste in the API design\".\n\n>  sequencer.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index d74fdce..745c86f 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -243,7 +243,6 @@ static int write_message(struct strbuf *msgbuf, const char *filename)\n>  \t\treturn error_errno(_(\"Could not lock '%s'\"), filename);\n>  \tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n>  \t\treturn error_errno(_(\"Could not write to %s\"), filename);\n> -\tstrbuf_release(msgbuf);\n>  \tif (commit_lock_file(&msg_file) < 0)\n>  \t\treturn error(_(\"Error wrapping up %s.\"), filename);\n>  \n> @@ -759,6 +758,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,\n>  \t\tfree_commit_list(common);\n>  \t\tfree_commit_list(remotes);\n>  \t}\n> +\tstrbuf_release(&msgbuf);\n>  \n>  \t/*\n>  \t * If the merge was clean or if it failed due to conflict, we write\n"},{"id":"304637","messageId":"xmqqmvhxbljm.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"d858bd99a3ad3dea807f38b8bd42a221a9f7924c.1477052405.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 22/27] sequencer: teach write_message() to append an optional LF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-21T18:32:13Z","receivedAt":"2016-10-21T18:32:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This commit prepares for future callers that will have a pointer/length\n> to some text to be written that lacks an LF, yet an LF is desired.\n> Instead of requiring the caller to append an LF to the buffer (and\n> potentially allocate memory to do so), the write_message() function\n> learns to append an LF at the end of the file.\n\nAs no existing callers need this, it probably is better left out and\nadded to the series that actually needs the new feature as a\npreparatory step.\n\n"},{"id":"304638","messageId":"xmqqinslbl5t.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-21T18:40:30Z","receivedAt":"2016-10-21T18:40:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Changes vs v4:\n\nI still do not understand (note that I am not saying \"I do not\naccept\"--acceptance or rejection happens after an understandable\nexplanation is given, and \"do not understand\" means no such\nexplanation has been given yet) your justification behind adding a\ntechnical debt to reimplement the author-script parser and not\nsharing it with \"git am\" in 13/27.\n\nAs I pointed out, I think 22/27 is out of place in this series.\n\nBut other than these two points, the changes since v4 look minimum,\nand they all looked good to me.\n\nThanks.\n"},{"id":"304681","messageId":"xmqqinsk8g1b.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"cover.1477052405.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-22T17:11:44Z","receivedAt":"2016-10-22T17:11:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This patch series marks the '4' in the countdown to speed up rebase -i\n> by implementing large parts in C (read: there will be three more patch\n> series after that before the full benefit hits git.git: sequencer-i,\n> rebase--helper and rebase-i-extra).\n> ...\n> It would be *really* nice if we could get this patch series at least into\n> `next` soon, as it gets late and later for the rest of the patches to make\n> it into `master` in time for v2.11 (and it is not for lack of trying on my\n> end...).\n\nThis \"countdown 4\" step can affect cherry-pick and revert, even\nthough we were careful to review changes to the sequencer.c code.  I\nprefer to cook it in 'next' sufficiently long to ensure that we hear\nfeedbacks from non-Windows users if there is any unexpected breakage.\n\nThere isn't enough time to include this topic in the upcoming\nrelease within the current https://tinyurl.com/gitCal calendar,\nhowever, which places the final on Nov 11th.\n\nI am wondering if it makes sense to delay 2.11 by moving the final\nby 4 weeks to Dec 9th.\n\nThoughts?\n\nSpeaking of what to and not to include in the upcoming release, we\ndo want to include Stefan's off-by-one fix to the submodule-helper,\nbut that is blocked on Windows end due to the test.  I think\neverybody agreed that a longer time \"right thing to do\" fix is to\naddress the \"when base is /path/to/dir/., where is ../sub relative\nto it?\" issue, but if we are to do so, it would need a longer\ngestation period once it hits 'next', as it can affect the current\nusers and we may even need B/C notes in the release notes for the\nchange.  Giving ourselves a few more weeks of breathing room would\nhelp us to make sure the fix to relative URL issue is sound, too.\n\nAs to \"countdown 3\" and below steps, I am guessing that some of them\ncan start cooking in 'next' before 2.11, but even with lengthened\nschedule, it is likely that they need to cook there beyond the end\nof this cycle, unless they are truly trivial changes that do not\neven need any reviews.\n\nThanks.\n"},{"id":"304749","messageId":"alpine.DEB.2.20.1610231125590.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqr379d82b.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 20/25] sequencer: refactor write_message()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-23T09:29:10Z","receivedAt":"2016-10-23T09:29:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 21 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Ah, make that four steps.  The final one is:\n> >> \n> >>     - add append_eol parameter that nobody uses at this step in the\n> >>       series.\n> >>\n> >> This is a new feature to the helper.  While it is OK to have it as a\n> >> preparatory step in this series, it is easier to understand if it\n> >> kept as a separate step.  It is even more preferrable if it is made\n> >> as a preparatory step in a series that adds a caller that passes\n> >> true to append_eol to this helper...\n> >\n> > Done,\n> > Dscho\n> \n> Hmm, what has been done exactly?  I still see append_eol in v5 where\n> nobody uses it yet.  Confused...\n\nYour bullet point suggests that this change should be a separate patch. I\ndid that.\n\nAnd since this patch series' purpose is to prepare the sequencer for the\nupcoming series that teaches it to understand git-rebase-todo scripts,\nthis patch falls fair and square into the preparatory phase.\n\nCiao,\nDscho\n"},{"id":"304751","messageId":"alpine.DEB.2.20.1610231129410.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqmvhxbljm.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 22/27] sequencer: teach write_message() to append an optional LF","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-23T09:34:47Z","receivedAt":"2016-10-23T09:35:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 21 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This commit prepares for future callers that will have a pointer/length\n> > to some text to be written that lacks an LF, yet an LF is desired.\n> > Instead of requiring the caller to append an LF to the buffer (and\n> > potentially allocate memory to do so), the write_message() function\n> > learns to append an LF at the end of the file.\n> \n> As no existing callers need this, it probably is better left out and\n> added to the series that actually needs the new feature as a\n> preparatory step.\n\nApart from this patch series being semantically the right place\n(\"prepare-sequencer\"), there is also the following consideration:\nThe next patch series is already quite long. Taking this current patch\nseries into account, which started out as a 22-patch series and needed to\nbloat by 25% through four subsequent iterations, it is probably not a wise\nidea to move this patch to a patch series that already weighs 34 patches.\n\nSo I respectfully, and forcefully, disagree,\nDscho\n"},{"id":"304752","messageId":"alpine.DEB.2.20.1610231135270.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqinslbl5t.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-23T09:50:40Z","receivedAt":"2016-10-23T09:51:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 21 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> I still do not understand (note that I am not saying \"I do not\n> accept\"--acceptance or rejection happens after an understandable\n> explanation is given, and \"do not understand\" means no such\n> explanation has been given yet) your justification behind adding a\n> technical debt to reimplement the author-script parser and not\n> sharing it with \"git am\" in 13/27.\n\nAt this point, I am most of all reluctant to introduce such a huge change,\nwhich surely would introduce a regression.\n\nThis is what happened a couple of times to me, most recently with the\nhide-dot-gitdir patch series that worked flawlessly for years, had to be\ndramatically changed during review to enter git.git, and introduced the\nmajor regression that `core.hideDotFiles = gitDirOnly` was broken.\n\nThe lesson I learned: review should not be valued more than the test of\ntime. This lesson has been reinforced by all the regressions that have not\nbeen caught by review nor the test suite running on Linux only.\n\nIt would be a different matter if I still had the cross-validator in place\n(which I did when I sent out v1 of this patch series) and tons of time to\nspend on accommodating your wishes, however I may disagree with them. And\nin this instance, I thought I made clear that I disagree, and why:\nInternally, git-am and git-rebase-i handle the author-script very\ndifferently. That may change at some stage in the future, and it would be\na good time then and there to take care of unifying this code. Currently,\nnot so much, as the only excuse to use the same parser would be that they\nboth read the same file, while they have to do very different things with\nthe parsed output (in fact, your suggestion would ask the parser in the\nsequencer to rip apart the information into key/value pairs, only to\nre-glue them back together when they are used as the environment variables\nas which rebase-i treats the contents of the author-script file).\n\nSo no, at this point I am not willing to risk introducing breakages in\ncode that has been proven to work in practice.\n\nCiao,\nDscho\n"},{"id":"304753","messageId":"alpine.DEB.2.20.1610231151140.3264@virtualbox","threadId":"43954","inReplyTo":"xmqqinsk8g1b.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-23T09:54:53Z","receivedAt":"2016-10-23T09:55:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 22 Oct 2016, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This patch series marks the '4' in the countdown to speed up rebase -i\n> > by implementing large parts in C (read: there will be three more patch\n> > series after that before the full benefit hits git.git: sequencer-i,\n> > rebase--helper and rebase-i-extra).\n> > ...\n> > It would be *really* nice if we could get this patch series at least\n> > into `next` soon, as it gets late and later for the rest of the\n> > patches to make it into `master` in time for v2.11 (and it is not for\n> > lack of trying on my end...).\n> \n> This \"countdown 4\" step can affect cherry-pick and revert, even\n> though we were careful to review changes to the sequencer.c code.\n\nAs I pointed out in another mail in this thread: we should not fall into\nthe trap of overrating review.\n\nIn the case of the rebase--helper patches, so far the review mainly\nresulted in more work for me (having to change spellings elsewhere, for\nexample), not in improving the changes I intended to introduce into\ngit.git's code.\n\nSure, there has been the occasional improvement, but it certainly feels as\nif I spent about 80% of the work after each -v1 iteration on things that\nhave positively nothing at all to do with accelerating rebase -i.\n\n> I prefer to cook it in 'next' sufficiently long to ensure that we hear\n> feedbacks from non-Windows users if there is any unexpected breakage.\n\nFWIW I am using the same patches not only on Windows but also in my Linux\nVM.\n\n> There isn't enough time to include this topic in the upcoming\n> release within the current https://tinyurl.com/gitCal calendar,\n> however, which places the final on Nov 11th.\n\nMore is the pity.\n\nThank you, though, for being upfront with me. I will shift my focus to\ntasks that require my attention more urgently, then.\n\nCiao,\nDscho\n"},{"id":"304754","messageId":"alpine.DEB.2.20.1610231157110.3264@virtualbox","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610231151140.3264@virtualbox","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-23T09:58:04Z","receivedAt":"2016-10-23T09:58:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 23 Oct 2016, Johannes Schindelin wrote:\n\n> On Sat, 22 Oct 2016, Junio C Hamano wrote:\n> \n> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> > \n> > > This patch series marks the '4' in the countdown to speed up rebase -i\n> > > by implementing large parts in C (read: there will be three more patch\n> > > series after that before the full benefit hits git.git: sequencer-i,\n> > > rebase--helper and rebase-i-extra).\n> > > ...\n> > > It would be *really* nice if we could get this patch series at least\n> > > into `next` soon, as it gets late and later for the rest of the\n> > > patches to make it into `master` in time for v2.11 (and it is not for\n> > > lack of trying on my end...).\n> > \n> > This \"countdown 4\" step can affect cherry-pick and revert, even\n\nOh, I forgot to comment on this tidbit of your mail, sorry.\n\nThis *is* the countdown 4, as the remaining 3 patch series depend on each\nother in the order I sent them out.\n\nCiao,\nDscho\n"},{"id":"304770","messageId":"DAD768D3-5558-49DE-9FDD-E46F17933ECE@quendi.de","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610231151140.3264@virtualbox","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Max Horn","fromEmail":"max@quendi.de","sentAt":"2016-10-24T12:24:49Z","receivedAt":"2016-10-24T12:39:55Z","isPatch":true,"sender":{"key":"max@quendi.de","avatar":"https://avatars.githubusercontent.com/u/241512?v=4"},"body":"Hi Dscho,\n\n> On 23 Oct 2016, at 11:54, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> \n> Hi Junio,\n> \n> On Sat, 22 Oct 2016, Junio C Hamano wrote:\n> \n[...]\n\n>> There isn't enough time to include this topic in the upcoming\n>> release within the current https://tinyurl.com/gitCal calendar,\n>> however, which places the final on Nov 11th.\n> \n> More is the pity.\n> \n> Thank you, though, for being upfront with me. I will shift my focus to\n> tasks that require my attention more urgently, then.\n\nJunio did go on, though:\n\n>> I am wondering if it makes sense to delay 2.11 by moving the final\n>> by 4 weeks to Dec 9th.\n\nI was reading this as an offer to delay things to accommodate the integration your work into 2.11. I.e. \"within the current plan, there is no time for this, but we could adjust the plan\". But maybe I am misinterpreting?\n\n\nCheers,\nMax\n"},{"id":"304774","messageId":"alpine.DEB.2.20.1610241500131.3264@virtualbox","threadId":"43954","inReplyTo":"DAD768D3-5558-49DE-9FDD-E46F17933ECE@quendi.de","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-10-24T14:02:57Z","receivedAt":"2016-10-24T14:08:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Max,\n\nOn Mon, 24 Oct 2016, Max Horn wrote:\n\n> > On 23 Oct 2016, at 11:54, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > \n> > On Sat, 22 Oct 2016, Junio C Hamano wrote:\n> > \n> [...]\n> \n> >> There isn't enough time to include this topic in the upcoming release\n> >> within the current https://tinyurl.com/gitCal calendar, however,\n> >> which places the final on Nov 11th.\n> > \n> > More is the pity.\n> > \n> > Thank you, though, for being upfront with me. I will shift my focus to\n> > tasks that require my attention more urgently, then.\n> \n> Junio did go on, though:\n> \n> >> I am wondering if it makes sense to delay 2.11 by moving the final\n> >> by 4 weeks to Dec 9th.\n> \n> I was reading this as an offer to delay things to accommodate the\n> integration your work into 2.11. I.e. \"within the current plan, there is\n> no time for this, but we could adjust the plan\". But maybe I am\n> misinterpreting?\n\nThere is no indication that the rebase--helper patches would make it into\n2.11 even with four more weeks.\n\nI will now focus on other things that I postponed in favor of the\ninteractive rebase patches. In fact, I *have* to focus on some quite\npressing tasks that I neglected over those patches.\n\nIt's not like the process would magically improve just because a release\ndate is pushed. To the contrary, pushing the release date to allow for the\nrebase--helper to be included may very well have the counterintuitive\neffect of delaying things beyond even that pushed date \"because there is\nnow so much time left\" (until there isn't). It's a variation of\n[Parkinson's Law](https://en.wikipedia.org/wiki/Parkinson%27s_law) ;-)\n\nAnyway, back to work,\nDscho\n"},{"id":"304797","messageId":"CAGZ79kaq85c1Gk1aRSrdQGp1Nm9p6tN0jXbFvTN0v+9ehooxYg@mail.gmail.com","threadId":"43954","inReplyTo":"xmqqinsk8g1b.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-10-24T19:36:50Z","receivedAt":"2016-10-24T19:36:56Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Sat, Oct 22, 2016 at 10:11 AM, Junio C Hamano <gitster@pobox.com> wrote:\n\n>\n> There isn't enough time to include this topic in the upcoming\n> release within the current https://tinyurl.com/gitCal calendar,\n> however, which places the final on Nov 11th.\n>\n> I am wondering if it makes sense to delay 2.11 by moving the final\n> by 4 weeks to Dec 9th.\n>\n> Thoughts?\n>\n> Speaking of what to and not to include in the upcoming release, we\n> do want to include Stefan's off-by-one fix to the submodule-helper,\n> but that is blocked on Windows end due to the test.\n\nI'd be happy either way, i.e. we could revert that fix and make a release?\nAFAICT, Windows only has broken tests, not broken functionality with that\nsubmodule bug fix.\n\n> I think\n> everybody agreed that a longer time \"right thing to do\" fix is to\n> address the \"when base is /path/to/dir/., where is ../sub relative\n> to it?\" issue, but if we are to do so, it would need a longer\n> gestation period once it hits 'next', as it can affect the current\n> users and we may even need B/C notes in the release notes for the\n> change.  Giving ourselves a few more weeks of breathing room would\n> help us to make sure the fix to relative URL issue is sound, too.\n\nIf we want a longer gestation period, we'd ideally merge it to master\njust after a release, such that we \"cook\" it in master without having\nit in any release (we had a similar discussion for the diff heuristics IIRC).\n\nSo please don't let the release schedule depend on my ability to deliver a\nproper patch for the submodule path issue.\n\nThanks,\nStefan\n"},{"id":"304801","messageId":"xmqq8ttd4iw0.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610231135270.3264@virtualbox","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-24T20:00:31Z","receivedAt":"2016-10-24T20:00:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I still do not understand (note that I am not saying \"I do not\n>> accept\"--acceptance or rejection happens after an understandable\n>> explanation is given, and \"do not understand\" means no such\n>> explanation has been given yet) your justification behind adding a\n>> technical debt to reimplement the author-script parser and not\n>> sharing it with \"git am\" in 13/27.\n>\n> At this point, I am most of all reluctant to introduce such a huge change,\n> which surely would introduce a regression.\n\nThat is a perfectly sensible and honest answer that I can\nunderstand, accept and even support.\n\nYou've been working on the series for several months, running with\nthese dozen or so lines of code, and replacing it with another dozen\nor so lines of code would require you to make sure the result is\nactually doing the same thing for the remainder of your series.  And\nI agree that is an unnecessary risk in order to ship a working code.\nThe code being battle tested counts.\n\nI cared on this point mostly because I wanted to make sure that\npeople later can find out why there are two functions that ought to\nbe doing the same thing.  \n\nIf there were a technical reason why these two must stay to be\ndifferent implementations that are potentially doing different\nthings, I want to see that reason described, so that those who come\nlater and want to refactor the helper functions into one later will\nknow why they are separate in the first place.\n\nIf on the other hand there isn't any technical reason why they must\nstay to be different, and they are different mostly because you\nhappened to have written a different one in 13/27 and have been\nrunning with it, that is also a good thing for them to know.\n\n"},{"id":"304802","messageId":"xmqqtwc13472.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"alpine.DEB.2.20.1610231151140.3264@virtualbox","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-24T20:03:13Z","receivedAt":"2016-10-24T20:03:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I prefer to cook it in 'next' sufficiently long to ensure that we hear\n>> feedbacks from non-Windows users if there is any unexpected breakage.\n>\n> FWIW I am using the same patches not only on Windows but also in my Linux\n> VM.\n\nThanks for a datapoint, but when I said \"non-Windows users\", I was\nnot referring you as \"the\" Windows user.  I am expecting that you\nwould hear from Windows users who got exposure to your series by its\ninclusion in Git for Windows.  They are the ones that I had in mind\nas \"Windows users\"---and not hearing breakage reported by them would\nbe a good sign.\n\nThe primary reason why we want to cook a new topic in 'next' is to\nexpose it to people with different workflows using it on different\nthings, and that is especially more important for a change that\naffects features that are flexible and can be used in different\nways---the set of options and commands used by the original author\nof the series are often different from other people's.\n\nAny change, when it hits 'next', is expected to be sufficiently\ntested by the original author [*1*], but that is only true in the\ncontext of the original author's daily use.  Both reviews and\nauthor's tests are not sufficient to find bugs [*2*].\n\nTopics that touch parts of the system that are more important to\nusers' daily Git life deserve extra time to find any unexpected\nbreakage in them.  Windows users are participating in that test by\ninclusion of the topic in the released version of Git for Windows.\nI want to see the the test for the rest of the world done by early\nadopters who run 'next' (as 'pu' is too scary for daily use).\n\n\n[Footnote]\n\n*1* And me, as topics geting ready to be in 'next' are first merged\n    to my private edition branch that is slightly ahead of 'next' to\n    be used in my everyday use, but just like the original author is\n    merely one user, I am also merely one user with a specific set\n    of workflows that is different from others'.\n\n*2* Bug finding is not the primary purpose of the review in the\n    first place.  It is to find design mistakes both at the external\n    and internal level, and bug finding \"here you have off-by-one\"\n    is merely a side effect.  End user tests may expose the former\n    (e.g. the design based on a wrong assumption may not accomodate\n    certain workflow the original author and the reviewers failed to\n    consider while writing and reviewing), but no amount of test\n    will uncover the latter (e.g. internal API that is misdesigned\n    will make future enhancement unnecessarily harder).\n\n    I think it was one of the achievements of the review cycle of\n    this particular series that we got rid of the _entrust() thing,\n    for example.  That had no visible external effect that would\n    have been caught by cooking on 'next' or releasing it to the\n    public, but was the kind of thing the code review was expected\n    to find and fix.\n"},{"id":"304803","messageId":"xmqqpomp33km.fsf@gitster.mtv.corp.google.com","threadId":"43954","inReplyTo":"CAGZ79kaq85c1Gk1aRSrdQGp1Nm9p6tN0jXbFvTN0v+9ehooxYg@mail.gmail.com","subject":"Re: [PATCH v5 00/27] Prepare the sequencer for the upcoming rebase -i patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-10-24T20:16:41Z","receivedAt":"2016-10-24T20:16:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n>> Speaking of what to and not to include in the upcoming release, we\n>> do want to include Stefan's off-by-one fix to the submodule-helper,\n>> but that is blocked on Windows end due to the test.\n>\n> I'd be happy either way, i.e. we could revert that fix and make a release?\n> AFAICT, Windows only has broken tests, not broken functionality with that\n> submodule bug fix.\n\nIf you are referring the \"trailing /. should not make difference\nwhen resolving ../relative/path\" change with \"rever that fix\", I\nthink that may be a reasonable way to proceed.  Even though that\nchange is a bugfix (at least from the point of view by me and j6t in\nthe recent discussion), it is a behaviour change that we would want\nto see feedback from existing submodule users and deserves a longer\ngestation period.  And that part is not yet in 'next' yet ;-)\n\n> If we want a longer gestation period, we'd ideally merge it to master\n> just after a release, such that we \"cook\" it in master without having\n> it in any release (we had a similar discussion for the diff heuristics IIRC).\n\nYes.  \n\nIt would mean that we would need a separate patch that adds the\n!MINGW prerequisite to some tests to what is on 'next', as the early\npatches on sb/submodule-ignore-trailing-slash~ that fixes off-by-one\nis the right thing to do either way.  It of course needs help from\nWindows folks to validate the results.\n"},{"id":"305452","messageId":"D3B8B6CB-D238-42A9-9B94-D135C25B4A63@gmail.com","threadId":"43954","inReplyTo":"c0d106125e1b6ba107b1ef06fb60dd710d184d29.1477052405.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 08/27] sequencer: completely revamp the \"todo\" script parsing","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2016-11-06T14:05:22Z","receivedAt":"2016-11-06T14:05:26Z","isPatch":true,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"\n> On 21 Oct 2016, at 14:24, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:\n> \n> When we came up with the \"sequencer\" idea, we really wanted to have\n> kind of a plumbing equivalent of the interactive rebase. Hence the\n> choice of words: the \"todo\" script, a \"pick\", etc.\n> \n> ...\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n> sequencer.c | 284 ++++++++++++++++++++++++++++++++++--------------------------\n> 1 file changed, 163 insertions(+), 121 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index 499f5ee..145de78 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -470,7 +470,26 @@ static int allow_empty(struct replay_opts *opts, struct commit *commit)\n> \t\treturn 1;\n> }\n> \n> -static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n> +enum todo_command {\n> +\tTODO_PICK = 0,\n> +\tTODO_REVERT\n> +};\n> +\n> +static const char *todo_command_strings[] = {\n> +\t\"pick\",\n> +\t\"revert\"\n> +};\n> +\n> +static const char *command_to_string(const enum todo_command command)\n> +{\n> +\tif (command < ARRAY_SIZE(todo_command_strings))\n\nWith DEVELOPER=1 I get this error on macOS when I compile current git/next (b27dc33) using clang:\n\nsequencer.c:632:14: error: comparison of constant 2 with expression of type 'const enum todo_command' is always true [-Werror,-Wtautological-constant-out-of-range-compare]\n        if (command < ARRAY_SIZE(todo_command_strings))\n\nTorsten discovered this problem already in v3 and Peff suggested\na working solution [1]. Is there any reason not to use Peff's suggestion?\n\n\nCheers,\nLars\n\n[1] http://public-inbox.org/git/d9f4f658-94fb-cb9e-7da8-3a2fac120a9e@web.de/"}]}