{"thread":{"id":"27786","subject":"[GSoC update] Sequencer for inclusion","startedAt":"2011-07-11T14:53:51Z","lastAt":"2011-07-20T05:32:30Z","messageCount":99,"participants":["Ramkumar Ramachandra","Jonathan Nieder","Junio C Hamano","Jeff King","Miles Bader","Sverre Rabbelier"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"171053","messageId":"1310396048-24925-1-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":null,"subject":"[GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:51Z","receivedAt":"2011-07-11T14:53:51Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nI'm excited to announce the first iteration of a fresh series -- this\none is intended for inclusion.  There are five new patches since last\ntime, the most significant of which is \"revert: Save command-line\noptions for continuing operation\", which introduces a parser for\ncommand-line options.  Some patches might be slightly controversial,\nbut I think most of the new ideas have already been discussed\npreviously.  Another significant introduction is \"sequencer: Announce\nsequencer state location\" -- this is where most of the post mid-term\nwork will go.\n\nI would have liked to reuse the gitconfig parser as-is for the opts\nparsing, but it's too tangled up in config.c.  I think it's safe to\nsay that the opts file format deviates only slightly from the\ngitconfig format, and I'm quite happy with the end result.\n\nWhat this requires now:\n1. Review all existing code.  Many things might have moved around due\nto heavy rebasing.\n2. Repetition of unimplemented suggestions.  I'm sorry if I've missed\nout some -- I was focusing on new features this time, not fixing\nexisting problems.\n3. Rigorous testing of the new options parser.  We don't want\nsegfaults because of a silly parser.\n4. New tests and documentation.  There's really no end to this, so\nplease suggest only things that are absolutely necessary before\ninclusion.\n\nIn general, please point out things that need to be done immediately\nbefore the inclusion.  The series is becoming large and unmanagable --\nwe can fix minor issues after the merge.\n\nThanks for reading.\n\n-- Ram\n\nRamkumar Ramachandra (17):\n  advice: Introduce error_resolve_conflict\n  revert: Inline add_message_to_msg function\n  revert: Don't check lone argument in get_encoding\n  revert: Rename no_replay to record_origin\n  revert: Propogate errors upwards from do_pick_commit\n  revert: Eliminate global \"commit\" variable\n  revert: Introduce struct to keep command-line options\n  revert: Separate cmdline parsing from functional code\n  revert: Don't create invalid replay_opts in parse_args\n  sequencer: Announce sequencer state location\n  revert: Save data for continuing after conflict resolution\n  revert: Save command-line options for continuing operation\n  revert: Introduce a layer of indirection over pick_commits\n  reset: Make hard reset remove the sequencer state\n  revert: Remove sequencer state when no commits are pending\n  revert: Introduce --reset to remove sequencer state\n  revert: Introduce --continue to continue the operation\n\n Documentation/git-cherry-pick.txt |    6 +\n Documentation/git-revert.txt      |    6 +\n Documentation/sequencer.txt       |    9 +\n Makefile                          |    2 +\n advice.c                          |   31 +-\n advice.h                          |    3 +-\n builtin/reset.c                   |    2 +\n builtin/revert.c                  |  863 ++++++++++++++++++++++++++++++-------\n git-rebase--interactive.sh        |   25 +-\n sequencer.c                       |   19 +\n sequencer.h                       |   19 +\n t/7106-reset-sequence.sh          |   40 ++\n t/t3510-cherry-pick-sequence.sh   |  197 +++++++++\n 13 files changed, 1058 insertions(+), 164 deletions(-)\n create mode 100644 Documentation/sequencer.txt\n create mode 100644 sequencer.c\n create mode 100644 sequencer.h\n create mode 100755 t/7106-reset-sequence.sh\n create mode 100755 t/t3510-cherry-pick-sequence.sh\n\n-- \n1.7.5.GIT\n"},{"id":"171054","messageId":"1310396048-24925-2-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 01/17] advice: Introduce error_resolve_conflict","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:52Z","receivedAt":"2011-07-11T14:53:52Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Enable future callers to report a conflict and not die immediately by\nintroducing a new function called error_resolve_conflict.\nRe-implement die_resolve_conflict as a call to error_resolve_conflict\nfollowed by a call to die.  Consequently, the message printed by\ndie_resolve_conflict changes from\n\nfatal: 'commit' is not possible because you have unmerged files.\n       Please, fix them up in the work tree ...\n       ...\n\nto\n\nerror: 'commit' is not possible because you have unmerged files.\nhint: Please, fix them up in the work tree ...\nhint: ...\nfatal: Exiting because of an unresolved conflict.\n\nHints are printed using the same advise function introduced in\nv1.7.3-rc0~26^2~3 (Introduce advise() to print hints, 2010-08-11).\n\nInspired-by: Christian Couder <chistian.couder@gmail.com>\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n advice.c         |   31 ++++++++++++++++++++++++-------\n advice.h         |    3 ++-\n builtin/revert.c |    9 ---------\n 3 files changed, 26 insertions(+), 17 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex 0be4b5f..a6b3fc2 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -19,6 +19,15 @@ static struct {\n \t{ \"detachedhead\", &advice_detached_head },\n };\n \n+void advise(const char *advice, ...)\n+{\n+\tva_list params;\n+\n+\tva_start(params, advice);\n+\tvreportf(\"hint: \", advice, params);\n+\tva_end(params);\n+}\n+\n int git_default_advice_config(const char *var, const char *value)\n {\n \tconst char *k = skip_prefix(var, \"advice.\");\n@@ -34,16 +43,24 @@ int git_default_advice_config(const char *var, const char *value)\n \treturn 0;\n }\n \n-void NORETURN die_resolve_conflict(const char *me)\n+int error_resolve_conflict(const char *me)\n {\n-\tif (advice_resolve_conflict)\n+\terror(\"'%s' is not possible because you have unmerged files.\", me);\n+\tif (advice_resolve_conflict) {\n \t\t/*\n \t\t * Message used both when 'git commit' fails and when\n \t\t * other commands doing a merge do.\n \t\t */\n-\t\tdie(\"'%s' is not possible because you have unmerged files.\\n\"\n-\t\t    \"Please, fix them up in the work tree, and then use 'git add/rm <file>' as\\n\"\n-\t\t    \"appropriate to mark resolution and make a commit, or use 'git commit -a'.\", me);\n-\telse\n-\t\tdie(\"'%s' is not possible because you have unmerged files.\", me);\n+\t\tadvise(\"Please, fix them up in the work tree,\");\n+\t\tadvise(\"and then use 'git add/rm <file>' as\");\n+\t\tadvise(\"appropriate to mark resolution and make a commit,\");\n+\t\tadvise(\"or use 'git commit -a'.\");\n+\t}\n+\treturn -1;\n+}\n+\n+void NORETURN die_resolve_conflict(const char *me)\n+{\n+\terror_resolve_conflict(me);\n+\tdie(\"Exiting because of an unresolved conflict.\");\n }\ndiff --git a/advice.h b/advice.h\nindex 3244ebb..e5d0af7 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -11,7 +11,8 @@ extern int advice_implicit_identity;\n extern int advice_detached_head;\n \n int git_default_advice_config(const char *var, const char *value);\n-\n+void advise(const char *advice, ...);\n+int error_resolve_conflict(const char *me);\n extern void NORETURN die_resolve_conflict(const char *me);\n \n #endif /* ADVICE_H */\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 1f27c63..2df3f3b 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -214,15 +214,6 @@ static void write_cherry_pick_head(void)\n \tstrbuf_release(&buf);\n }\n \n-static void advise(const char *advice, ...)\n-{\n-\tva_list params;\n-\n-\tva_start(params, advice);\n-\tvreportf(\"hint: \", advice, params);\n-\tva_end(params);\n-}\n-\n static void print_advice(void)\n {\n \tchar *msg = getenv(\"GIT_CHERRY_PICK_HELP\");\n-- \n1.7.5.GIT\n"},{"id":"171055","messageId":"1310396048-24925-3-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:53Z","receivedAt":"2011-07-11T14:53:53Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The add_message_to_msg function is poorly implemented, has an unclear\nAPI, and only one callsite.  Replace the callsite with a cleaner\nimplementation.  Additionally, fix a bug introduced in 9509af6 (Make\ngit-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\nwas being incremented when \"\\n\\n\" was not found in \"message\".\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   20 ++++++--------------\n 1 files changed, 6 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 2df3f3b..f88e007 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -185,19 +185,6 @@ static char *get_encoding(const char *message)\n \treturn NULL;\n }\n \n-static void add_message_to_msg(struct strbuf *msgbuf, const char *message)\n-{\n-\tconst char *p = message;\n-\twhile (*p && (*p != '\\n' || p[1] != '\\n'))\n-\t\tp++;\n-\n-\tif (!*p)\n-\t\tstrbuf_addstr(msgbuf, sha1_to_hex(commit->object.sha1));\n-\n-\tp += 2;\n-\tstrbuf_addstr(msgbuf, p);\n-}\n-\n static void write_cherry_pick_head(void)\n {\n \tint fd;\n@@ -462,11 +449,16 @@ static int do_pick_commit(void)\n \t\t}\n \t\tstrbuf_addstr(&msgbuf, \".\\n\");\n \t} else {\n+\t\tconst char *p = strstr(msg.message, \"\\n\\n\");\n+\n \t\tbase = parent;\n \t\tbase_label = msg.parent_label;\n \t\tnext = commit;\n \t\tnext_label = msg.label;\n-\t\tadd_message_to_msg(&msgbuf, msg.message);\n+\n+\t\tp = p ? p + 2 : sha1_to_hex(commit->object.sha1);\n+\t\tstrbuf_addstr(&msgbuf, p);\n+\n \t\tif (no_replay) {\n \t\t\tstrbuf_addstr(&msgbuf, \"(cherry picked from commit \");\n \t\t\tstrbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));\n-- \n1.7.5.GIT\n"},{"id":"171056","messageId":"1310396048-24925-4-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 03/17] revert: Don't check lone argument in get_encoding","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:54Z","receivedAt":"2011-07-11T14:53:54Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The get_encoding function has only one callsite, and its caller makes\nsure that a NULL argument isn't passed.  Don't unnecessarily double\ncheck the same argument in get_encoding.\n\nSuggested-by: Jonathan Nieder <jrnieder@gmail.com>\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |    3 ---\n 1 files changed, 0 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex f88e007..6c826e1 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -167,9 +167,6 @@ static char *get_encoding(const char *message)\n {\n \tconst char *p = message, *eol;\n \n-\tif (!p)\n-\t\tdie (_(\"Could not read commit message of %s\"),\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n \twhile (*p && *p != '\\n') {\n \t\tfor (eol = p + 1; *eol && *eol != '\\n'; eol++)\n \t\t\t; /* do nothing */\n-- \n1.7.5.GIT\n"},{"id":"171070","messageId":"1310396048-24925-5-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 04/17] revert: Rename no_replay to record_origin","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:55Z","receivedAt":"2011-07-11T14:53:55Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Rename the variable corresponding to the \"-x\" command-line option from\n\"no_replay\" to a more apt \"record_origin\".\n\nSuggested-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |    8 ++++----\n 1 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 6c826e1..3d8b3a9 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -35,7 +35,7 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, no_replay, no_commit, mainline, signoff, allow_ff;\n+static int edit, record_origin, no_commit, mainline, signoff, allow_ff;\n static enum { REVERT, CHERRY_PICK } action;\n static struct commit *commit;\n static int commit_argc;\n@@ -91,7 +91,7 @@ static void parse_args(int argc, const char **argv)\n \n \tif (action == CHERRY_PICK) {\n \t\tstruct option cp_extra[] = {\n-\t\t\tOPT_BOOLEAN('x', NULL, &no_replay, \"append commit name\"),\n+\t\t\tOPT_BOOLEAN('x', NULL, &record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &allow_ff, \"allow fast-forward\"),\n \t\t\tOPT_END(),\n \t\t};\n@@ -456,7 +456,7 @@ static int do_pick_commit(void)\n \t\tp = p ? p + 2 : sha1_to_hex(commit->object.sha1);\n \t\tstrbuf_addstr(&msgbuf, p);\n \n-\t\tif (no_replay) {\n+\t\tif (record_origin) {\n \t\t\tstrbuf_addstr(&msgbuf, \"(cherry picked from commit \");\n \t\t\tstrbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));\n \t\t\tstrbuf_addstr(&msgbuf, \")\\n\");\n@@ -551,7 +551,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --signoff\"));\n \t\tif (no_commit)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --no-commit\"));\n-\t\tif (no_replay)\n+\t\tif (record_origin)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with -x\"));\n \t\tif (edit)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --edit\"));\n-- \n1.7.5.GIT\n"},{"id":"171061","messageId":"1310396048-24925-6-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 05/17] revert: Propogate errors upwards from do_pick_commit","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:56Z","receivedAt":"2011-07-11T14:53:56Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Currently, the return value from revert_or_cherry_pick is a\nnon-negative number representing the intended exit status from `git\nrevert` or `git cherry-pick`.  Change this by replacing some of the\ncalls to \"die\" with calls to \"error\", so that it can return negative\nvalues too.  Postive return values indicate conflicts, while negative\nones indicate other errors.  This return status is propogated updwards\nfrom do_pick_commit, to be finally handled in cmd_cherry_pick and\ncmd_revert.\n\nIn the same spirit, also introduce a new function error_dirty_index,\nbased on die_dirty_index, which prints some hints and returns an error\nto its caller do_pick_commit.\n\nWhile the full benefits of this patch will only be seen once all the\n\"die\" calls are replaced with calls to \"error\", its immediate impact\nis to change some of the \"die:\" messages to \"error:\" messages and\nprint a new \"fatal: cherry-pick failed\" message when the operation\nfails.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Jonathan Nieder <jrnieder@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   69 ++++++++++++++++++++++++++++-------------------------\n 1 files changed, 36 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 3d8b3a9..e2fd7b0 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -241,25 +241,20 @@ static struct tree *empty_tree(void)\n \treturn tree;\n }\n \n-static NORETURN void die_dirty_index(const char *me)\n+static int error_dirty_index(const char *me)\n {\n-\tif (read_cache_unmerged()) {\n-\t\tdie_resolve_conflict(me);\n-\t} else {\n-\t\tif (advice_commit_before_merge) {\n-\t\t\tif (action == REVERT)\n-\t\t\t\tdie(_(\"Your local changes would be overwritten by revert.\\n\"\n-\t\t\t\t\t  \"Please, commit your changes or stash them to proceed.\"));\n-\t\t\telse\n-\t\t\t\tdie(_(\"Your local changes would be overwritten by cherry-pick.\\n\"\n-\t\t\t\t\t  \"Please, commit your changes or stash them to proceed.\"));\n-\t\t} else {\n-\t\t\tif (action == REVERT)\n-\t\t\t\tdie(_(\"Your local changes would be overwritten by revert.\\n\"));\n-\t\t\telse\n-\t\t\t\tdie(_(\"Your local changes would be overwritten by cherry-pick.\\n\"));\n-\t\t}\n-\t}\n+\tif (read_cache_unmerged())\n+\t\treturn error_resolve_conflict(me);\n+\n+\t/* Different translation strings for cherry-pick and revert */\n+\tif (action == CHERRY_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+\n+\tif (advice_commit_before_merge)\n+\t\tadvise(_(\"Please, commit your changes or stash them to proceed.\"));\n+\treturn -1;\n }\n \n static int fast_forward_to(const unsigned char *to, const unsigned char *from)\n@@ -373,12 +368,12 @@ static int do_pick_commit(void)\n \t\t * to work on.\n \t\t */\n \t\tif (write_cache_as_tree(head, 0, NULL))\n-\t\t\tdie (_(\"Your index file is unmerged.\"));\n+\t\t\treturn error(_(\"Your index file is unmerged.\"));\n \t} else {\n \t\tif (get_sha1(\"HEAD\", head))\n-\t\t\tdie (_(\"You do not have a valid HEAD\"));\n+\t\t\treturn error(_(\"You do not have a valid HEAD\"));\n \t\tif (index_differs_from(\"HEAD\", 0))\n-\t\t\tdie_dirty_index(me);\n+\t\t\treturn error_dirty_index(me);\n \t}\n \tdiscard_cache();\n \n@@ -391,20 +386,20 @@ static int do_pick_commit(void)\n \t\tstruct commit_list *p;\n \n \t\tif (!mainline)\n-\t\t\tdie(_(\"Commit %s is a merge but no -m option was given.\"),\n-\t\t\t    sha1_to_hex(commit->object.sha1));\n+\t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n+\t\t\t\tsha1_to_hex(commit->object.sha1));\n \n \t\tfor (cnt = 1, p = commit->parents;\n \t\t     cnt != mainline && p;\n \t\t     cnt++)\n \t\t\tp = p->next;\n \t\tif (cnt != mainline || !p)\n-\t\t\tdie(_(\"Commit %s does not have parent %d\"),\n-\t\t\t    sha1_to_hex(commit->object.sha1), mainline);\n+\t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n+\t\t\t\tsha1_to_hex(commit->object.sha1), mainline);\n \t\tparent = p->item;\n \t} else if (0 < mainline)\n-\t\tdie(_(\"Mainline was specified but commit %s is not a merge.\"),\n-\t\t    sha1_to_hex(commit->object.sha1));\n+\t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n+\t\t\tsha1_to_hex(commit->object.sha1));\n \telse\n \t\tparent = commit->parents->item;\n \n@@ -414,12 +409,12 @@ static int do_pick_commit(void)\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\tdie(_(\"%s: cannot parse parent commit %s\"),\n-\t\t    me, sha1_to_hex(parent->object.sha1));\n+\t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n+\t\t\tme, sha1_to_hex(parent->object.sha1));\n \n \tif (get_message(commit->buffer, &msg) != 0)\n-\t\tdie(_(\"Cannot get commit message for %s\"),\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n+\t\treturn error(_(\"Cannot get commit message for %s\"),\n+\t\t\tsha1_to_hex(commit->object.sha1));\n \n \t/*\n \t * \"commit\" is an existing commit.  We would want to apply\n@@ -572,14 +567,22 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n+\tint res;\n \tif (isatty(0))\n \t\tedit = 1;\n \taction = REVERT;\n-\treturn revert_or_cherry_pick(argc, argv);\n+\tres = revert_or_cherry_pick(argc, argv);\n+\tif (res < 0)\n+\t\tdie(_(\"revert failed\"));\n+\treturn res;\n }\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n+\tint res;\n \taction = CHERRY_PICK;\n-\treturn revert_or_cherry_pick(argc, argv);\n+\tres = revert_or_cherry_pick(argc, argv);\n+\tif (res < 0)\n+\t\tdie(_(\"cherry-pick failed\"));\n+\treturn res;\n }\n-- \n1.7.5.GIT\n"},{"id":"171059","messageId":"1310396048-24925-7-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:57Z","receivedAt":"2011-07-11T14:53:57Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Since we want to develop the functionality to either pick or revert\nindividual commits atomically later in the series, make \"commit\" a\nvariable to be passed around explicitly as an argument for clarity.\nThis involves changing several functions to take an additional\nargument, but no functional changes.  Additionaly, this will permit\nmore than one commit to be cherry-picked at once, should we choose to\ndevelop this functionality in future.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   22 +++++++++++-----------\n 1 files changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e2fd7b0..840e2a3 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -37,7 +37,6 @@ static const char * const cherry_pick_usage[] = {\n \n static int edit, record_origin, no_commit, mainline, signoff, allow_ff;\n static enum { REVERT, CHERRY_PICK } action;\n-static struct commit *commit;\n static int commit_argc;\n static const char **commit_argv;\n static int allow_rerere_auto;\n@@ -116,25 +115,25 @@ struct commit_message {\n \tconst char *message;\n };\n \n-static int get_message(const char *raw_message, struct commit_message *out)\n+static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *encoding;\n \tconst char *abbrev, *subject;\n \tint abbrev_len, subject_len;\n \tchar *q;\n \n-\tif (!raw_message)\n+\tif (!commit->buffer)\n \t\treturn -1;\n-\tencoding = get_encoding(raw_message);\n+\tencoding = get_encoding(commit->buffer);\n \tif (!encoding)\n \t\tencoding = \"UTF-8\";\n \tif (!git_commit_encoding)\n \t\tgit_commit_encoding = \"UTF-8\";\n \n \tout->reencoded_message = NULL;\n-\tout->message = raw_message;\n+\tout->message = commit->buffer;\n \tif (strcmp(encoding, git_commit_encoding))\n-\t\tout->reencoded_message = reencode_string(raw_message,\n+\t\tout->reencoded_message = reencode_string(commit->buffer,\n \t\t\t\t\tgit_commit_encoding, encoding);\n \tif (out->reencoded_message)\n \t\tout->message = out->reencoded_message;\n@@ -182,7 +181,7 @@ static char *get_encoding(const char *message)\n \treturn NULL;\n }\n \n-static void write_cherry_pick_head(void)\n+static void write_cherry_pick_head(struct commit *commit)\n {\n \tint fd;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -350,7 +349,7 @@ static int run_git_commit(const char *defmsg)\n \treturn run_command_v_opt(args, RUN_GIT_CMD);\n }\n \n-static int do_pick_commit(void)\n+static int do_pick_commit(struct commit *commit)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -412,7 +411,7 @@ static int do_pick_commit(void)\n \t\treturn error(_(\"%s: cannot parse parent commit %s\"),\n \t\t\tme, sha1_to_hex(parent->object.sha1));\n \n-\tif (get_message(commit->buffer, &msg) != 0)\n+\tif (get_message(commit, &msg) != 0)\n \t\treturn error(_(\"Cannot get commit message for %s\"),\n \t\t\tsha1_to_hex(commit->object.sha1));\n \n@@ -457,7 +456,7 @@ static int do_pick_commit(void)\n \t\t\tstrbuf_addstr(&msgbuf, \")\\n\");\n \t\t}\n \t\tif (!no_commit)\n-\t\t\twrite_cherry_pick_head();\n+\t\t\twrite_cherry_pick_head(commit);\n \t}\n \n \tif (!strategy || !strcmp(strategy, \"recursive\") || action == REVERT) {\n@@ -535,6 +534,7 @@ static void read_and_refresh_cache(const char *me)\n static int revert_or_cherry_pick(int argc, const char **argv)\n {\n \tstruct rev_info revs;\n+\tstruct commit *commit;\n \n \tgit_config(git_default_config, NULL);\n \tme = action == REVERT ? \"revert\" : \"cherry-pick\";\n@@ -557,7 +557,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \tprepare_revs(&revs);\n \n \twhile ((commit = get_revision(&revs))) {\n-\t\tint res = do_pick_commit();\n+\t\tint res = do_pick_commit(commit);\n \t\tif (res)\n \t\t\treturn res;\n \t}\n-- \n1.7.5.GIT\n"},{"id":"171063","messageId":"1310396048-24925-8-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 07/17] revert: Introduce struct to keep command-line options","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:58Z","receivedAt":"2011-07-11T14:53:58Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The current code uses a set of file-scope static variables to tell the\ncherry-pick/ revert machinery how to replay the changes, and\ninitializes them by parsing the command-line arguments.  In later\nsteps in this series, we would like to introduce an API function that\ncalls into this machinery directly and have a way to tell it what to\ndo.  Hence, introduce a structure to group these variables, so that\nthe API can take them as a single replay_options parameter.\n\nThe variable \"me\" is left as a file-scope static variable because it\nis not an independent option.  \"me\" is simply a string that needs to\nbe inferred from the \"action\" option, and is kept global to save each\nfunction the trouble of determining it independently.\n\nUnfortunately, this patch introduces a minor regression.  Parsing\nstrategy-option violates a C89 rule: Initializers cannot refer to\nvariables whose address is not known at compile time.  Currently, this\nrule is violated by some other parts of Git as well, and it is\npossible to get GCC to report these instances using the \"-std=c89\n-pedantic\" option.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Jonathan Nieder <jrnieder@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |  180 ++++++++++++++++++++++++++++++------------------------\n 1 files changed, 101 insertions(+), 79 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 840e2a3..a95cfbb 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -35,76 +35,90 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, record_origin, no_commit, mainline, signoff, allow_ff;\n-static enum { REVERT, CHERRY_PICK } action;\n-static int commit_argc;\n-static const char **commit_argv;\n-static int allow_rerere_auto;\n-\n static const char *me;\n-\n-/* Merge strategy. */\n-static const char *strategy;\n-static const char **xopts;\n-static size_t xopts_nr, xopts_alloc;\n+enum replay_action { REVERT, CHERRY_PICK };\n+\n+struct replay_opts {\n+\tenum replay_action action;\n+\n+\t/* Boolean options */\n+\tint edit;\n+\tint record_origin;\n+\tint no_commit;\n+\tint signoff;\n+\tint allow_ff;\n+\tint allow_rerere_auto;\n+\n+\tint mainline;\n+\tint commit_argc;\n+\tconst char **commit_argv;\n+\n+\t/* Merge strategy */\n+\tconst char *strategy;\n+\tconst char **xopts;\n+\tsize_t xopts_nr, xopts_alloc;\n+};\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n static char *get_encoding(const char *message);\n \n-static const char * const *revert_or_cherry_pick_usage(void)\n+static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)\n {\n-\treturn action == REVERT ? revert_usage : cherry_pick_usage;\n+\treturn opts->action == REVERT ? revert_usage : cherry_pick_usage;\n }\n \n static int option_parse_x(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n+\tstruct replay_opts **opts_ptr = opt->value;\n+\tstruct replay_opts *opts = *opts_ptr;\n+\n \tif (unset)\n \t\treturn 0;\n \n-\tALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);\n-\txopts[xopts_nr++] = xstrdup(arg);\n+\tALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);\n+\topts->xopts[opts->xopts_nr++] = xstrdup(arg);\n \treturn 0;\n }\n \n-static void parse_args(int argc, const char **argv)\n+static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n {\n-\tconst char * const * usage_str = revert_or_cherry_pick_usage();\n+\tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tint noop;\n \tstruct option options[] = {\n-\t\tOPT_BOOLEAN('n', \"no-commit\", &no_commit, \"don't automatically commit\"),\n-\t\tOPT_BOOLEAN('e', \"edit\", &edit, \"edit the commit message\"),\n+\t\tOPT_BOOLEAN('n', \"no-commit\", &opts->no_commit, \"don't automatically commit\"),\n+\t\tOPT_BOOLEAN('e', \"edit\", &opts->edit, \"edit the commit message\"),\n \t\t{ OPTION_BOOLEAN, 'r', NULL, &noop, NULL, \"no-op (backward compatibility)\",\n \t\t  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 0 },\n-\t\tOPT_BOOLEAN('s', \"signoff\", &signoff, \"add Signed-off-by:\"),\n-\t\tOPT_INTEGER('m', \"mainline\", &mainline, \"parent number\"),\n-\t\tOPT_RERERE_AUTOUPDATE(&allow_rerere_auto),\n-\t\tOPT_STRING(0, \"strategy\", &strategy, \"strategy\", \"merge strategy\"),\n-\t\tOPT_CALLBACK('X', \"strategy-option\", &xopts, \"option\",\n+\t\tOPT_BOOLEAN('s', \"signoff\", &opts->signoff, \"add Signed-off-by:\"),\n+\t\tOPT_INTEGER('m', \"mainline\", &opts->mainline, \"parent number\"),\n+\t\tOPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),\n+\t\tOPT_STRING(0, \"strategy\", &opts->strategy, \"strategy\", \"merge strategy\"),\n+\t\tOPT_CALLBACK('X', \"strategy-option\", &opts, \"option\",\n \t\t\t\"option for merge strategy\", option_parse_x),\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t};\n \n-\tif (action == CHERRY_PICK) {\n+\tif (opts->action == CHERRY_PICK) {\n \t\tstruct option cp_extra[] = {\n-\t\t\tOPT_BOOLEAN('x', NULL, &record_origin, \"append commit name\"),\n-\t\t\tOPT_BOOLEAN(0, \"ff\", &allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n+\t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n \t\t\tdie(_(\"program error\"));\n \t}\n \n-\tcommit_argc = parse_options(argc, argv, NULL, options, usage_str,\n-\t\t\t\t    PARSE_OPT_KEEP_ARGV0 |\n-\t\t\t\t    PARSE_OPT_KEEP_UNKNOWN);\n-\tif (commit_argc < 2)\n+\topts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,\n+\t\t\t\t\tPARSE_OPT_KEEP_ARGV0 |\n+\t\t\t\t\tPARSE_OPT_KEEP_UNKNOWN);\n+\tif (opts->commit_argc < 2)\n \t\tusage_with_options(usage_str, options);\n \n-\tcommit_argv = argv;\n+\topts->commit_argv = argv;\n }\n \n struct commit_message {\n@@ -240,7 +254,7 @@ static struct tree *empty_tree(void)\n \treturn tree;\n }\n \n-static int error_dirty_index(const char *me)\n+static int error_dirty_index(const char *me, enum replay_action action)\n {\n \tif (read_cache_unmerged())\n \t\treturn error_resolve_conflict(me);\n@@ -269,7 +283,8 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from)\n \n static int do_recursive_merge(struct commit *base, struct commit *next,\n \t\t\t      const char *base_label, const char *next_label,\n-\t\t\t      unsigned char *head, struct strbuf *msgbuf)\n+\t\t\t      unsigned char *head, struct strbuf *msgbuf,\n+\t\t\t      struct replay_opts *opts)\n {\n \tstruct merge_options o;\n \tstruct tree *result, *next_tree, *base_tree, *head_tree;\n@@ -290,7 +305,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \tnext_tree = next ? next->tree : empty_tree();\n \tbase_tree = base ? base->tree : empty_tree();\n \n-\tfor (xopt = xopts; xopt != xopts + xopts_nr; xopt++)\n+\tfor (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)\n \t\tparse_merge_opt(&o, *xopt);\n \n \tclean = merge_trees(&o,\n@@ -330,7 +345,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\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-static int run_git_commit(const char *defmsg)\n+static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n \t/* 6 is max possible length of our args array including NULL */\n \tconst char *args[6];\n@@ -338,9 +353,9 @@ static int run_git_commit(const char *defmsg)\n \n \targs[i++] = \"commit\";\n \targs[i++] = \"-n\";\n-\tif (signoff)\n+\tif (opts->signoff)\n \t\targs[i++] = \"-s\";\n-\tif (!edit) {\n+\tif (!opts->edit) {\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n@@ -349,7 +364,7 @@ static int run_git_commit(const char *defmsg)\n \treturn run_command_v_opt(args, RUN_GIT_CMD);\n }\n \n-static int do_pick_commit(struct commit *commit)\n+static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n {\n \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -359,7 +374,7 @@ static int do_pick_commit(struct commit *commit)\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n \n-\tif (no_commit) {\n+\tif (opts->no_commit) {\n \t\t/*\n \t\t * We do not intend to commit immediately.  We just want to\n \t\t * merge the differences in, so let's compute the tree\n@@ -372,7 +387,7 @@ static int do_pick_commit(struct commit *commit)\n \t\tif (get_sha1(\"HEAD\", head))\n \t\t\treturn error(_(\"You do not have a valid HEAD\"));\n \t\tif (index_differs_from(\"HEAD\", 0))\n-\t\t\treturn error_dirty_index(me);\n+\t\t\treturn error_dirty_index(me, opts->action);\n \t}\n \tdiscard_cache();\n \n@@ -384,25 +399,25 @@ static int do_pick_commit(struct commit *commit)\n \t\tint cnt;\n \t\tstruct commit_list *p;\n \n-\t\tif (!mainline)\n+\t\tif (!opts->mainline)\n \t\t\treturn error(_(\"Commit %s is a merge but no -m option was given.\"),\n \t\t\t\tsha1_to_hex(commit->object.sha1));\n \n \t\tfor (cnt = 1, p = commit->parents;\n-\t\t     cnt != mainline && p;\n+\t\t     cnt != opts->mainline && p;\n \t\t     cnt++)\n \t\t\tp = p->next;\n-\t\tif (cnt != mainline || !p)\n+\t\tif (cnt != opts->mainline || !p)\n \t\t\treturn error(_(\"Commit %s does not have parent %d\"),\n-\t\t\t\tsha1_to_hex(commit->object.sha1), mainline);\n+\t\t\t\tsha1_to_hex(commit->object.sha1), opts->mainline);\n \t\tparent = p->item;\n-\t} else if (0 < mainline)\n+\t} else if (0 < opts->mainline)\n \t\treturn error(_(\"Mainline was specified but commit %s is not a merge.\"),\n \t\t\tsha1_to_hex(commit->object.sha1));\n \telse\n \t\tparent = commit->parents->item;\n \n-\tif (allow_ff && parent && !hashcmp(parent->object.sha1, head))\n+\tif (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))\n \t\treturn fast_forward_to(commit->object.sha1, head);\n \n \tif (parent && parse_commit(parent) < 0)\n@@ -424,7 +439,7 @@ static int do_pick_commit(struct commit *commit)\n \n \tdefmsg = git_pathdup(\"MERGE_MSG\");\n \n-\tif (action == REVERT) {\n+\tif (opts->action == REVERT) {\n \t\tbase = commit;\n \t\tbase_label = msg.label;\n \t\tnext = parent;\n@@ -450,18 +465,18 @@ static int do_pick_commit(struct commit *commit)\n \t\tp = p ? p + 2 : sha1_to_hex(commit->object.sha1);\n \t\tstrbuf_addstr(&msgbuf, p);\n \n-\t\tif (record_origin) {\n+\t\tif (opts->record_origin) {\n \t\t\tstrbuf_addstr(&msgbuf, \"(cherry picked from commit \");\n \t\t\tstrbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));\n \t\t\tstrbuf_addstr(&msgbuf, \")\\n\");\n \t\t}\n-\t\tif (!no_commit)\n+\t\tif (!opts->no_commit)\n \t\t\twrite_cherry_pick_head(commit);\n \t}\n \n-\tif (!strategy || !strcmp(strategy, \"recursive\") || action == REVERT) {\n+\tif (!opts->strategy || !strcmp(opts->strategy, \"recursive\") || opts->action == REVERT) {\n \t\tres = do_recursive_merge(base, next, base_label, next_label,\n-\t\t\t\t\t head, &msgbuf);\n+\t\t\t\t\t head, &msgbuf, opts);\n \t\twrite_message(&msgbuf, defmsg);\n \t} else {\n \t\tstruct commit_list *common = NULL;\n@@ -471,23 +486,23 @@ static int do_pick_commit(struct commit *commit)\n \n \t\tcommit_list_insert(base, &common);\n \t\tcommit_list_insert(next, &remotes);\n-\t\tres = try_merge_command(strategy, xopts_nr, xopts, common,\n-\t\t\t\t\tsha1_to_hex(head), remotes);\n+\t\tres = try_merge_command(opts->strategy, opts->xopts_nr, 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 \t}\n \n \tif (res) {\n-\t\terror(action == REVERT\n+\t\terror(opts->action == 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.sha1, DEFAULT_ABBREV),\n \t\t      msg.subject);\n \t\tprint_advice();\n-\t\trerere(allow_rerere_auto);\n+\t\trerere(opts->allow_rerere_auto);\n \t} else {\n-\t\tif (!no_commit)\n-\t\t\tres = run_git_commit(defmsg);\n+\t\tif (!opts->no_commit)\n+\t\t\tres = run_git_commit(defmsg, opts);\n \t}\n \n \tfree_message(&msg);\n@@ -496,18 +511,18 @@ static int do_pick_commit(struct commit *commit)\n \treturn res;\n }\n \n-static void prepare_revs(struct rev_info *revs)\n+static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)\n {\n \tint argc;\n \n \tinit_revisions(revs, NULL);\n \trevs->no_walk = 1;\n-\tif (action != REVERT)\n+\tif (opts->action != REVERT)\n \t\trevs->reverse = 1;\n \n-\targc = setup_revisions(commit_argc, commit_argv, revs, NULL);\n+\targc = setup_revisions(opts->commit_argc, opts->commit_argv, revs, NULL);\n \tif (argc > 1)\n-\t\tusage(*revert_or_cherry_pick_usage());\n+\t\tusage(*revert_or_cherry_pick_usage(opts));\n \n \tif (prepare_revision_walk(revs))\n \t\tdie(_(\"revision walk setup failed\"));\n@@ -516,7 +531,7 @@ static void prepare_revs(struct rev_info *revs)\n \t\tdie(_(\"empty commit set passed\"));\n }\n \n-static void read_and_refresh_cache(const char *me)\n+static void read_and_refresh_cache(const char *me, struct replay_opts *opts)\n {\n \tstatic struct lock_file index_lock;\n \tint index_fd = hold_locked_index(&index_lock, 0);\n@@ -531,33 +546,34 @@ static void read_and_refresh_cache(const char *me)\n \trollback_lock_file(&index_lock);\n }\n \n-static int revert_or_cherry_pick(int argc, const char **argv)\n+static int revert_or_cherry_pick(int argc, const char **argv,\n+\t\t\t\tstruct replay_opts *opts)\n {\n \tstruct rev_info revs;\n \tstruct commit *commit;\n \n \tgit_config(git_default_config, NULL);\n-\tme = action == REVERT ? \"revert\" : \"cherry-pick\";\n+\tme = opts->action == REVERT ? \"revert\" : \"cherry-pick\";\n \tsetenv(GIT_REFLOG_ACTION, me, 0);\n-\tparse_args(argc, argv);\n+\tparse_args(argc, argv, opts);\n \n-\tif (allow_ff) {\n-\t\tif (signoff)\n+\tif (opts->allow_ff) {\n+\t\tif (opts->signoff)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --signoff\"));\n-\t\tif (no_commit)\n+\t\tif (opts->no_commit)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --no-commit\"));\n-\t\tif (record_origin)\n+\t\tif (opts->record_origin)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with -x\"));\n-\t\tif (edit)\n+\t\tif (opts->edit)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --edit\"));\n \t}\n \n-\tread_and_refresh_cache(me);\n+\tread_and_refresh_cache(me, opts);\n \n-\tprepare_revs(&revs);\n+\tprepare_revs(&revs, opts);\n \n \twhile ((commit = get_revision(&revs))) {\n-\t\tint res = do_pick_commit(commit);\n+\t\tint res = do_pick_commit(commit, opts);\n \t\tif (res)\n \t\t\treturn res;\n \t}\n@@ -568,10 +584,13 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n \tint res;\n+\tstruct replay_opts opts;\n+\n+\tmemset(&opts, 0, sizeof(struct replay_opts));\n \tif (isatty(0))\n-\t\tedit = 1;\n-\taction = REVERT;\n-\tres = revert_or_cherry_pick(argc, argv);\n+\t\topts.edit = 1;\n+\topts.action = REVERT;\n+\tres = revert_or_cherry_pick(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -580,8 +599,11 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n \tint res;\n-\taction = CHERRY_PICK;\n-\tres = revert_or_cherry_pick(argc, argv);\n+\tstruct replay_opts opts;\n+\n+\tmemset(&opts, 0, sizeof(struct replay_opts));\n+\topts.action = CHERRY_PICK;\n+\tres = revert_or_cherry_pick(argc, argv, &opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\n-- \n1.7.5.GIT\n"},{"id":"171068","messageId":"1310396048-24925-9-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 08/17] revert: Separate cmdline parsing from functional code","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:53:59Z","receivedAt":"2011-07-11T14:53:59Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Currently, revert_or_cherry_pick does too many things including\nargument parsing and setting up to pick the commits; this doesn't make\na good API.  Simplify and rename the function to pick_commits, so that\nit just has the responsibility of setting up the revision walker and\ncalling do_pick_commit in a loop.  Transfer the remaining work to its\ncallers cmd_cherry_pick and cmd_revert.  Later in the series,\npick_commits will serve as the starting point for continuing the\ncherry-pick or revert.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   17 +++++++++--------\n 1 files changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex a95cfbb..da55ba4 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -546,17 +546,12 @@ static void read_and_refresh_cache(const char *me, struct replay_opts *opts)\n \trollback_lock_file(&index_lock);\n }\n \n-static int revert_or_cherry_pick(int argc, const char **argv,\n-\t\t\t\tstruct replay_opts *opts)\n+static int pick_commits(struct replay_opts *opts)\n {\n \tstruct rev_info revs;\n \tstruct commit *commit;\n \n-\tgit_config(git_default_config, NULL);\n-\tme = opts->action == REVERT ? \"revert\" : \"cherry-pick\";\n \tsetenv(GIT_REFLOG_ACTION, me, 0);\n-\tparse_args(argc, argv, opts);\n-\n \tif (opts->allow_ff) {\n \t\tif (opts->signoff)\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --signoff\"));\n@@ -590,7 +585,10 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \tif (isatty(0))\n \t\topts.edit = 1;\n \topts.action = REVERT;\n-\tres = revert_or_cherry_pick(argc, argv, &opts);\n+\tgit_config(git_default_config, NULL);\n+\tme = \"revert\";\n+\tparse_args(argc, argv, &opts);\n+\tres = pick_commits(&opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -603,7 +601,10 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \n \tmemset(&opts, 0, sizeof(struct replay_opts));\n \topts.action = CHERRY_PICK;\n-\tres = revert_or_cherry_pick(argc, argv, &opts);\n+\tgit_config(git_default_config, NULL);\n+\tme = \"cherry-pick\";\n+\tparse_args(argc, argv, &opts);\n+\tres = pick_commits(&opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\n-- \n1.7.5.GIT\n"},{"id":"171057","messageId":"1310396048-24925-10-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:00Z","receivedAt":"2011-07-11T14:54:00Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The \"--ff\" command-line option cannot be used with four other\ncommand-line options.  However, parse_args still parses these\nincompatible options into a replay_opts structure for use by the rest\nof the program.  Although pick_commits, the current gatekeeper to the\ncherry-pick machinery, checks the validity of the replay_opts\nstructure before before starting its operation, there will be multiple\nentry points to the cherry-pick machinery in future.  To futureproof\nthe code and catch these errors in one place, make sure that an\ninvalid replay_opts structure is not created by parse_args in the\nfirst place.  Also ensure that regressions in maintaining this\ninvariant are caught in the future by adding an assertion in\npick_commits.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Jonathan Nieder <jrnieder@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   37 ++++++++++++++++++++++++++-----------\n 1 files changed, 26 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex da55ba4..ef5b097 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -82,6 +82,22 @@ static int option_parse_x(const struct option *opt,\n \treturn 0;\n }\n \n+static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n+{\n+\tconst char *this_opt;\n+\tva_list ap;\n+\tint set;\n+\n+\tva_start(ap, base_opt);\n+\twhile ((this_opt = va_arg(ap, const char *))) {\n+\t\tset = va_arg(ap, int);\n+\t\tif (set)\n+\t\t\tdie(_(\"%s: %s cannot be used with %s\"),\n+\t\t\t\tme, this_opt, base_opt);\n+\t}\n+\tva_end(ap);\n+}\n+\n static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n@@ -118,6 +134,13 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \tif (opts->commit_argc < 2)\n \t\tusage_with_options(usage_str, options);\n \n+\tif (opts->allow_ff)\n+\t\tverify_opt_compatible(me, \"--ff\",\n+\t\t\t\t\"--signoff\", opts->signoff,\n+\t\t\t\t\"--no-commit\", opts->no_commit,\n+\t\t\t\t\"-x\", opts->record_origin,\n+\t\t\t\t\"--edit\", opts->edit,\n+\t\t\t\tNULL);\n \topts->commit_argv = argv;\n }\n \n@@ -552,17 +575,9 @@ static int pick_commits(struct replay_opts *opts)\n \tstruct commit *commit;\n \n \tsetenv(GIT_REFLOG_ACTION, me, 0);\n-\tif (opts->allow_ff) {\n-\t\tif (opts->signoff)\n-\t\t\tdie(_(\"cherry-pick --ff cannot be used with --signoff\"));\n-\t\tif (opts->no_commit)\n-\t\t\tdie(_(\"cherry-pick --ff cannot be used with --no-commit\"));\n-\t\tif (opts->record_origin)\n-\t\t\tdie(_(\"cherry-pick --ff cannot be used with -x\"));\n-\t\tif (opts->edit)\n-\t\t\tdie(_(\"cherry-pick --ff cannot be used with --edit\"));\n-\t}\n-\n+\tif (opts->allow_ff)\n+\t\tassert(!(opts->signoff || opts->no_commit ||\n+\t\t\t\topts->record_origin || opts->edit));\n \tread_and_refresh_cache(me, opts);\n \n \tprepare_revs(&revs, opts);\n-- \n1.7.5.GIT\n"},{"id":"171058","messageId":"1310396048-24925-11-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:01Z","receivedAt":"2011-07-11T14:54:01Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The plan to build a generic sequencer involves fist writing the\nfunctionality into builtin/revert.c (for cherry-pick and revert), and\nthen factoring it out into sequencer.c and exposing it through\nsequencer.h as a nice API.  As a prelude to this, announce the\nlocation of the sequencer state in sequencer.h and write a function to\nremove it.  Later in the series, two indepenent Git programs, namely\ncherry-pick/ revert and reset, will use this to save and clear\nsequencer state in a uniform manner.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Makefile    |    2 ++\n sequencer.c |   17 +++++++++++++++++\n sequencer.h |   14 ++++++++++++++\n 3 files changed, 33 insertions(+), 0 deletions(-)\n create mode 100644 sequencer.c\n create mode 100644 sequencer.h\n\ndiff --git a/Makefile b/Makefile\nindex f8c72e1..4ac09df 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -551,6 +551,7 @@ LIB_H += rerere.h\n LIB_H += resolve-undo.h\n LIB_H += revision.h\n LIB_H += run-command.h\n+LIB_H += sequencer.h\n LIB_H += sha1-array.h\n LIB_H += sha1-lookup.h\n LIB_H += sideband.h\n@@ -655,6 +656,7 @@ LIB_OBJS += revision.o\n LIB_OBJS += run-command.o\n LIB_OBJS += server-info.o\n LIB_OBJS += setup.o\n+LIB_OBJS += sequencer.o\n LIB_OBJS += sha1-array.o\n LIB_OBJS += sha1-lookup.o\n LIB_OBJS += sha1_file.o\ndiff --git a/sequencer.c b/sequencer.c\nnew file mode 100644\nindex 0000000..8c1de63\n--- /dev/null\n+++ b/sequencer.c\n@@ -0,0 +1,17 @@\n+#include \"cache.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+#include \"dir.h\"\n+\n+void remove_sequencer_state(void)\n+{\n+\tstruct strbuf seq_dir = STRBUF_INIT;\n+\tstruct strbuf seq_old_dir = STRBUF_INIT;\n+\n+\tstrbuf_addf(&seq_dir, \"%s\", git_path(SEQ_DIR));\n+\tstrbuf_addf(&seq_old_dir, \"%s\", git_path(SEQ_OLD_DIR));\n+\tremove_dir_recursively(&seq_old_dir, 0);\n+\trename(git_path(SEQ_DIR), git_path(SEQ_OLD_DIR));\n+\tstrbuf_release(&seq_dir);\n+\tstrbuf_release(&seq_old_dir);\n+}\ndiff --git a/sequencer.h b/sequencer.h\nnew file mode 100644\nindex 0000000..673616b\n--- /dev/null\n+++ b/sequencer.h\n@@ -0,0 +1,14 @@\n+#ifndef SEQUENCER_H\n+#define SEQUENCER_H\n+\n+#define SEQ_DIR\t\t\"sequencer\"\n+#define SEQ_OLD_DIR\t\"sequencer-old\"\n+#define SEQ_HEAD_FILE\t\"sequencer/head\"\n+#define SEQ_TODO_FILE\t\"sequencer/todo\"\n+\n+/* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring\n+ * any errors.  Intended to be used by 'git reset --hard'.\n+ */\n+void remove_sequencer_state(void);\n+\n+#endif\n-- \n1.7.5.GIT\n"},{"id":"171060","messageId":"1310396048-24925-12-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:02Z","receivedAt":"2011-07-11T14:54:02Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Ever since v1.7.2-rc1~4^2~7 (revert: allow cherry-picking more than\none commit, 2010-06-02), a single invocation of \"git cherry-pick\" or\n\"git revert\" can perform picks of several individual commits.  To\nimplement features like \"--continue\" to continue the whole operation,\nwe will need to store some information about the state and the plan at\nthe beginning.  Introduce a \".git/sequencer/head\" file to store this\nstate, and \".git/sequencer/todo\" file to store the plan.  The head\nfile contains the SHA-1 of the HEAD before the start of the operation,\nand the todo file contains an instruction sheet whose format is\ninspired by the format of the \"rebase -i\" instruction sheet.  As a\nresult, a typical todo file looks like:\n\npick 8537f0e submodule add: test failure when url is not configured\npick 4d68932 submodule add: allow relative repository path\npick f22a17e submodule add: clean up duplicated code\npick 59a5775 make copy_ref globally available\n\nSince SHA-1 hex is abbreviated using an find_unique_abbrev(), it is\nunambiguous.  This does not guarantee that there will be no ambiguity\nwhen more objects are added to the repository.\n\nIt is imperative to note that these two files alone are not enough to\nimplement \"--continue\"; we will also need to persist the options that\nwere specified on the command-line, and this is done later in the\nseries.\n\nThese new files are unrelated to the existing .git/CHERRY_PICK_HEAD,\nwhich will still be useful while committing after a conflict\nresolution.\n\nInspired-by: Christian Couder <chriscool@tuxfamily.org>\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c                |  202 ++++++++++++++++++++++++++++++++++++++-\n t/t3510-cherry-pick-sequence.sh |   48 +++++++++\n 2 files changed, 246 insertions(+), 4 deletions(-)\n create mode 100755 t/t3510-cherry-pick-sequence.sh\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex ef5b097..856ee97 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -13,6 +13,8 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"dir.h\"\n+#include \"sequencer.h\"\n \n /*\n  * This implements the builtins revert and cherry-pick.\n@@ -569,10 +571,192 @@ static void read_and_refresh_cache(const char *me, struct replay_opts *opts)\n \trollback_lock_file(&index_lock);\n }\n \n-static int pick_commits(struct replay_opts *opts)\n+/* Insert into todo_list in same order; commit_list_insert reverses\n+ * the order\n+ *\n+ * Usage example:\n+ *\n+ *     struct commit_list *list;\n+ *     struct commit_list **next = &list;\n+ *\n+ *     next = commit_list_append(c1, next);\n+ *     next = commit_list_append(c2, next);\n+ *     *next = NULL;\n+ *     assert(commit_list_count(list) == 2);\n+ *     return list;\n+ *\n+ * Don't forget to NULL-terminate!\n+ */\n+struct commit_list **commit_list_append(struct commit *commit,\n+\t\t\t\t\tstruct commit_list **next)\n+{\n+\tstruct commit_list *new = xmalloc(sizeof(struct commit_list));\n+\tnew->item = commit;\n+\t*next = new;\n+\treturn &new->next;\n+}\n+\n+static void format_todo(struct strbuf *buf, struct commit_list *todo_list,\n+\t\t\tstruct replay_opts *opts)\n+{\n+\tstruct commit_list *cur = NULL;\n+\tstruct commit_message msg = { NULL, NULL, NULL, NULL, NULL };\n+\tconst char *sha1_abbrev = NULL;\n+\tconst char *action;\n+\n+\taction = (opts->action == REVERT ? \"revert\" : \"pick\");\n+\tfor (cur = todo_list; cur; cur = cur->next) {\n+\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);\n+\t\tif (get_message(cur->item, &msg))\n+\t\t\tdie(_(\"Cannot get commit message for %s\"), sha1_abbrev);\n+\t\tstrbuf_addf(buf, \"%s %s %s\\n\", action, sha1_abbrev, msg.subject);\n+\t}\n+}\n+\n+static struct commit *parse_insn_line(char *start, struct replay_opts *opts)\n+{\n+\tunsigned char commit_sha1[20];\n+\tchar sha1_abbrev[40];\n+\tstruct commit *commit;\n+\tenum replay_action action;\n+\tint insn_len = 0;\n+\tchar *p;\n+\n+\tp = start;\n+\tif (!(p = strchr(p, ' ')))\n+\t\treturn NULL;\n+\tinsn_len = p - start;\n+\tif (!(p = strchr(p + 1, ' ')))\n+\t\treturn NULL;\n+\tp += 1;\n+\tstrlcpy(sha1_abbrev, start + insn_len + 1,\n+\t\tp - (start + insn_len + 1));\n+\n+\tif (!strncmp(start, \"pick\", insn_len))\n+\t\taction = CHERRY_PICK;\n+\telse if (!strncmp(start, \"revert\", insn_len))\n+\t\taction = REVERT;\n+\telse\n+\t\treturn NULL;\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\treturn NULL;\n+\n+\tif ((get_sha1(sha1_abbrev, commit_sha1) < 0)\n+\t\t|| !(commit = lookup_commit_reference(commit_sha1)))\n+\t\treturn NULL;\n+\n+\treturn commit;\n+}\n+\n+static void read_populate_todo(struct commit_list **todo_list,\n+\t\t\tstruct replay_opts *opts)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct commit_list *new;\n+\tstruct commit_list **next;\n+\tstruct commit *commit;\n+\tchar *p;\n+\tint fd;\n+\n+\tfd = open(git_path(SEQ_TODO_FILE), O_RDONLY);\n+\tif (fd < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\tdie_errno(_(\"Could not open %s.\"), git_path(SEQ_TODO_FILE));\n+\t}\n+\tif (strbuf_read(&buf, fd, 0) < buf.len) {\n+\t\tclose(fd);\n+\t\tstrbuf_release(&buf);\n+\t\tdie(_(\"Could not read %s.\"), git_path(SEQ_TODO_FILE));\n+\t}\n+\tclose(fd);\n+\n+\tnext = todo_list;\n+\tfor (p = buf.buf; *p; p = strchr(p, '\\n') + 1) {\n+\t\tif (!(commit = parse_insn_line(p, opts)))\n+\t\t\tgoto error;\n+\t\tnew = xmalloc(sizeof(struct commit_list));\n+\t\tnew->item = commit;\n+\t\t*next = new;\n+\t\tnext = &new->next;\n+\t}\n+\t*next = NULL;\n+\tif (!*todo_list)\n+\t\tgoto error;\n+\tstrbuf_release(&buf);\n+\treturn;\n+error:\n+\tstrbuf_release(&buf);\n+\tdie(_(\"Malformed instruction sheet: %s\"), git_path(SEQ_TODO_FILE));\n+}\n+\n+static void walk_revs_populate_todo(struct commit_list **todo_list,\n+\t\t\t\tstruct replay_opts *opts)\n {\n \tstruct rev_info revs;\n \tstruct commit *commit;\n+\tstruct commit_list **next;\n+\n+\tprepare_revs(&revs, opts);\n+\n+\tnext = todo_list;\n+\twhile ((commit = get_revision(&revs)))\n+\t\tnext = commit_list_append(commit, next);\n+\t*next = NULL;\n+}\n+\n+static void create_seq_dir(void)\n+{\n+\tif (file_exists(git_path(SEQ_DIR))) {\n+\t\tif (!is_directory(git_path(SEQ_DIR)) && remove_path(git_path(SEQ_DIR)) < 0)\n+\t\t\tdie(_(\"Could not remove %s\"), git_path(SEQ_DIR));\n+\t} else if (mkdir(git_path(SEQ_DIR), 0777) < 0)\n+\t\tdie_errno(_(\"Could not create sequencer directory '%s'.\"), git_path(SEQ_DIR));\n+}\n+\n+static void save_head(const char *head)\n+{\n+\tstatic struct lock_file head_lock;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint fd;\n+\n+\tfd = hold_lock_file_for_update(&head_lock, git_path(SEQ_HEAD_FILE), LOCK_DIE_ON_ERROR);\n+\tstrbuf_addf(&buf, \"%s\\n\", head);\n+\tif (write_in_full(fd, buf.buf, buf.len) < 0)\n+\t\tdie_errno(_(\"Could not write to %s.\"), git_path(SEQ_HEAD_FILE));\n+\tif (commit_lock_file(&head_lock) < 0)\n+\t\tdie(_(\"Error wrapping up %s\"), git_path(SEQ_HEAD_FILE));\n+}\n+\n+static void save_todo(struct commit_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+\n+\tfd = hold_lock_file_for_update(&todo_lock, git_path(SEQ_TODO_FILE), LOCK_DIE_ON_ERROR);\n+\tformat_todo(&buf, todo_list, opts);\n+\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\tdie_errno(_(\"Could not write to %s.\"), git_path(SEQ_TODO_FILE));\n+\t}\n+\tif (commit_lock_file(&todo_lock) < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\tdie(_(\"Error wrapping up %s\"), git_path(SEQ_TODO_FILE));\n+\t}\n+\tstrbuf_release(&buf);\n+}\n+\n+static int pick_commits(struct replay_opts *opts)\n+{\n+\tstruct commit_list *todo_list = NULL;\n+\tunsigned char sha1[20];\n+\tstruct commit_list *cur;\n+\tint res;\n \n \tsetenv(GIT_REFLOG_ACTION, me, 0);\n \tif (opts->allow_ff)\n@@ -580,14 +764,24 @@ static int pick_commits(struct replay_opts *opts)\n \t\t\t\topts->record_origin || opts->edit));\n \tread_and_refresh_cache(me, opts);\n \n-\tprepare_revs(&revs, opts);\n+\twalk_revs_populate_todo(&todo_list, opts);\n+\tcreate_seq_dir();\n+\tif (!get_sha1(\"HEAD\", sha1))\n+\t\tsave_head(sha1_to_hex(sha1));\n+\tsave_todo(todo_list, opts);\n \n-\twhile ((commit = get_revision(&revs))) {\n-\t\tint res = do_pick_commit(commit, opts);\n+\tfor (cur = todo_list; cur; cur = cur->next) {\n+\t\tsave_todo(cur, opts);\n+\t\tres = do_pick_commit(cur->item, opts);\n \t\tif (res)\n \t\t\treturn res;\n \t}\n \n+\t/*\n+\t * Sequence of picks finished successfully; cleanup by\n+\t * removing the .git/sequencer directory\n+\t */\n+\tremove_sequencer_state();\n \treturn 0;\n }\n \ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nnew file mode 100755\nindex 0000000..64eaa20\n--- /dev/null\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -0,0 +1,48 @@\n+#!/bin/sh\n+\n+test_description='Test cherry-pick continuation features\n+\n+  + anotherpick: rewrites foo to d\n+  + picked: rewrites foo to c\n+  + unrelatedpick: rewrites unrelated to reallyunrelated\n+  + base: rewrites foo to b\n+  + initial: writes foo as a, unrelated as unrelated\n+\n+'\n+\n+. ./test-lib.sh\n+\n+pristine_detach () {\n+\tgit checkout -f \"$1^0\" &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x\n+}\n+\n+test_expect_success setup '\n+\techo unrelated >unrelated &&\n+\tgit add unrelated &&\n+\ttest_commit initial foo a &&\n+\ttest_commit base foo b &&\n+\ttest_commit unrelatedpick unrelated reallyunrelated &&\n+\ttest_commit picked foo c &&\n+\ttest_commit anotherpick foo d &&\n+\tgit config advice.detachedhead false\n+\n+'\n+\n+test_expect_success 'cherry-pick persists data on failure' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick base..anotherpick &&\n+\ttest_path_is_dir .git/sequencer &&\n+\ttest_path_is_file .git/sequencer/head &&\n+\ttest_path_is_file .git/sequencer/todo &&\n+\trm -rf .git/sequencer\n+'\n+\n+test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n+\tpristine_detach initial &&\n+\tgit cherry-pick initial..picked &&\n+\ttest_path_is_missing .git/sequencer\n+'\n+\n+test_done\n-- \n1.7.5.GIT\n"},{"id":"171065","messageId":"1310396048-24925-13-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 12/17] revert: Save command-line options for continuing operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:03Z","receivedAt":"2011-07-11T14:54:03Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"In the same spirit as \".git/sequencer/head\" and \".git/sequencer/todo\",\nintroduce \".git/sequencer/opts\" to persist the replay_opts structure\nfor continuing after a conflict resolution.  Use a simple \"key =\nvalue\" format for this file, using \"|\" to separate multiple values so\nthat the file looks like:\n\nsignoff = true\nrecord-origin = true\nmainline = 1\nstrategy = recursive\nstrategy-option = patience | ours\n\nWrite the file just after writing \".git/sequencer/head\", and parse it\nout just after parsing out \".git/sequencer/head\".  There is now enough\ndata for \"--continue\" to work.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c                |  226 +++++++++++++++++++++++++++++++++++++++\n sequencer.h                     |    1 +\n t/t3510-cherry-pick-sequence.sh |   20 ++++-\n 3 files changed, 246 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 856ee97..edf74fb 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -596,6 +596,32 @@ struct commit_list **commit_list_append(struct commit *commit,\n \treturn &new->next;\n }\n \n+static void format_opts(struct strbuf *buf, struct replay_opts *opts)\n+{\n+\tint i;\n+\n+\tif (opts->no_commit)\n+\t\tstrbuf_addstr(buf, \"no-commit = true\\n\");\n+\tif (opts->edit)\n+\t\tstrbuf_addstr(buf, \"edit = true\\n\");\n+\tif (opts->signoff)\n+\t\tstrbuf_addstr(buf, \"signoff = true\\n\");\n+\tif (opts->record_origin)\n+\t\tstrbuf_addstr(buf, \"record-origin = true\\n\");\n+\tif (opts->allow_ff)\n+\t\tstrbuf_addstr(buf, \"ff = true\\n\");\n+\tif (opts->mainline)\n+\t\tstrbuf_addf(buf, \"mainline = %d\\n\", opts->mainline);\n+\tif (opts->strategy)\n+\t\tstrbuf_addf(buf, \"strategy = %s\\n\", opts->strategy);\n+\tif (opts->xopts) {\n+\t\tstrbuf_addf(buf, \"strategy-option = \");\n+\t\tfor (i = 0; i < opts->xopts_nr - 1; i ++)\n+\t\t\tstrbuf_addf(buf, \"%s | \", opts->xopts[i]);\n+\t\tstrbuf_addf(buf, \"%s\\n\", opts->xopts[i]);\n+\t}\n+}\n+\n static void format_todo(struct strbuf *buf, struct commit_list *todo_list,\n \t\t\tstruct replay_opts *opts)\n {\n@@ -694,6 +720,184 @@ error:\n \tdie(_(\"Malformed instruction sheet: %s\"), git_path(SEQ_TODO_FILE));\n }\n \n+static struct strbuf *parse_value(const char *start, char **end_ptr)\n+{\n+\tstatic struct strbuf value = STRBUF_INIT;\n+\tint quote = 0;\n+\tchar *p = (char *)start;\n+\tchar *end;\n+\n+\t/* Find and strip '\\n', '\\r' */\n+\tif ((end = strchr(start, '\\n'))) {\n+\t\t*end = '\\0'; /* Remove trailing '\\n' */\n+\t\tif (*(end - 1) == '\\r')\n+\t\t\t*(end - 1) = '\\0'; /* Remove trailing '\\r' */\n+\t} else if (strchr(start, '\\0'))\n+\t\tend = NULL;\n+\telse\n+\t\tgoto error;\n+\n+\tfor (; *p != '\\0'; p ++) {\n+\t\tif (!quote && (*p == ';' || *p == '#'))\n+\t\t\t/* Ignore comments */\n+\t\t\tgoto ok;\n+\t\tif (*p == '\\\\') {\n+\t\t\tp += 1;\n+\t\t\tswitch (*p) {\n+\t\t\tcase '\\n':\n+\t\t\t\tcontinue;\n+\t\t\tcase 't':\n+\t\t\t\tstrbuf_addch(&value, '\\t');\n+\t\t\t\tbreak;\n+\t\t\tcase 'b':\n+\t\t\t\tstrbuf_addch(&value, '\\b');\n+\t\t\t\tbreak;\n+\t\t\tcase 'n':\n+\t\t\t\tstrbuf_addch(&value, '\\n');\n+\t\t\t\tbreak;\n+\t\t\t/* Some pharapters escape as themselves */\n+\t\t\tcase '\\\\': case '\"':\n+\t\t\t\tbreak;\n+\t\t\t/* Reject unknown escape sequences */\n+\t\t\tdefault:\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (*p == '\"') {\n+\t\t\tquote = 1 - quote;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tstrbuf_addch(&value, *p);\n+\t}\n+\t/* Quote not closed */\n+\tif (quote)\n+\t\tgoto error;\n+\n+\tif (end)\n+\t\t*end_ptr = end + 1;\n+\telse\n+\t\t*end_ptr = NULL;\n+ok:\n+\tstrbuf_trim(&value);\n+\treturn &value;\n+error:\n+\tstrbuf_release(&value);\n+\treturn NULL;\n+}\n+\n+static char *parse_opt_value(const char *start, void *key,\n+\t\t\tenum parse_opt_type type, parse_opt_cb *cb_function)\n+{\n+\tstruct strbuf *value, *subvalue;\n+\tstruct option opt;\n+\tchar *p, *cur, *val, *end;\n+\n+\t/* Remove spaces before '=' */\n+\tfor (p = (char *)start; isspace(*p); p++);\n+\tif (*p != '=')\n+\t\tgoto error;\n+\n+\tif (!(value = parse_value(p + 1, &end)))\n+\t\tgoto error;\n+\tval = value->buf;\n+\n+\tswitch (type) {\n+\tcase OPTION_BOOLEAN:\n+\t\tif (!strcasecmp(val, \"true\")\n+\t\t\t|| !strcasecmp(val, \"yes\")\n+\t\t\t|| !strcasecmp(val, \"on\"))\n+\t\t\t*(int *)key = 1;\n+\t\telse if (!strcasecmp(val, \"false\")\n+\t\t\t|| !strcasecmp(val, \"no\")\n+\t\t\t|| !strcasecmp(val, \"off\"))\n+\t\t\t*(int *)key = 0;\n+\t\telse\n+\t\t\tgoto error;\n+\t\tbreak;\n+\tcase OPTION_INTEGER:\n+\t\t*(int *)key = strtol(val, NULL, 10);\n+\t\tbreak;\n+\tcase OPTION_STRING:\n+\t\t*(char **)key = xstrdup(val);\n+\t\tbreak;\n+\tcase OPTION_CALLBACK:\n+\t\topt.value = (struct replay_opts **)key;\n+\t\twhile (val) {\n+\t\t\tif ((cur = strchr(val, '|'))) {\n+\t\t\t\t*cur = '\\0';\n+\t\t\t\tsubvalue = parse_value(val, &end);\n+\t\t\t\t(*cb_function)(&opt, subvalue->buf, 0);\n+\t\t\t\tstrbuf_release(subvalue);\n+\t\t\t\tval = cur + 1;\n+\t\t\t} else {\n+\t\t\t\t(*cb_function)(&opt, val, 0);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"program error\"));\n+\t}\n+\tstrbuf_release(value);\n+\treturn end;\n+error:\n+\tdie(_(\"Malformed options sheet: %s\"), git_path(SEQ_OPTS_FILE));\n+}\n+\n+static void read_populate_opts(struct replay_opts **opts_ptr)\n+{\n+\tstruct replay_opts *opts = *opts_ptr;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tchar *p;\n+\tint fd;\n+\n+\tfd = open(git_path(SEQ_OPTS_FILE), O_RDONLY);\n+\tif (fd < 0)\n+\t\tgoto ok;\n+\tif (strbuf_read(&buf, fd, 0) < buf.len) {\n+\t\tclose(fd);\n+\t\tstrbuf_release(&buf);\n+\t\tdie(_(\"Could not read %s.\"), git_path(SEQ_OPTS_FILE));\n+\t}\n+\tclose(fd);\n+\n+\tfor (p = buf.buf; p && *p != '\\0';) {\n+\t\tif (!prefixcmp(p, \"no-commit\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"no-commit\"),\n+\t\t\t\t\t&opts->no_commit, OPTION_BOOLEAN, NULL);\n+\t\telse if (!prefixcmp(p, \"edit\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"edit\"),\n+\t\t\t\t\t&opts->edit, OPTION_BOOLEAN, NULL);\n+\t\telse if (!prefixcmp(p, \"signoff\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"signoff\"),\n+\t\t\t\t\t&opts->signoff, OPTION_BOOLEAN, NULL);\n+\t\telse if (!prefixcmp(p, \"mainline\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"mainline\"),\n+\t\t\t\t\t&opts->mainline, OPTION_INTEGER, NULL);\n+\t\telse if (!prefixcmp(p, \"record-origin\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"record-origin\"),\n+\t\t\t\t\t&opts->record_origin, OPTION_BOOLEAN, NULL);\n+\t\telse if (!prefixcmp(p, \"ff\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"ff\"),\n+\t\t\t\t\t&opts->allow_ff, OPTION_BOOLEAN, NULL);\n+\t\telse if (!prefixcmp(p, \"strategy-option\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"strategy-option\"),\n+\t\t\t\t\t&opts, OPTION_CALLBACK, option_parse_x);\n+\t\telse if (!prefixcmp(p, \"strategy\"))\n+\t\t\tp = parse_opt_value(p + strlen(\"strategy\"),\n+\t\t\t\t\t&opts->strategy, OPTION_STRING, NULL);\n+\t\telse\n+\t\t\tgoto error;\n+\t}\n+ok:\n+\tstrbuf_release(&buf);\n+\treturn;\n+error:\n+\tstrbuf_release(&buf);\n+\tdie(_(\"Malformed options sheet: %s\"), git_path(SEQ_OPTS_FILE));\n+}\n+\n static void walk_revs_populate_todo(struct commit_list **todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\n@@ -751,6 +955,27 @@ static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n \tstrbuf_release(&buf);\n }\n \n+static void save_opts(struct replay_opts *opts)\n+{\n+\tstatic struct lock_file opts_lock;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint fd;\n+\n+\tfd = hold_lock_file_for_update(&opts_lock, git_path(SEQ_OPTS_FILE), LOCK_DIE_ON_ERROR);\n+\tformat_opts(&buf, opts);\n+\tif (!buf.len)\n+\t\treturn;\n+\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\tdie_errno(_(\"Could not write to %s.\"), git_path(SEQ_OPTS_FILE));\n+\t}\n+\tif (commit_lock_file(&opts_lock) < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\tdie(_(\"Error wrapping up %s\"), git_path(SEQ_OPTS_FILE));\n+\t}\n+\tstrbuf_release(&buf);\n+}\n+\n static int pick_commits(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n@@ -768,6 +993,7 @@ static int pick_commits(struct replay_opts *opts)\n \tcreate_seq_dir();\n \tif (!get_sha1(\"HEAD\", sha1))\n \t\tsave_head(sha1_to_hex(sha1));\n+\tsave_opts(opts);\n \tsave_todo(todo_list, opts);\n \n \tfor (cur = todo_list; cur; cur = cur->next) {\ndiff --git a/sequencer.h b/sequencer.h\nindex 673616b..dcb51b1 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -5,6 +5,7 @@\n #define SEQ_OLD_DIR\t\"sequencer-old\"\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 \n /* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring\n  * any errors.  Intended to be used by 'git reset --hard'.\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 64eaa20..100cbb1 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -32,10 +32,28 @@ test_expect_success setup '\n \n test_expect_success 'cherry-pick persists data on failure' '\n \tpristine_detach initial &&\n-\ttest_must_fail git cherry-pick base..anotherpick &&\n+\ttest_must_fail git cherry-pick -s base..anotherpick &&\n \ttest_path_is_dir .git/sequencer &&\n \ttest_path_is_file .git/sequencer/head &&\n \ttest_path_is_file .git/sequencer/todo &&\n+\ttest_path_is_file .git/sequencer/opts &&\n+\trm -rf .git/sequencer\n+'\n+\n+test_expect_success 'cherry-pick persists opts correctly' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&\n+\ttest_path_is_dir .git/sequencer &&\n+\ttest_path_is_file .git/sequencer/head &&\n+\ttest_path_is_file .git/sequencer/todo &&\n+\ttest_path_is_file .git/sequencer/opts &&\n+\tcat >expect <<-\\EOF &&\n+\tsignoff = true\n+\tmainline = 1\n+\tstrategy = recursive\n+\tstrategy-option = patience | ours\n+\tEOF\n+\ttest_cmp expect .git/sequencer/opts &&\n \trm -rf .git/sequencer\n '\n \n-- \n1.7.5.GIT\n"},{"id":"171064","messageId":"1310396048-24925-14-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 13/17] revert: Introduce a layer of indirection over pick_commits","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:04Z","receivedAt":"2011-07-11T14:54:04Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Write a new function called process_subcommand to prepare a todo_list\nto call pick_commits with; the job of pick_commits is simplified into\nperforming the tasks listed in todo_list.  This will be useful when\nsubcommands like \"--reset\" and \"--continue\" are introduced later in\nthe series.\n\nHelped-by: Jonathan Nieder <jrnider@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   38 ++++++++++++++++++++++++++------------\n 1 files changed, 26 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex edf74fb..f9f5e3a 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -976,10 +976,8 @@ static void save_opts(struct replay_opts *opts)\n \tstrbuf_release(&buf);\n }\n \n-static int pick_commits(struct replay_opts *opts)\n+static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n {\n-\tstruct commit_list *todo_list = NULL;\n-\tunsigned char sha1[20];\n \tstruct commit_list *cur;\n \tint res;\n \n@@ -989,13 +987,6 @@ static int pick_commits(struct replay_opts *opts)\n \t\t\t\topts->record_origin || opts->edit));\n \tread_and_refresh_cache(me, opts);\n \n-\twalk_revs_populate_todo(&todo_list, opts);\n-\tcreate_seq_dir();\n-\tif (!get_sha1(\"HEAD\", sha1))\n-\t\tsave_head(sha1_to_hex(sha1));\n-\tsave_opts(opts);\n-\tsave_todo(todo_list, opts);\n-\n \tfor (cur = todo_list; cur; cur = cur->next) {\n \t\tsave_todo(cur, opts);\n \t\tres = do_pick_commit(cur->item, opts);\n@@ -1011,6 +1002,23 @@ static int pick_commits(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static int process_subcommand(struct replay_opts *opts)\n+{\n+\tstruct commit_list *todo_list = NULL;\n+\tunsigned char sha1[20];\n+\n+\tread_and_refresh_cache(me, opts);\n+\n+\twalk_revs_populate_todo(&todo_list, opts);\n+\tcreate_seq_dir();\n+\tif (!get_sha1(\"HEAD\", sha1))\n+\t\tsave_head(sha1_to_hex(sha1));\n+\tsave_opts(opts);\n+\tsave_todo(todo_list, opts);\n+\n+\treturn pick_commits(todo_list, opts);\n+}\n+\n int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n \tint res;\n@@ -1023,7 +1031,13 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \tgit_config(git_default_config, NULL);\n \tme = \"revert\";\n \tparse_args(argc, argv, &opts);\n-\tres = pick_commits(&opts);\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+\tres = process_subcommand(&opts);\n \tif (res < 0)\n \t\tdie(_(\"revert failed\"));\n \treturn res;\n@@ -1039,7 +1053,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n \tgit_config(git_default_config, NULL);\n \tme = \"cherry-pick\";\n \tparse_args(argc, argv, &opts);\n-\tres = pick_commits(&opts);\n+\tres = process_subcommand(&opts);\n \tif (res < 0)\n \t\tdie(_(\"cherry-pick failed\"));\n \treturn res;\n-- \n1.7.5.GIT\n"},{"id":"171062","messageId":"1310396048-24925-15-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 14/17] reset: Make hard reset remove the sequencer state","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:05Z","receivedAt":"2011-07-11T14:54:05Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Years of muscle memory have trained users to use \"git reset --hard\" to\nremove away the branch state after any sort of operation.  In\nretrospect, while this may not have been the best design decision, we\nare stuck with it for historical reasons.  This sort of workflow is\nnow possible:\n\n$ git cherry-pick foo..bar\n... conflict encountered ...\n$ git reset --hard # Oops, I didn't mean that\n$ git cherry-pick quux..bar\n... cherry-pick succeeded ...\n\nAlso, guard against accidental removal of the sequencer state by\nmoving \".git/sequencer\" to \".git/sequencer-old\" in the first \"git\nreset --hard\" call, and only remove it completely only after the\nsecond call.\n\nAdditionally, this patch ensures that some existing tests don't break\nwhen features like \"--reset\" and \"--continue\" are introduced later in\nthe series.  Without this patch, we would expect the last cherry-pick\ncall in the example to fail with the complaint that an existing\ncherry-pick operation is in progress.\n\nSuggested-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/reset.c          |    2 ++\n t/7106-reset-sequence.sh |   40 ++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 0 deletions(-)\n create mode 100755 t/7106-reset-sequence.sh\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 98bca04..899e250 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -20,6 +20,7 @@\n #include \"parse-options.h\"\n #include \"unpack-trees.h\"\n #include \"cache-tree.h\"\n+#include \"sequencer.h\"\n \n static const char * const git_reset_usage[] = {\n \t\"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\",\n@@ -367,6 +368,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \n \tswitch (reset_type) {\n \tcase HARD:\n+\t\tremove_sequencer_state();\n \t\tif (!update_ref_status && !quiet)\n \t\t\tprint_new_head_line(commit);\n \t\tbreak;\ndiff --git a/t/7106-reset-sequence.sh b/t/7106-reset-sequence.sh\nnew file mode 100755\nindex 0000000..5aa8b71\n--- /dev/null\n+++ b/t/7106-reset-sequence.sh\n@@ -0,0 +1,40 @@\n+#!/bin/sh\n+\n+test_description='Test interaction of reset --hard with sequencer\n+\n+  + anotherpick: rewrites foo to d\n+  + picked: rewrites foo to c\n+  + unrelatedpick: rewrites unrelated to reallyunrelated\n+  + base: rewrites foo to b\n+  + initial: writes foo as a, unrelated as unrelated\n+'\n+\n+. ./test-lib.sh\n+\n+pristine_detach () {\n+\tgit checkout -f \"$1^0\" &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x\n+}\n+\n+test_expect_success setup '\n+\techo unrelated >unrelated &&\n+\tgit add unrelated &&\n+\ttest_commit initial foo a &&\n+\ttest_commit base foo b &&\n+\ttest_commit unrelatedpick unrelated reallyunrelated &&\n+\ttest_commit picked foo c &&\n+\ttest_commit anotherpick foo d &&\n+\tgit config advice.detachedhead false\n+\n+'\n+\n+test_expect_success 'reset --hard cleans up sequencer state' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick base..anotherpick &&\n+\ttest_path_is_dir .git/sequencer &&\n+\tgit reset --hard &&\n+\ttest_path_is_missing .git/sequencer\n+'\n+\n+test_done\n-- \n1.7.5.GIT\n"},{"id":"171069","messageId":"1310396048-24925-16-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 15/17] revert: Remove sequencer state when no commits are pending","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:06Z","receivedAt":"2011-07-11T14:54:06Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"When cherry-pick or revert is called on a list of commits, and a\nconflict encountered somewhere in the middle, the data in\n\".git/sequencer\" is required to continue the operation.  However, when\na conflict is encountered in the very last commit, the user will have\nto \"continue\" after resolving the conflict and committing just so that\nthe sequencer state is removed.  This is how the current \"rebase -i\"\nscript works as well.\n\n$ git cherry-pick foo..bar\n... conflict encountered while picking \"bar\" ...\n$ echo \"resolved\" >problematicfile\n$ git add problematicfile\n$ git commit\n$ git cherry-pick --continue # This would be a noop\n\nChange this so that the sequencer state is cleared when a conflict is\nencountered in the last commit.  Incidentally, this patch makes sure\nthat some existing tests don't break when features like \"--reset\" and\n\"--continue\" are implemented later in the series.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c                |   12 +++++++++++-\n t/t3510-cherry-pick-sequence.sh |   25 +++++++++++++++++++++++++\n 2 files changed, 36 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex f9f5e3a..3936516 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -990,8 +990,18 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \tfor (cur = todo_list; cur; cur = cur->next) {\n \t\tsave_todo(cur, opts);\n \t\tres = do_pick_commit(cur->item, opts);\n-\t\tif (res)\n+\t\tif (res) {\n+\t\t\tif (!cur->next)\n+\t\t\t\t/*\n+\t\t\t\t * An error was encountered while\n+\t\t\t\t * picking the last commit; the\n+\t\t\t\t * sequencer state is useless now --\n+\t\t\t\t * the user simply needs to resolve\n+\t\t\t\t * the conflict and commit\n+\t\t\t\t */\n+\t\t\t\tremove_sequencer_state();\n \t\t\treturn res;\n+\t\t}\n \t}\n \n \t/*\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 100cbb1..0a8b093 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -63,4 +63,29 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..picked &&\n+\ttest_path_is_missing .git/sequencer &&\n+\techo \"resolved\" >foo &&\n+\tgit add foo &&\n+\tgit commit &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/[0-9a-f]\\{40\\}/OBJID/g\"\n+\t} >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n1.7.5.GIT\n"},{"id":"171067","messageId":"1310396048-24925-17-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 16/17] revert: Introduce --reset to remove sequencer state","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:07Z","receivedAt":"2011-07-11T14:54:07Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Protect the sequencer state from accidentally being stomped by a new\ncherry-pick or revert invocation by ensuring that an existing one\nisn't in progress.  While this patch would normally be expected to\nbreak many tests, the earlier patches \"reset: Make hard reset remove\nthe sequencer state\" and \"revert: Remove sequencer state when no\ncommits are pending\" make sure that they don't.\n\nTo explicitly remove the sequencer state for a fresh cherry-pick or\nrevert invocation, introduce a new subcommand called '--reset' which\nreally removes the sequencer state on the very first invocation.\n\nEnsure that the \"rebase -i\" script which invokes cherry-pick or revert\ndoesn't change its behavior by using '--reset' to to clear the state\nafter every failed pick.  Effectively, the script will remain unaware\nand unaffected by introduction of further subcommands like\n'--continue'.\n\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-cherry-pick.txt |    5 +++\n Documentation/git-revert.txt      |    5 +++\n Documentation/sequencer.txt       |    4 ++\n builtin/reset.c                   |    2 +-\n builtin/revert.c                  |   66 ++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh        |   25 +++++++++++---\n sequencer.c                       |    4 ++-\n sequencer.h                       |    6 +++-\n t/t3510-cherry-pick-sequence.sh   |   17 ++++++++-\n 9 files changed, 113 insertions(+), 21 deletions(-)\n create mode 100644 Documentation/sequencer.txt\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 9d8fe0d..138a292 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -8,6 +8,7 @@ git-cherry-pick - Apply the changes introduced by some existing commits\n SYNOPSIS\n --------\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...\n+'git cherry-pick' --reset\n \n DESCRIPTION\n -----------\n@@ -109,6 +110,10 @@ effect to your index in a row.\n \tPass the merge strategy-specific option through to the\n \tmerge strategy.  See linkgit:git-merge[1] for details.\n \n+SEQUENCER SUBCOMMANDS\n+---------------------\n+include::sequencer.txt[]\n+\n EXAMPLES\n --------\n git cherry-pick master::\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex ac10cfb..783ffb4 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -8,6 +8,7 @@ git-revert - Revert some existing commits\n SYNOPSIS\n --------\n 'git revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...\n+'git revert' --reset\n \n DESCRIPTION\n -----------\n@@ -90,6 +91,10 @@ effect to your index in a row.\n \tPass the merge strategy-specific option through to the\n \tmerge strategy.  See linkgit:git-merge[1] for details.\n \n+SEQUENCER SUBCOMMANDS\n+---------------------\n+include::sequencer.txt[]\n+\n EXAMPLES\n --------\n git revert HEAD~3::\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nnew file mode 100644\nindex 0000000..16ce88c\n--- /dev/null\n+++ b/Documentation/sequencer.txt\n@@ -0,0 +1,4 @@\n+--reset::\n+\tForget about the current operation in progress.  Can be used\n+\tto clear the sequencer state after a failed cherry-pick or\n+\trevert.\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 899e250..ec0e5d0 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -368,7 +368,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \n \tswitch (reset_type) {\n \tcase HARD:\n-\t\tremove_sequencer_state();\n+\t\tremove_sequencer_state(0);\n \t\tif (!update_ref_status && !quiet)\n \t\t\tprint_new_head_line(commit);\n \t\tbreak;\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 3936516..409d88f 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -29,19 +29,23 @@\n \n static const char * const revert_usage[] = {\n \t\"git revert [options] <commit-ish>\",\n+\t\"git revert <subcommand>\",\n \tNULL\n };\n \n static const char * const cherry_pick_usage[] = {\n \t\"git cherry-pick [options] <commit-ish>\",\n+\t\"git cherry-pick <subcommand>\",\n \tNULL\n };\n \n static const char *me;\n enum replay_action { REVERT, CHERRY_PICK };\n+enum replay_subcommand { REPLAY_NONE, REPLAY_RESET };\n \n struct replay_opts {\n \tenum replay_action action;\n+\tenum replay_subcommand subcommand;\n \n \t/* Boolean options */\n \tint edit;\n@@ -104,7 +108,9 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tint noop;\n+\tint reset = 0;\n \tstruct option options[] = {\n+\t\tOPT_BOOLEAN(0, \"reset\", &reset, \"forget the current operation\"),\n \t\tOPT_BOOLEAN('n', \"no-commit\", &opts->no_commit, \"don't automatically commit\"),\n \t\tOPT_BOOLEAN('e', \"edit\", &opts->edit, \"edit the commit message\"),\n \t\t{ OPTION_BOOLEAN, 'r', NULL, &noop, NULL, \"no-op (backward compatibility)\",\n@@ -133,7 +139,27 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \topts->commit_argc = parse_options(argc, argv, NULL, options, usage_str,\n \t\t\t\t\tPARSE_OPT_KEEP_ARGV0 |\n \t\t\t\t\tPARSE_OPT_KEEP_UNKNOWN);\n-\tif (opts->commit_argc < 2)\n+\n+\t/* Set the subcommand */\n+\tif (reset)\n+\t\topts->subcommand = REPLAY_RESET;\n+\telse\n+\t\topts->subcommand = REPLAY_NONE;\n+\n+\t/* Check for incompatible command line arguments */\n+\tif (opts->subcommand == REPLAY_RESET) {\n+\t\tverify_opt_compatible(me, \"--reset\",\n+\t\t\t\t\"--no-commit\", opts->no_commit,\n+\t\t\t\t\"--signoff\", opts->signoff,\n+\t\t\t\t\"--mainline\", opts->mainline,\n+\t\t\t\t\"--strategy\", opts->strategy ? 1 : 0,\n+\t\t\t\t\"--strategy-option\", opts->xopts ? 1 : 0,\n+\t\t\t\t\"-x\", opts->record_origin,\n+\t\t\t\t\"--ff\", opts->allow_ff,\n+\t\t\t\tNULL);\n+\t}\n+\n+\telse if (opts->commit_argc < 2)\n \t\tusage_with_options(usage_str, options);\n \n \tif (opts->allow_ff)\n@@ -916,8 +942,11 @@ static void walk_revs_populate_todo(struct commit_list **todo_list,\n static void create_seq_dir(void)\n {\n \tif (file_exists(git_path(SEQ_DIR))) {\n-\t\tif (!is_directory(git_path(SEQ_DIR)) && remove_path(git_path(SEQ_DIR)) < 0)\n-\t\t\tdie(_(\"Could not remove %s\"), git_path(SEQ_DIR));\n+\t\terror(_(\"%s already exists.\"), git_path(SEQ_DIR));\n+\t\tadvise(_(\"This usually means that a %s operation is in progress.\"), me);\n+\t\tadvise(_(\"Use %s --continue to continue the operation\"), me);\n+\t\tadvise(_(\"or use %s --reset to forget about it\"), me);\n+\t\tdie(_(\"%s failed\"), me);\n \t} else if (mkdir(git_path(SEQ_DIR), 0777) < 0)\n \t\tdie_errno(_(\"Could not create sequencer directory '%s'.\"), git_path(SEQ_DIR));\n }\n@@ -999,7 +1028,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n \t\t\t\t * the user simply needs to resolve\n \t\t\t\t * the conflict and commit\n \t\t\t\t */\n-\t\t\t\tremove_sequencer_state();\n+\t\t\t\tremove_sequencer_state(0);\n \t\t\treturn res;\n \t\t}\n \t}\n@@ -1008,7 +1037,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(1);\n \treturn 0;\n }\n \n@@ -1019,13 +1048,28 @@ static int process_subcommand(struct replay_opts *opts)\n \n \tread_and_refresh_cache(me, opts);\n \n-\twalk_revs_populate_todo(&todo_list, opts);\n-\tcreate_seq_dir();\n-\tif (!get_sha1(\"HEAD\", sha1))\n-\t\tsave_head(sha1_to_hex(sha1));\n-\tsave_opts(opts);\n-\tsave_todo(todo_list, opts);\n+\tif (opts->subcommand == REPLAY_RESET) {\n+\t\tremove_sequencer_state(1);\n+\t\treturn 0;\n+\t} else {\n+\t\t/*\n+\t\t * Start a new cherry-pick/ revert sequence; but\n+\t\t * first, make sure that an existing one isn't in\n+\t\t * progress\n+\t\t */\n+\t\tif (file_exists(git_path(SEQ_TODO_FILE))) {\n+\t\t\terror(_(\"A %s is already in progress\"), me);\n+\t\t\tadvise(_(\"Use %s --reset to forget about it\"), me);\n+\t\t\treturn -1;\n+\t\t}\n \n+\t\twalk_revs_populate_todo(&todo_list, opts);\n+\t\tcreate_seq_dir();\n+\t\tif (!get_sha1(\"HEAD\", sha1))\n+\t\t\tsave_head(sha1_to_hex(sha1));\n+\t\tsave_opts(opts);\n+\t\tsave_todo(todo_list, opts);\n+\t}\n \treturn pick_commits(todo_list, opts);\n }\n \ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 65690af..14c57dd 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -136,6 +136,10 @@ make_patch () {\n \t\tget_author_ident_from_commit \"$1\" > \"$author_script\"\n }\n \n+clear_cherry_pick_state () {\n+\tgit cherry-pick --reset\n+}\n+\n die_with_patch () {\n \techo \"$1\" > \"$state_dir\"/stopped-sha\n \tmake_patch \"$1\"\n@@ -279,8 +283,10 @@ pick_one_preserving_merges () {\n \t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$rewritten_list\"\n \t\t\t;;\n \t\t*)\n-\t\t\toutput git cherry-pick \"$@\" ||\n+\t\t\toutput git cherry-pick \"$@\" || {\n+\t\t\t\tclear_cherry_pick_state\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\n+\t\t\t}\n \t\t\t;;\n \t\tesac\n \t\t;;\n@@ -385,16 +391,20 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n+\t\tpick_one $sha1 || {\n+\t\t\tclear_cherry_pick_state\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\t}\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n+\t\tpick_one $sha1 || {\n+\t\t\tclear_cherry_pick_state\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\t}\n \t\tgit commit --amend --no-post-rewrite\n \t\trecord_in_rewritten $sha1\n \t\t;;\n@@ -402,8 +412,10 @@ do_next () {\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n+\t\tpick_one $sha1 || {\n+\t\t\tclear_cherry_pick_state\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\t}\n \t\techo \"$sha1\" > \"$state_dir\"/stopped-sha\n \t\tmake_patch $sha1\n \t\tgit rev-parse --verify HEAD > \"$amend\"\n@@ -438,7 +450,10 @@ do_next () {\n \t\techo \"$author_script_content\" > \"$author_script\"\n \t\teval \"$author_script_content\"\n \t\toutput git reset --soft HEAD^\n-\t\tpick_one -n $sha1 || die_failed_squash $sha1 \"$rest\"\n+\t\tpick_one -n $sha1 || {\n+\t\t\tclear_cherry_pick_state\n+\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t}\n \t\tcase \"$(peek_next_command)\" in\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\ndiff --git a/sequencer.c b/sequencer.c\nindex 8c1de63..bc2c046 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3,7 +3,7 @@\n #include \"strbuf.h\"\n #include \"dir.h\"\n \n-void remove_sequencer_state(void)\n+void remove_sequencer_state(int aggressive)\n {\n \tstruct strbuf seq_dir = STRBUF_INIT;\n \tstruct strbuf seq_old_dir = STRBUF_INIT;\n@@ -12,6 +12,8 @@ void remove_sequencer_state(void)\n \tstrbuf_addf(&seq_old_dir, \"%s\", git_path(SEQ_OLD_DIR));\n \tremove_dir_recursively(&seq_old_dir, 0);\n \trename(git_path(SEQ_DIR), git_path(SEQ_OLD_DIR));\n+\tif (aggressive)\n+\t\tremove_dir_recursively(&seq_old_dir, 0);\n \tstrbuf_release(&seq_dir);\n \tstrbuf_release(&seq_old_dir);\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex dcb51b1..e1951cc 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -9,7 +9,11 @@\n \n /* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring\n  * any errors.  Intended to be used by 'git reset --hard'.\n+ *\n+ * With the aggressive flag, it additionally removes SEQ_OLD_DIR,\n+ * ignoring any errors.  Inteded to be used by the sequencer's\n+ * '--reset' subcommand.\n  */\n-void remove_sequencer_state(void);\n+void remove_sequencer_state(int aggressive);\n \n #endif\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 0a8b093..c21b345 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -37,7 +37,7 @@ test_expect_success 'cherry-pick persists data on failure' '\n \ttest_path_is_file .git/sequencer/head &&\n \ttest_path_is_file .git/sequencer/todo &&\n \ttest_path_is_file .git/sequencer/opts &&\n-\trm -rf .git/sequencer\n+\tgit cherry-pick --reset\n '\n \n test_expect_success 'cherry-pick persists opts correctly' '\n@@ -54,7 +54,7 @@ test_expect_success 'cherry-pick persists opts correctly' '\n \tstrategy-option = patience | ours\n \tEOF\n \ttest_cmp expect .git/sequencer/opts &&\n-\trm -rf .git/sequencer\n+\tgit cherry-pick --reset\n '\n \n test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n@@ -88,4 +88,17 @@ test_expect_success 'cherry-pick cleans up sequencer state when one commit is le\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--reset does not complain when no cherry-pick is in progress' '\n+\tpristine_detach initial &&\n+\tgit cherry-pick --reset\n+'\n+\n+test_expect_success '--reset cleans up sequencer state' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..picked &&\n+\tgit cherry-pick --reset &&\n+\ttest_path_is_missing .git/sequencer\n+'\n+\n test_done\n-- \n1.7.5.GIT\n"},{"id":"171066","messageId":"1310396048-24925-18-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T14:54:08Z","receivedAt":"2011-07-11T14:54:08Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Using the information in \".git/sequencer\", it is now possible to\ncontinue a cherry-pick or continue after a conflict.  To do this, we\nhave to parse the information in \".git/sequencer/opts\" into the\nreplay_opts structure and build a commit_list from the information in\n\".git/sequencer/todo\" before calling into the cherry-picking\nmachinery.  Introduce a new subcommand called '--continue' to\nfacilitate this.  It is imperative to note that this subcommand will\nblindly drop the first instruction and attempt to perform the rest of\nthe instructions in \".git/sequencer/todo\" to affect the current HEAD\nprovided that the index matches HEAD.  The resulting end-user workflow\nis as follows:\n\n$ git cherry-pick foo..bar\n... conflict in commit moo ...\n$ git cherry-pick --continue\nerror: 'cherry-pick' is not possible because you have unmerged files.\n...\n$ echo \"resolved\" >conflictingfile\n$ git commit # this is a replacement for \"moo\"\n$ git cherry-pick --continue # drops \"moo\" and replays everything else\n\nDuring the \"git commit\" stage, CHERRY_PICK_HEAD will aid by providing\nthe commit message from the conflicting \"moo\" commit.  Note that the\ncherry-pick mechanism has no control at this stage, so the user is\nfree to violate anything that was specified during the first\ncherry-pick invocation.  For example, if \"-x\" was specified during the\nfirst cherry-pick invocation, the user is free to edit out the message\nduring commit time.  One glitch to note is that the \"--signoff\" option\nspecified at cherry-pick invocation time is not reflected in the\ncommit message provided by CHERRY_PICK_HEAD; the user must take care\nto add \"--signoff\" during the \"git commit\" invocation.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-cherry-pick.txt |    1 +\n Documentation/git-revert.txt      |    1 +\n Documentation/sequencer.txt       |    5 ++\n builtin/revert.c                  |   60 ++++++++++++++++++++++--\n t/t3510-cherry-pick-sequence.sh   |   93 +++++++++++++++++++++++++++++++++++++\n 5 files changed, 156 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 138a292..663186b 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -9,6 +9,7 @@ SYNOPSIS\n --------\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...\n 'git cherry-pick' --reset\n+'git cherry-pick' --continue\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 783ffb4..9be2fe2 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,6 +9,7 @@ SYNOPSIS\n --------\n 'git revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...\n 'git revert' --reset\n+'git revert' --continue\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 16ce88c..3e6df33 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -2,3 +2,8 @@\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\n \trevert.\n+\n+--continue::\n+\tContinue the operation in progress using the information in\n+\t'.git/sequencer'.  Can be used to continue after resolving\n+\tconflicts in a failed cherry-pick or revert.\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 409d88f..f974ee0 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -41,7 +41,7 @@ static const char * const cherry_pick_usage[] = {\n \n static const char *me;\n enum replay_action { REVERT, CHERRY_PICK };\n-enum replay_subcommand { REPLAY_NONE, REPLAY_RESET };\n+enum replay_subcommand { REPLAY_NONE, REPLAY_RESET, REPLAY_CONTINUE };\n \n struct replay_opts {\n \tenum replay_action action;\n@@ -104,13 +104,39 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)\n \tva_end(ap);\n }\n \n+static void verify_opt_mutually_compatible(const char *me, ...)\n+{\n+       const char *opt1, *opt2;\n+       va_list ap;\n+       int set;\n+\n+       va_start(ap, me);\n+       while ((opt1 = va_arg(ap, const char *))) {\n+\t       set = va_arg(ap, int);\n+\t       if (set)\n+\t\t       break;\n+       }\n+       if (!opt1)\n+\t       goto ok;\n+       while ((opt2 = va_arg(ap, const char *))) {\n+\t       set = va_arg(ap, int);\n+\t       if (set)\n+\t\t       die(_(\"%s: %s cannot be used with %s\"),\n+\t\t\t       me, opt1, opt2);\n+       }\n+ok:\n+       va_end(ap);\n+}\n+\n static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n {\n \tconst char * const * usage_str = revert_or_cherry_pick_usage(opts);\n \tint noop;\n \tint reset = 0;\n+\tint contin = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOLEAN(0, \"reset\", &reset, \"forget the current operation\"),\n+\t\tOPT_BOOLEAN(0, \"continue\", &contin, \"continue the current operation\"),\n \t\tOPT_BOOLEAN('n', \"no-commit\", &opts->no_commit, \"don't automatically commit\"),\n \t\tOPT_BOOLEAN('e', \"edit\", &opts->edit, \"edit the commit message\"),\n \t\t{ OPTION_BOOLEAN, 'r', NULL, &noop, NULL, \"no-op (backward compatibility)\",\n@@ -140,15 +166,29 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\tPARSE_OPT_KEEP_ARGV0 |\n \t\t\t\t\tPARSE_OPT_KEEP_UNKNOWN);\n \n+\t/* Check for incompatible subcommands */\n+\tverify_opt_mutually_compatible(me,\n+\t\t\t\t\"--reset\", reset,\n+\t\t\t\t\"--continue\", contin,\n+\t\t\t\tNULL);\n+\n \t/* Set the subcommand */\n \tif (reset)\n \t\topts->subcommand = REPLAY_RESET;\n+\telse if (contin)\n+\t\topts->subcommand = REPLAY_CONTINUE;\n \telse\n \t\topts->subcommand = REPLAY_NONE;\n \n \t/* Check for incompatible command line arguments */\n-\tif (opts->subcommand == REPLAY_RESET) {\n-\t\tverify_opt_compatible(me, \"--reset\",\n+\tif (opts->subcommand != REPLAY_NONE) {\n+\t\tchar *this_operation;\n+\t\tif (opts->subcommand == REPLAY_RESET)\n+\t\t\tthis_operation = \"--reset\";\n+\t\telse\n+\t\t\tthis_operation = \"--continue\";\n+\n+\t\tverify_opt_compatible(me, this_operation,\n \t\t\t\t\"--no-commit\", opts->no_commit,\n \t\t\t\t\"--signoff\", opts->signoff,\n \t\t\t\t\"--mainline\", opts->mainline,\n@@ -1051,6 +1091,15 @@ static int process_subcommand(struct replay_opts *opts)\n \tif (opts->subcommand == REPLAY_RESET) {\n \t\tremove_sequencer_state(1);\n \t\treturn 0;\n+\t} else if (opts->subcommand == REPLAY_CONTINUE) {\n+\t\tif (!file_exists(git_path(SEQ_TODO_FILE)))\n+\t\t\tgoto error;\n+\t\tread_populate_opts(&opts);\n+\t\tread_populate_todo(&todo_list, opts);\n+\n+\t\t/* Verify that the conflict has been resolved */\n+\t\tif (!index_differs_from(\"HEAD\", 0))\n+\t\t\ttodo_list = todo_list->next;\n \t} else {\n \t\t/*\n \t\t * Start a new cherry-pick/ revert sequence; but\n@@ -1059,7 +1108,8 @@ static int process_subcommand(struct replay_opts *opts)\n \t\t */\n \t\tif (file_exists(git_path(SEQ_TODO_FILE))) {\n \t\t\terror(_(\"A %s is already in progress\"), me);\n-\t\t\tadvise(_(\"Use %s --reset to forget about it\"), me);\n+\t\t\tadvise(_(\"Use %s --continue to continue the operation\"), me);\n+\t\t\tadvise(_(\"or use %s --reset to forget about it\"), me);\n \t\t\treturn -1;\n \t\t}\n \n@@ -1071,6 +1121,8 @@ static int process_subcommand(struct replay_opts *opts)\n \t\tsave_todo(todo_list, opts);\n \t}\n \treturn pick_commits(todo_list, opts);\n+error:\n+\treturn error(_(\"No %s in progress\"), me);\n }\n \n int cmd_revert(int argc, const char **argv, const char *prefix)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex c21b345..635a45e 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -101,4 +101,97 @@ test_expect_success '--reset cleans up sequencer state' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success '--continue complains when no cherry-pick is in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --continue >actual 2>&1 &&\n+\ttest_i18ngrep \"error\" actual\n+'\n+\n+test_expect_success '--continue complains when there are unresolved conflicts' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..picked &&\n+\ttest_must_fail git cherry-pick --continue &&\n+\tgit cherry-pick --reset\n+'\n+\n+test_expect_success '--continue continues after conflicts are resolved' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..anotherpick &&\n+\techo \"c\" >foo &&\n+\tgit add foo &&\n+\tgit commit &&\n+\tgit cherry-pick --continue &&\n+\ttest_path_is_missing .git/sequencer &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/[0-9a-f]\\{40\\}/OBJID/g\"\n+\t} >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--continue respects opts' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick -s -x base..anotherpick &&\n+\techo \"c\" >foo &&\n+\tgit add foo &&\n+\tgit commit -s &&\n+\tgit cherry-pick --continue &&\n+\ttest_path_is_missing .git/sequencer &&\n+\tgit cat-file commit HEAD >anotherpick_msg &&\n+\tgit cat-file commit HEAD~1 >picked_msg &&\n+\tgit cat-file commit HEAD~2 >unrelatedpick_msg &&\n+\tgit cat-file commit HEAD~3 >initial_msg &&\n+\ttest_must_fail test_i18ngrep \"Signed-off-by:\" initial_msg &&\n+\ttest_i18ngrep \"Signed-off-by:\" unrelatedpick_msg &&\n+\ttest_i18ngrep \"Signed-off-by:\" picked_msg &&\n+\ttest_i18ngrep \"Signed-off-by:\" anotherpick_msg &&\n+\ttest_must_fail test_i18ngrep \"cherry picked from\" initial_msg &&\n+\ttest_i18ngrep \"cherry picked from\" unrelatedpick_msg &&\n+\ttest_i18ngrep \"cherry picked from\" picked_msg &&\n+\ttest_i18ngrep \"cherry picked from\" anotherpick_msg\n+'\n+\n+test_expect_success 'malformed instruction sheet 1' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..picked &&\n+\techo \"resolved\" >foo &&\n+\tgit add foo &&\n+\tgit commit &&\n+\tsed \"s/pick /pick/\" .git/sequencer/todo >new_sheet\n+\tcp new_sheet .git/sequencer/todo\n+\ttest_must_fail git cherry-pick --continue >actual 2>&1 &&\n+\tgit cherry-pick --reset &&\n+\ttest_i18ngrep \"fatal\" actual\n+'\n+\n+test_expect_success 'malformed instruction sheet 2' '\n+\tpristine_detach initial &&\n+\thead=$(git rev-parse HEAD) &&\n+\ttest_must_fail git cherry-pick base..picked &&\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_must_fail git cherry-pick --continue >actual 2>&1 &&\n+\tgit cherry-pick --reset &&\n+\ttest_i18ngrep \"fatal\" actual\n+'\n+\n test_done\n-- \n1.7.5.GIT\n"},{"id":"171085","messageId":"20110711171713.GA5963@elie","threadId":"27786","inReplyTo":"1310396048-24925-1-git-send-email-artagnon@gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-11T17:17:13Z","receivedAt":"2011-07-11T17:17:13Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi Ram!\n\nRamkumar Ramachandra wrote:\n\n> I'm excited to announce the first iteration of a fresh series\n\nThe basic questions:\n\n - has the result of applying each patch in the new iteration been\n   tested (for example by rebasing interactively with \"exec make test\"\n   after each \"pick\" line)?\n\n - what changed since last time, for each patch?  (For the future, the\n   space under the \"---\" is generally a good place to put that\n   information.)\n\n - what proposed changes did not make it in, for each patch?  If any,\n   did they not fit well with the design, or was it more a matter of\n   \"sure, that would be nice, but let's get this in first\"?\n\n[...]\n> I would have liked to reuse the gitconfig parser as-is for the opts\n> parsing, but it's too tangled up in config.c.  I think it's safe to\n> say that the opts file format deviates only slightly from the\n> gitconfig format, and I'm quite happy with the end result.\n\nTo be precise, the format used includes\n\n\tstrategy-option = patience | renormalize\n\nto represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\nabout that is that the \"|\" can sound like \"or\", which would seem\nstrange to a user that does not necessarily develop software (so is\nnot thinking about bitfields).  The format used in config files puts\n\n\tstrategy-option = patience\n\tstrategy-option = renormalize\n\nas separate lines.  \n\n> 4. New tests and documentation.  There's really no end to this\n\nOnce each new feature has been documented and each new feature or\nfixed bug has an associated test, you've reached the end of this.\n\nMeanwhile, it's true that it's possible to improve tests and\ndocumentation beyond that, but that would not fit well in the context\nof this series anyway.\n\n[...]\n> The series is becoming large and unmanagable --\n> we can fix minor issues after the merge.\n[...]\n>   advice: Introduce error_resolve_conflict\n>   revert: Inline add_message_to_msg function\n>   revert: Don't check lone argument in get_encoding\n>   revert: Rename no_replay to record_origin\n>   revert: Propogate errors upwards from do_pick_commit\n>   revert: Eliminate global \"commit\" variable\n>   revert: Introduce struct to keep command-line options\n>   revert: Separate cmdline parsing from functional code\n>   revert: Don't create invalid replay_opts in parse_args\n>   sequencer: Announce sequencer state location\n>   revert: Save data for continuing after conflict resolution\n>   revert: Save command-line options for continuing operation\n>   revert: Introduce a layer of indirection over pick_commits\n>   reset: Make hard reset remove the sequencer state\n>   revert: Remove sequencer state when no commits are pending\n>   revert: Introduce --reset to remove sequencer state\n>   revert: Introduce --continue to continue the operation\n\nMy main worry is still the commit messages.  They don't need to be\nelaborate but they should explain the purpose and effect of each\npatch.  Part of the reason I care is that it makes the life of future\nreaders using \"git log -S\" or \"git bisect\" before changing that code\nmuch easier.  Think of them like a special kind of comments that don't\ninterfere with reading the code straight through.\n\nThe main reason I care is that that information makes the code itself\neasier to review.\n\nI don't know how to move forward on that.  I can explain what's\nmissing in each message, but I get the impression that you already\nunderstand that and there's something else (e.g., time) preventing\nthem from getting fixed.  I could rewrite each commit message, but I\nam likely to miss things and come up with something that sounds\nvaguely plausible but doesn't accurately explain the intent.  What do\nyou suggest?\n\nJonathan\n"},{"id":"171094","messageId":"CALkWK0msdBdXX4oMkd+WAMR8PXTRT3ivjMrf3ZAMfBrsLoM=dQ@mail.gmail.com","threadId":"27786","inReplyTo":"20110711171713.GA5963@elie","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T17:57:06Z","receivedAt":"2011-07-11T17:57:06Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> I'm excited to announce the first iteration of a fresh series\n>  - has the result of applying each patch in the new iteration been\n>   tested (for example by rebasing interactively with \"exec make test\"\n>   after each \"pick\" line)?\n\nTests are still running.  I'll let you know the results in the morning.\n\n>  - what changed since last time, for each patch?  (For the future, the\n>   space under the \"---\" is generally a good place to put that\n>   information.)\n\nWill comment a little more on this in the morning.  The main focus of\nthis series is to showcase the new option parser, and show how it fits\ninto the rest of the series.\n\n>  - what proposed changes did not make it in, for each patch?  If any,\n>   did they not fit well with the design, or was it more a matter of\n>   \"sure, that would be nice, but let's get this in first\"?\n\nA combination of both.  More on this later.\n\n>> I would have liked to reuse the gitconfig parser as-is for the opts\n>> parsing, but it's too tangled up in config.c.  I think it's safe to\n>> say that the opts file format deviates only slightly from the\n>> gitconfig format, and I'm quite happy with the end result.\n>\n> To be precise, the format used includes\n>\n>        strategy-option = patience | renormalize\n>\n> to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n> about that is that the \"|\" can sound like \"or\", which would seem\n> strange to a user that does not necessarily develop software (so is\n> not thinking about bitfields).  The format used in config files puts\n>\n>        strategy-option = patience\n>        strategy-option = renormalize\n>\n> as separate lines.\n\nOkay, I can change to that if it's desirable.  My rationale for using\n\"|\" is that lines like \"key = value1\" and \"key = value2\" tend to look\nodd -- it's like I'm reassigning the key a different value.\n\n>> 4. New tests and documentation.  There's really no end to this\n>\n> Once each new feature has been documented and each new feature or\n> fixed bug has an associated test, you've reached the end of this.\n\nIt depends on how rigorously you want to document and test things, no?\n For example, I haven't documented the formats of the configuration\nfiles anywhere but in the commit messages.  Something in\nDocumentation/technical would be nice, but I think we should wait\nuntil the format evolves a bit.  Since I haven't exposed anything like\na \"--interactive\" functionality, the user will never see it and we can\nchange it as and when we like.\n\nAlso, for things like the option parser, how far do you want to go\nwith testing? How many kinds of malformed instruction sheets do you\nwant to test with?  I'll include some more basic tests soon, but I\ndon't think we should go too deep, due to time constraints.\n\nAs you can see, I've included basic usage documentation.  Do let me\nknow what else is required right now.\n\n> My main worry is still the commit messages.  They don't need to be\n> elaborate but they should explain the purpose and effect of each\n> patch.  Part of the reason I care is that it makes the life of future\n> readers using \"git log -S\" or \"git bisect\" before changing that code\n> much easier.  Think of them like a special kind of comments that don't\n> interfere with reading the code straight through.\n>\n> The main reason I care is that that information makes the code itself\n> easier to review.\n\nI completely agree.  We should not compromise on commit messages --\nthey can't be fixed later.\n\n> I don't know how to move forward on that.  I can explain what's\n> missing in each message, but I get the impression that you already\n> understand that and there's something else (e.g., time) preventing\n> them from getting fixed.  I could rewrite each commit message, but I\n> am likely to miss things and come up with something that sounds\n> vaguely plausible but doesn't accurately explain the intent.  What do\n> you suggest?\n\nI have updated many of the commit messages.  Do let me know what's\nmissing where.  As usual, you can leave quick comments on IRC -- I'll\ncheck the logs in the morning.\n\nThanks!\n\n-- Ram\n"},{"id":"171105","messageId":"7vvcv8bjmf.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"1310396048-24925-16-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 15/17] revert: Remove sequencer state when no commits are pending","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T19:58:16Z","receivedAt":"2011-07-11T19:58:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index f9f5e3a..3936516 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -990,8 +990,18 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n>  \tfor (cur = todo_list; cur; cur = cur->next) {\n>  \t\tsave_todo(cur, opts);\n>  \t\tres = do_pick_commit(cur->item, opts);\n> -\t\tif (res)\n> +\t\tif (res) {\n> +\t\t\tif (!cur->next)\n> +\t\t\t\t/*\n> +\t\t\t\t * An error was encountered while\n> +\t\t\t\t * picking the last commit; the\n> +\t\t\t\t * sequencer state is useless now --\n> +\t\t\t\t * the user simply needs to resolve\n> +\t\t\t\t * the conflict and commit\n> +\t\t\t\t */\n> +\t\t\t\tremove_sequencer_state();\n>  \t\t\treturn res;\n> +\t\t}\n>  \t}\n\nIt may be useless for --continue, but wouldn't --abort need some clue on\nwhat you were doing?\n"},{"id":"171097","messageId":"CALkWK0kQY_ZO7Q37Q0ihi+c6G70zRvOxFi-zkBPrTtUNOafedA@mail.gmail.com","threadId":"27786","inReplyTo":"CALkWK0msdBdXX4oMkd+WAMR8PXTRT3ivjMrf3ZAMfBrsLoM=dQ@mail.gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-11T20:05:05Z","receivedAt":"2011-07-11T20:05:05Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nRamkumar Ramachandra writes:\n> Jonathan Nieder writes:\n>> Ramkumar Ramachandra wrote:\n>>> I'm excited to announce the first iteration of a fresh series\n>>  - has the result of applying each patch in the new iteration been\n>>   tested (for example by rebasing interactively with \"exec make test\"\n>>   after each \"pick\" line)?\n>\n> Tests are still running.  I'll let you know the results in the morning.\n\nQuick update: Yes! All of them pass all tests :)\n\n-- Ram\n"},{"id":"171106","messageId":"7vpqlgbjmd.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"20110711171713.GA5963@elie","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T20:07:20Z","receivedAt":"2011-07-11T20:07:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> The basic questions:\n> ...\n\nAll good suggestions.\n\n> To be precise, the format used includes\n> \n> \tstrategy-option = patience | renormalize\n>\n> to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n> about that is that the \"|\" can sound like \"or\", which would seem\n> strange to a user that does not necessarily develop software (so is\n> not thinking about bitfields).  The format used in config files puts\n>\n> \tstrategy-option = patience\n> \tstrategy-option = renormalize\n>\n> as separate lines.  \n\nA very good point again. I do not think anywhere in our codebase we use\n\"|\" as a separator for state files (either used for internal or exposed to\nthe end user), and we probably would want to be consistent across\ncommands.\n\n>> 4. New tests and documentation.  There's really no end to this\n>\n> Once each new feature has been documented and each new feature or\n> fixed bug has an associated test, you've reached the end of this.\n\nYes.\n\n> My main worry is still the commit messages.  They don't need to be\n> elaborate but they should explain the purpose and effect of each\n> patch.\n\nDoubly yes.\n\n> I don't know how to move forward on that.  I can explain what's\n> missing in each message, but I get the impression that you already\n> understand that and there's something else (e.g., time) preventing\n> them from getting fixed.\n\nUnderstanding that does not lead to an action does not really count, does\nit? After all, this series was labeled \"for inclusion\", not an RFC, which\nwould mean the submitter, helpers, and reviewers all made reasonable\neffort to perfect the series to their ability, no?\n"},{"id":"171101","messageId":"20110711201124.GA6568@elie","threadId":"27786","inReplyTo":"CALkWK0msdBdXX4oMkd+WAMR8PXTRT3ivjMrf3ZAMfBrsLoM=dQ@mail.gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-11T20:11:24Z","receivedAt":"2011-07-11T20:11:24Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n> Jonathan Nieder writes:\n\n>> To be precise, the format used includes\n>>\n>>        strategy-option = patience | renormalize\n>>\n>> to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n>> about that is that the \"|\" can sound like \"or\", which would seem\n>> strange to a user that does not necessarily develop software (so is\n>> not thinking about bitfields).  The format used in config files puts\n>>\n>>        strategy-option = patience\n>>        strategy-option = renormalize\n>>\n>> as separate lines.\n>\n> Okay, I can change to that if it's desirable.  My rationale for using\n> \"|\" is that lines like \"key = value1\" and \"key = value2\" tend to look\n> odd -- it's like I'm reassigning the key a different value.\n\nOn second thought, I don't think it matters, since this is not meant\nfor humans anyway, right?\n\nI.e., it could be\n\n\tgibberish=patience renormalize\n\nand that would work just as well.  Feel free to forget I said anything.\n\n>> Once each new feature has been documented and each new feature or\n>> fixed bug has an associated test, you've reached the end of this.\n>\n> It depends on how rigorously you want to document and test things, no?\n>  For example, I haven't documented the formats of the configuration\n> files anywhere but in the commit messages.  Something in\n> Documentation/technical would be nice, but I think we should wait\n> until the format evolves a bit.  Since I haven't exposed anything like\n> a \"--interactive\" functionality, the user will never see it and we can\n> change it as and when we like.\n\nRight, I haven't looked through carefully but this didn't look\nunderdocumented.\n\nI mostly meant about tests:\n\n> Also, for things like the option parser, how far do you want to go\n> with testing? How many kinds of malformed instruction sheets do you\n> want to test with?  I'll include some more basic tests soon, but I\n> don't think we should go too deep, due to time constraints.\n\nThere are other reasons not to test too much, too: the longer tests\nare, the less pleasant an experience it is to run them or to modify\nthe testsuite later.  So just the minimum to make sure the feature and\nchecks you carefully introduced continue to work as later changes are\nmade is not only enough but ideal.\n\n> I have updated many of the commit messages.  Do let me know what's\n> missing where.\n\nWill send relevant links to previous reviews.  Thanks.\n"},{"id":"171108","messageId":"7vk4bobjjk.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"1310396048-24925-10-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T20:44:42Z","receivedAt":"2011-07-11T20:44:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> structure before before starting its operation, there will be multiple\n\nbefore before\n"},{"id":"171102","messageId":"7vbox0cz1j.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"1310396048-24925-12-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T21:01:12Z","receivedAt":"2011-07-11T21:01:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> +/* Insert into todo_list in same order; commit_list_insert reverses\n> + * the order\n\nStyle: end the first line of multi-line comment at \"/*\".\n\nAs you say \"in same order\", you solicit a question \"The same as what?\".\nAs you say \"insert reverses the order\", you sound as if you are\ncomplaining you do not want insert to do so.\n\nAnd you do not need either of them. The function is \"append\", and if you\nexplain it as \"append\", you do not have to contrast it with \"insert\".\nIn other words, starting this comment with\n\n        /*\n         * Append a commit at the end of the commit_list.\n\nis perfectly adequate, I think. More useful would be (although it could be\nread from the usage example) to help callers what \"next\" means, perhaps\nlike:\n\n         * next starts by pointing at the variable that holds the head of\n         * the list when the for an empty commit_list, and is updated to\n         * point at the \"next\" field of the last item on the list, as new\n         * commits are appended to the list.\n\n> + *\n> + * Usage example:\n> + *\n> + *     struct commit_list *list;\n> + *     struct commit_list **next = &list;\n> + *\n> + *     next = commit_list_append(c1, next);\n> + *     next = commit_list_append(c2, next);\n> + *     *next = NULL;\n> + *     assert(commit_list_count(list) == 2);\n> + *     return list;\n> + *\n> + * Don't forget to NULL-terminate!\n\nI am still not convinced that making it the caller's responsibility to\nNULL-terminate the list after it finishes to append is a good trade-off\nbetween run-time performance and ease of API use.  If you are appending\nthousands of commits to a commit list in a tight loop, surely you would\nsave the same thousands of assignment of NULL to the next field of the\nelement at the tail of the list, which may reduce the instruction count a\ntiny bit, but that field was assigned in the last round in that tight loop\nand the cacheline would likely to be owned by the CPU already, so it might\nnot make much practical difference.\n"},{"id":"171109","messageId":"7vei1wbjji.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"1310396048-24925-13-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 12/17] revert: Save command-line options for continuing operation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T21:15:18Z","receivedAt":"2011-07-11T21:15:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> +\tdie(_(\"Malformed options sheet: %s\"), git_path(SEQ_OPTS_FILE));\n> +}\n> +\n> +static void read_populate_opts(struct replay_opts **opts_ptr)\n\nIt would make sense to refactor config.c:git_parse_file() to be easier to\nuse, rename it to be more descriptive (it should be a function that takes\na struct that holds these fields\n\n        static FILE *config_file;\n        static const char *config_file_name;\n        static int config_linenr;\n        static int config_file_eof;\n\nin addition to the callback \"fn\" and callback \"data\", expects the file to\nbe in something similar to the .ini format, parses it with the help from\nthe callback function), and use it here, without rolling your own.\n\nAlso I get\n\nbuiltin/revert.c:682: error: 'read_populate_todo' defined but not used\nbuiltin/revert.c:848: error: 'read_populate_opts' defined but not used\n\nat this step in the series, which is not quite optimal.\n"},{"id":"171111","messageId":"7v62n8bj28.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"7vbox0cz1j.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-11T21:31:43Z","receivedAt":"2011-07-11T21:31:43Z","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>          * next starts by pointing at the variable that holds the head of\n>          * the list when the for an empty commit_list, and is updated to\n\ns/when the//; sorry for the edit-o.\n"},{"id":"171114","messageId":"20110711221419.GE30155@sigill.intra.peff.net","threadId":"27786","inReplyTo":"7vpqlgbjmd.fsf@alter.siamese.dyndns.org","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-11T22:14:19Z","receivedAt":"2011-07-11T22:14:19Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jul 11, 2011 at 01:07:20PM -0700, Junio C Hamano wrote:\n\n> > To be precise, the format used includes\n> > \n> > \tstrategy-option = patience | renormalize\n> >\n> > to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n> > about that is that the \"|\" can sound like \"or\", which would seem\n> > strange to a user that does not necessarily develop software (so is\n> > not thinking about bitfields).  The format used in config files puts\n> >\n> > \tstrategy-option = patience\n> > \tstrategy-option = renormalize\n> >\n> > as separate lines.  \n> \n> A very good point again. I do not think anywhere in our codebase we use\n> \"|\" as a separator for state files (either used for internal or exposed to\n> the end user), and we probably would want to be consistent across\n> commands.\n\nI had the same feeling about the \"|\". I'm a little confused about what\nthese options are good for, though.\n\nIs it purely about saving some persistent data between runs, and nobody\nelse is going to look at it? In that case, I don't think it matters what\nthe format is. Use some unambiguous encoding that we already have\navailable (like sq_quote_argv and sq_dequote_argv), and write as little\ncode as possible.\n\nOr is it something that, like the information in .git/rebase-apply,\npeople might want to read or tweak? In that case, might it make sense to\nfollow that lead and split things into one file per item? That keeps the\nparsing burden extremely low for things like shell scripts (or shell\nusers) who might want to read or tweak.\n\n-Peff\n"},{"id":"171123","messageId":"CALkWK0=W58pHShDeoPkys2gYNAk+VSP7CCVijvSDq6N_NdLaKw@mail.gmail.com","threadId":"27786","inReplyTo":"7vbox0cz1j.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T05:43:58Z","receivedAt":"2011-07-12T05:43:58Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>> + *\n>> + * Usage example:\n>> + *\n>> + *     struct commit_list *list;\n>> + *     struct commit_list **next = &list;\n>> + *\n>> + *     next = commit_list_append(c1, next);\n>> + *     next = commit_list_append(c2, next);\n>> + *     *next = NULL;\n>> + *     assert(commit_list_count(list) == 2);\n>> + *     return list;\n>> + *\n>> + * Don't forget to NULL-terminate!\n>\n> I am still not convinced that making it the caller's responsibility to\n> NULL-terminate the list after it finishes to append is a good trade-off\n> between run-time performance and ease of API use.  If you are appending\n> thousands of commits to a commit list in a tight loop, surely you would\n> save the same thousands of assignment of NULL to the next field of the\n> element at the tail of the list, which may reduce the instruction count a\n> tiny bit, but that field was assigned in the last round in that tight loop\n> and the cacheline would likely to be owned by the CPU already, so it might\n> not make much practical difference.\n\nAh, I hadn't thought about it this deeply.  Changed now- thanks for\nthe explanation.\n\n-- Ram\n"},{"id":"171127","messageId":"CALkWK0kxnN_vcvaetOFw1Ouj7vj3mQ2DjPWv5v_9_a5UNjFooQ@mail.gmail.com","threadId":"27786","inReplyTo":"7vei1wbjji.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 12/17] revert: Save command-line options for continuing operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T05:56:46Z","receivedAt":"2011-07-12T05:56:46Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>> +     die(_(\"Malformed options sheet: %s\"), git_path(SEQ_OPTS_FILE));\n>> +}\n>> +\n>> +static void read_populate_opts(struct replay_opts **opts_ptr)\n>\n> It would make sense to refactor config.c:git_parse_file() to be easier to\n> use, rename it to be more descriptive (it should be a function that takes\n> a struct that holds these fields\n>\n>        static FILE *config_file;\n>        static const char *config_file_name;\n>        static int config_linenr;\n>        static int config_file_eof;\n>\n> in addition to the callback \"fn\" and callback \"data\", expects the file to\n> be in something similar to the .ini format, parses it with the help from\n> the callback function), and use it here, without rolling your own.\n\nYes, and I'm working on it.  However, it'll probably take me more than\na few iterations to get the patch right- I didn't want the options\nparser to be blocked by that.\n\n> Also I get\n>\n> builtin/revert.c:682: error: 'read_populate_todo' defined but not used\n> builtin/revert.c:848: error: 'read_populate_opts' defined but not used\n>\n> at this step in the series, which is not quite optimal.\n\nAh, yes.  I was going to ask about this:\n\"revert: Save data for continuing after conflict resolution\"\nintroduces read_ and save_ counterparts for todo\n\"revert: Save command-line options for continuing operation\"\nintroduces read_ and save_ counterparts for opts\nThe read_ counterparts of both are only used much later in \"revert:\nIntroduce --continue to continue the operation\"\n\nNow I could introduce the read_ functions in the last patch, but that\nwouldn't be very elegant -- I want to show people how to read the\ntodo/ opts file in the same patch where I first announce and show\npeople how to write them.  Does that make sense?  What do you suggest?\n Something like the GCC \"unused\"?\n\nThanks.\n\n-- Ram\n"},{"id":"171128","messageId":"CALkWK0m8S3fEFhFQV_A=UNipwa_6yBpdJ1iDc8c6BicthTTSyg@mail.gmail.com","threadId":"27786","inReplyTo":"7vk4bobjjk.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T05:57:12Z","receivedAt":"2011-07-12T05:57:12Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJunio C Hamano writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>> structure before before starting its operation, there will be multiple\n>\n> before before\n\nFixed.  Thanks.\n\n-- Ram\n"},{"id":"171129","messageId":"20110712055817.GA10169@elie","threadId":"27786","inReplyTo":"7vpqlgbjmd.fsf@alter.siamese.dyndns.org","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T05:58:17Z","receivedAt":"2011-07-12T05:58:17Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n\n> After all, this series was labeled \"for inclusion\", not an RFC, which\n> would mean the submitter, helpers, and reviewers all made reasonable\n> effort to perfect the series to their ability, no?\n\nYep, that is how I interpret the subject line, too.\n\nWow, the series has been through a lot of iterations.  I finally found\na moment to dig up the ones I replied to (a full list would be harder\nsince search.gmane.org is still down).  Maybe they can save others\nsome time, too.\n\n - RFC: Sequencer Foundations [1]\n   The basic themes are introduced and Daniel explains the\n   two-levels concept.\n\n - Sequencer Foundations[2]\n   Basic discussion of the purpose of die()-to-error() conversion and\n   the suggestion of an almost crash-only design to avoid some of its\n   problems.\n\n - Better error handling around revert[3]\n   A quick discussion of die() versus assert() and how to unwind\n   after errors.\n\n - Sequencer Foundations v3, v4[4]\n   Capturing globals in a struct.  Whether to save error codes before\n   propagating them (versus the simpler \"return -1\").  Another round\n   of die()-to-error() versus crash-only code.  Pacing and the idea of\n   merging bit-by-bit.\n\n - Implementing --abort processing[5][6]\n   UI design is difficult.  The easiest way is to teach the porcelain\n   to do what you were doing by hand already.\n\n - Sequencer with continuation features[7]\n   Commit messages.  Variable names.  commit_list_append().  It seems\n   we are closing in.\n\n - Sequencer: the insn sheet format[8]\n   Various loose ends: i18n, commit messages, relationship between\n   breakage of scripts and workflows and the need to patch tests, the\n   \"me\" variable, advise(), variable names.\n\nI suspect that getting the workarounds that keep existing scripts\nworking will take another round.  However, some of the early patches\nmight be ready.  My review will focus on that possibility.\n\nRam, thanks for your hard work.\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/171255\n[2] http://thread.gmane.org/gmane.comp.version-control.git/173408\n[3] http://thread.gmane.org/gmane.comp.version-control.git/174043/focus=174050\n[4] http://thread.gmane.org/gmane.comp.version-control.git/174393/focus=174540\n[5] http://thread.gmane.org/gmane.comp.version-control.git/174874\n[6] http://thread.gmane.org/gmane.comp.version-control.git/175638\n[7] http://thread.gmane.org/gmane.comp.version-control.git/176139\n[8] http://thread.gmane.org/gmane.comp.version-control.git/176647\n"},{"id":"171136","messageId":"CALkWK0=5ExB0a_VKY=F6m-q4rx0F-uzCgGywj5zsgY5qWxVZjA@mail.gmail.com","threadId":"27786","inReplyTo":"7vvcv8bjmf.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 15/17] revert: Remove sequencer state when no commits are pending","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T06:26:14Z","receivedAt":"2011-07-12T06:26:14Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Junio,\n\nJunio C Hamano wites:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>> diff --git a/builtin/revert.c b/builtin/revert.c\n>> index f9f5e3a..3936516 100644\n>> --- a/builtin/revert.c\n>> +++ b/builtin/revert.c\n>> @@ -990,8 +990,18 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n>>       for (cur = todo_list; cur; cur = cur->next) {\n>>               save_todo(cur, opts);\n>>               res = do_pick_commit(cur->item, opts);\n>> -             if (res)\n>> +             if (res) {\n>> +                     if (!cur->next)\n>> +                             /*\n>> +                              * An error was encountered while\n>> +                              * picking the last commit; the\n>> +                              * sequencer state is useless now --\n>> +                              * the user simply needs to resolve\n>> +                              * the conflict and commit\n>> +                              */\n>> +                             remove_sequencer_state();\n>>                       return res;\n>> +             }\n>>       }\n>\n> It may be useless for --continue, but wouldn't --abort need some clue on\n> what you were doing?\n\nJonathan pointed this out too.  I'd like to know what you think of the\nalternatives\n1. Layering a hack on top: writing .git/sequencer/to-remove or\nsomething as ugly.\n2. Teaching \"git commit\" to remove the sequencer state instead.\n\nActually, an \"--abort\" can be taught to work even here by reading\n.git/sequencer-old/head, but that's arguably ugly too.\n\n-- Ram\n"},{"id":"171137","messageId":"buo1uxwggh9.fsf@dhlpc061.dev.necel.com","threadId":"27786","inReplyTo":"20110711171713.GA5963@elie","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Miles Bader","fromEmail":"miles@gnu.org","sentAt":"2011-07-12T06:28:34Z","receivedAt":"2011-07-12T06:28:34Z","isPatch":false,"sender":{"key":"miles@gnu.org","avatar":"https://gravatar.com/avatar/01069b69593af7bff28e2f97afeb3644ae6fe2f5f56cb3a8cf34c5fb8c36efe5?d=mp&s=160"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n> To be precise, the format used includes\n>\n> \tstrategy-option = patience | renormalize\n>\n> to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n> about that is that the \"|\" can sound like \"or\", which would seem\n> strange to a user that does not necessarily develop software (so is\n> not thinking about bitfields).\n\nHow about using \"+\" instead of \"|\"...?\n\nI think that would make sense both for bitfield-thinking and\nnon-bitfield-thinking readers ... :]\n\n-Miles\n\n-- \nOccam's razor split hairs so well, I bought the whole argument!\n"},{"id":"171141","messageId":"CALkWK0n41LZ8-ZU2M1oD_ddJ2g2A47MxuO8w+5Ew6Php8gvF+g@mail.gmail.com","threadId":"27786","inReplyTo":"20110711221419.GE30155@sigill.intra.peff.net","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T06:41:44Z","receivedAt":"2011-07-12T06:41:44Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jeff, Junio, Jonathan, and Miles,\n\nJeff King writes:\n> On Mon, Jul 11, 2011 at 01:07:20PM -0700, Junio C Hamano wrote:\n>> > To be precise, the format used includes\n>> >\n>> >     strategy-option = patience | renormalize\n>> >\n>> > to represent the effect of \"-Xpatience -Xrenormalize\".  My only worry\n>> > about that is that the \"|\" can sound like \"or\", which would seem\n>> > strange to a user that does not necessarily develop software (so is\n>> > not thinking about bitfields).  The format used in config files puts\n>> >\n>> >     strategy-option = patience\n>> >     strategy-option = renormalize\n>> >\n>> > as separate lines.\n>>\n>> A very good point again. I do not think anywhere in our codebase we use\n>> \"|\" as a separator for state files (either used for internal or exposed to\n>> the end user), and we probably would want to be consistent across\n>> commands.\n>\n> I had the same feeling about the \"|\". I'm a little confused about what\n> these options are good for, though.\n\nMiles Bader writes:\n> How about using \"+\" instead of \"|\"...?\n>\n> I think that would make sense both for bitfield-thinking and\n> non-bitfield-thinking readers ... :]\n\nFrankly, I don't like the idea of separate lines like \"key = value1\"\nand \"key = value 2\" -- even a generic *nix configuration file parser\nwould break here.  Yes, I know that we don't use \"|\" anywhere else; we\ndon't persist options anywhere else either, so I was trying to be\ninventive :p\n\nI didn't realize \"|\" would confuse users -- if that's the case, should\nwe use a different separator like Miles' \"+\" suggestion?\n\nJeff King writes:\n> Is it purely about saving some persistent data between runs, and nobody\n> else is going to look at it? In that case, I don't think it matters what\n> the format is. Use some unambiguous encoding that we already have\n> available (like sq_quote_argv and sq_dequote_argv), and write as little\n> code as possible.\n>\n> Or is it something that, like the information in .git/rebase-apply,\n> people might want to read or tweak? In that case, might it make sense to\n> follow that lead and split things into one file per item? That keeps the\n> parsing burden extremely low for things like shell scripts (or shell\n> users) who might want to read or tweak.\n\nYes, it's a little like the information in .git/rebase-apply.  We\nshould give the user the ability to tweak it by hand: the result from\nsq_quote_argv and sq_dequote_argv would look very ugly.  Hm, I don't\nlike the one-file-per-command-line-option approach because: we might\nonly have a few options now, but when the sequencer is built to\nsupport many actions and options, the directory will be polluted with\nlots of files.  I was thinking more along the lines of something that\ncan be parsed using gitconfig.\n\nThanks.\n\n-- Ram\n"},{"id":"171142","messageId":"20110712064706.GA13375@sigill.intra.peff.net","threadId":"27786","inReplyTo":"CALkWK0n41LZ8-ZU2M1oD_ddJ2g2A47MxuO8w+5Ew6Php8gvF+g@mail.gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-12T06:47:07Z","receivedAt":"2011-07-12T06:47:07Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 12, 2011 at 12:11:44PM +0530, Ramkumar Ramachandra wrote:\n\n> > Or is it something that, like the information in .git/rebase-apply,\n> > people might want to read or tweak? In that case, might it make sense to\n> > follow that lead and split things into one file per item? That keeps the\n> > parsing burden extremely low for things like shell scripts (or shell\n> > users) who might want to read or tweak.\n> \n> Yes, it's a little like the information in .git/rebase-apply.  We\n> should give the user the ability to tweak it by hand: the result from\n> sq_quote_argv and sq_dequote_argv would look very ugly.  Hm, I don't\n> like the one-file-per-command-line-option approach because: we might\n> only have a few options now, but when the sequencer is built to\n> support many actions and options, the directory will be polluted with\n> lots of files.  I was thinking more along the lines of something that\n> can be parsed using gitconfig.\n\nI don't consider having lots of files there \"pollution\", but rather \"a\nwell-used key/value store\". But I suppose it is in the eye of the\nbeholder. :)\n\nUsing git-config is maybe a little more self-documenting than something\nlike \"sq_quote_argv\". And probably not much more code (maybe even less,\nsince it can handle the file update for you).\n\nI recently used the config code to write out a non-standard config file.\nMy two complaints were:\n\n  1. You can't queue up a bunch of changes and then write the file once.\n     Every time you call git_config_set, it rewrites the whole file.\n\n  2. There's no way to write to a nonstandard file short of the horribly\n     hack-ish:\n\n       const char *saved = config_exclusive_filename;\n       config_exclusive_filename = \"foo.conf\";\n       git_config_set(...);\n       config_exclusive_filename = saved;\n\nPoint (2) is pretty easy to fix. But point (1) might be a bit more\ninvolved. I haven't really looked yet.\n\n-Peff\n"},{"id":"171144","messageId":"CALkWK0mT7srC5+Jgk6G5gze+WwVZ-9rJJfCO5OAScaT+YLfZGA@mail.gmail.com","threadId":"27786","inReplyTo":"CALkWK0msdBdXX4oMkd+WAMR8PXTRT3ivjMrf3ZAMfBrsLoM=dQ@mail.gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-12T07:05:32Z","receivedAt":"2011-07-12T07:05:32Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nRamkumar Ramachandra writes:\n> Jonathan Nieder writes:\n>>  - what changed since last time, for each patch?  (For the future, the\n>>   space under the \"---\" is generally a good place to put that\n>>   information.)\n>\n> Will comment a little more on this in the morning.  The main focus of\n> this series is to showcase the new option parser, and show how it fits\n> into the rest of the series.\n\nHere's the full change manifest (from memory; might have missed a few):\nPatch 1: Exposed advise\nPatch 2: No changes.\nPatch 3: No changes.\nPatch 4: No changes.\nPatch 5: No changes.\nPatch 6: No changes (forgot to update commit message)\nPatch 7: No changes.\nPatch 8: No changes.\nPatch 9: Rewrote commit message\nPatch 10: New!\nPatch 11: Updated commit message, rebased on 10.\nPatch 12: New!\nPatch 13: process_continuation => process_subcommand\nPatch 14: New!\nPatch 15: New!\nPatch 16: Near complete rewrite (subcommand, documentation, tests)\nPatch 17: Complete rewrite.\n\nThanks.\n\n-- Ram\n"},{"id":"171158","messageId":"20110712165302.GA13578@elie","threadId":"27786","inReplyTo":"1310396048-24925-3-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T16:53:02Z","receivedAt":"2011-07-12T16:53:02Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> The add_message_to_msg function is poorly implemented, has an unclear\n> API, and only one callsite.  Replace the callsite with a cleaner\n> implementation.  Additionally, fix a bug introduced in 9509af6 (Make\n> git-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\n> was being incremented when \"\\n\\n\" was not found in \"message\".\n\nRather than being an optimization, the main impact of this change is\nto avoid a NULL pointer dereference in some cases, right?\n\nIf so, the subject line should say so.  Is it possible to reproduce\nthis?  Could we add a test to avoid regressing in the future?\n\nLess importantly:\n\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n[...]\n> @@ -462,11 +449,16 @@ static int do_pick_commit(void)\n>  \t\t}\n>  \t\tstrbuf_addstr(&msgbuf, \".\\n\");\n>  \t} else {\n> +\t\tconst char *p = strstr(msg.message, \"\\n\\n\");\n> +\n>  \t\tbase = parent;\n>  \t\tbase_label = msg.parent_label;\n>  \t\tnext = commit;\n>  \t\tnext_label = msg.label;\n> -\t\tadd_message_to_msg(&msgbuf, msg.message);\n> +\n> +\t\tp = p ? p + 2 : sha1_to_hex(commit->object.sha1);\n> +\t\tstrbuf_addstr(&msgbuf, p);\n\nI think this would be clearer like so:\n\n\t\tconst char *p;\n\t\t...\n\t\tp = strstr(...);\n\t\tif (p)\n\t\t\tp += 2;\n\t\telse\n\t\t\tp = sha1_to_hex...\n\t\tstrbuf_addstr(&msgbuf, p);\n\ni.e., putting all the code that manipulates p together.  Besides,\npre-C99 compilers don't like \"p\" to be initialized to a non-constant.\n:)\n\nAt [1], I also see a suggestion of a comment that could clarify the\ncode a little.\n\nHope that helps,\nJonathan\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176139/focus=176183\n"},{"id":"171159","messageId":"20110712165949.GB13578@elie","threadId":"27786","inReplyTo":"1310396048-24925-4-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 03/17] revert: Don't check lone argument in get_encoding","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T16:59:49Z","receivedAt":"2011-07-12T16:59:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> The get_encoding function has only one callsite, and its caller makes\n> sure that a NULL argument isn't passed.  Don't unnecessarily double\n> check the same argument in get_encoding.\n\nSuch a double-check is not a huge maintenance burden, is it?  As I\nmentioned at [1], I am guessing the actual motivation is (1) to avoid\nhaving to pass \"commit\" around and (2) to avoid burdening translators\nwith a message that will never be shown.\n\nWould it be possible to clarify the commit message so it is no longer\nnecessary to guess?\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176139/focus=176166\n"},{"id":"171161","messageId":"20110712170256.GC13578@elie","threadId":"27786","inReplyTo":"1310396048-24925-5-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 04/17] revert: Rename no_replay to record_origin","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T17:02:56Z","receivedAt":"2011-07-12T17:02:56Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Rename the variable corresponding to the \"-x\" command-line option from\n> \"no_replay\" to a more apt \"record_origin\".\n\nWhy is it more apt?  What does \"-x\" do?  Why was it called \"no_replay\"\nbefore?  Is there some other motivation to this change (e.g., does this\npave the way to using the name \"replay\" for something else)?\n"},{"id":"171164","messageId":"20110712173220.GA14120@elie","threadId":"27786","inReplyTo":"1310396048-24925-6-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 05/17] revert: Propogate errors upwards from do_pick_commit","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T17:32:20Z","receivedAt":"2011-07-12T17:32:20Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Currently, the return value from revert_or_cherry_pick is a\n> non-negative number representing the intended exit status from `git\n> revert` or `git cherry-pick`.  Change this by replacing some of the\n> calls to \"die\" with calls to \"error\", so that it can return negative\n> values too.  Postive return values indicate conflicts, while negative\n> ones indicate other errors.  This return status is propogated updwards\n> from do_pick_commit, to be finally handled in cmd_cherry_pick and\n> cmd_revert.\n\nAs mentioned at [1], this accurately describes the effect, but not the\nmotivation.  (In tricky cases like this, knowing the motivation would\nhelp with review immensely.)\n\n[...]\n> While the full benefits of this patch will only be seen once all the\n> \"die\" calls are replaced with calls to \"error\", its immediate impact\n> is to change some of the \"die:\" messages to \"error:\" messages and\n> print a new \"fatal: cherry-pick failed\" message when the operation\n> fails.\n\nI think by \"die:\" you mean \"fatal:\".\n\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n[...]\n> @@ -373,12 +368,12 @@ static int do_pick_commit(void)\n>  \t\t * to work on.\n>  \t\t */\n>  \t\tif (write_cache_as_tree(head, 0, NULL))\n> -\t\t\tdie (_(\"Your index file is unmerged.\"));\n> +\t\t\treturn error(_(\"Your index file is unmerged.\"));\n\nwrite_cache_as_tree() locks the index and does not always commit or\nroll it back except on success.  Current callers aren't likely to try\nto lock the index again (since they just die()), but presumably the\ngoal of returning error() here is to allow for callers that want to\nstay alive and do something more.  How should they recover (i.e., what\nis the intended API)?\n\nSimilar questions probably apply to calls to other APIs that return -1\nto mean \"I failed; please print an appropriate message about that and\nexit\".  I haven't checked carefully, since the answer to this example\ncould help in knowing what to look for in the others.\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176647/focus=176664\n"},{"id":"171166","messageId":"20110712174518.GB14120@elie","threadId":"27786","inReplyTo":"1310396048-24925-7-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T17:45:18Z","receivedAt":"2011-07-12T17:45:18Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Since we want to develop the functionality to either pick or revert\n> individual commits atomically later in the series, make \"commit\" a\n> variable to be passed around explicitly as an argument for clarity.\n\nThe above explanation is not so clear to me, but the patch looks good.\nIsn't the idea something like\n\n\tcommit = grab_a_nice_commit();\n\tres = do_pick_commit();\n\nbeing just an unpleasant API relative to\n\n\tres = do_pick_commit(grab_a_nice_commit());\n\nbecause in the latter it is more obvious which commit is being\ncherry-picked?  Likewise with the functions it calls.\n\nOr perhaps the idea is that eventually we will want to expose something\nlike do_pick_commit to other translation units, but a static variable\nlike \"commit\" would not be appropriate for exposing.  Or that we save\na word of global memory.  Or that this way if do_pick_commit or a\nfunction it calls ever ends up recursing by mistake it won't get\nbroken.  Or that we can use multiple threads some day.  Or...\n\nOh, the uncertainty! :)  It is not clear to me what any of the above\nhave to do with wanting the functionality to replay an individual\ncommit atomically.  By the way, what does pickiing or reverting a\ncommit atomically mean, and how is it different from ordinary\ncherry-picks?\n"},{"id":"171169","messageId":"20110712180549.GC14120@elie","threadId":"27786","inReplyTo":"1310396048-24925-8-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 07/17] revert: Introduce struct to keep command-line options","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T18:05:49Z","receivedAt":"2011-07-12T18:05:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> The variable \"me\" is left as a file-scope static variable because it\n> is not an independent option.  \"me\" is simply a string that needs to\n> be inferred from the \"action\" option, and is kept global to save each\n> function the trouble of determining it independently.\n\nWhy not do something like this[1]?\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176647/focus=176730\n\ndiff --git i/builtin/revert.c w/builtin/revert.c\nindex 63baca85..3161e696 100644\n--- i/builtin/revert.c\n+++ w/builtin/revert.c\n@@ -36,7 +36,6 @@ static const char * const cherry_pick_usage[] = {\n };\n \n static struct commit *commit;\n-static const char *me;\n enum replay_action { REVERT, CHERRY_PICK };\n \n struct replay_opts {\n@@ -69,6 +68,11 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)\n \treturn opts->action == REVERT ? revert_usage : cherry_pick_usage;\n }\n \n+static const char *action_name(const struct replay_opts *opts)\n+{\n+\treturn opts->action == REVERT ? \"revert\" : \"cherry-pick\";\n+}\n+\n static int option_parse_x(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n@@ -280,20 +284,20 @@ static struct tree *empty_tree(void)\n \treturn tree;\n }\n \n-static NORETURN void die_dirty_index(const char *me, enum replay_action action)\n+static NORETURN void die_dirty_index(const struct replay_opts *opts)\n {\n \tif (read_cache_unmerged()) {\n-\t\tdie_resolve_conflict(me);\n+\t\tdie_resolve_conflict(action_name(opts));\n \t} else {\n \t\tif (advice_commit_before_merge) {\n-\t\t\tif (action == REVERT)\n+\t\t\tif (opts->action == REVERT)\n \t\t\t\tdie(_(\"Your local changes would be overwritten by revert.\\n\"\n \t\t\t\t\t  \"Please, commit your changes or stash them to proceed.\"));\n \t\t\telse\n \t\t\t\tdie(_(\"Your local changes would be overwritten by cherry-pick.\\n\"\n \t\t\t\t\t  \"Please, commit your changes or stash them to proceed.\"));\n \t\t} else {\n-\t\t\tif (action == REVERT)\n+\t\t\tif (opts->action == REVERT)\n \t\t\t\tdie(_(\"Your local changes would be overwritten by revert.\\n\"));\n \t\t\telse\n \t\t\t\tdie(_(\"Your local changes would be overwritten by cherry-pick.\\n\"));\n@@ -347,7 +351,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \t    (write_cache(index_fd, active_cache, active_nr) ||\n \t     commit_locked_index(&index_lock)))\n \t\t/* TRANSLATORS: %s will be \"revert\" or \"cherry-pick\" */\n-\t\tdie(_(\"%s: Unable to write new index file\"), me);\n+\t\tdie(_(\"%s: Unable to write new index file\"),\n+\t\t    action_name(opts));\n \trollback_lock_file(&index_lock);\n \n \tif (!clean) {\n@@ -418,7 +423,7 @@ static int do_pick_commit(struct replay_opts *opts)\n \t\tif (get_sha1(\"HEAD\", head))\n \t\t\tdie (_(\"You do not have a valid HEAD\"));\n \t\tif (index_differs_from(\"HEAD\", 0))\n-\t\t\tdie_dirty_index(me, opts->action);\n+\t\t\tdie_dirty_index(opts);\n \t}\n \tdiscard_cache();\n \n@@ -455,7 +460,7 @@ static int do_pick_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\tdie(_(\"%s: cannot parse parent commit %s\"),\n-\t\t    me, sha1_to_hex(parent->object.sha1));\n+\t\t    action_name(opts), sha1_to_hex(parent->object.sha1));\n \n \tif (get_message(commit->buffer, &msg) != 0)\n \t\tdie(_(\"Cannot get commit message for %s\"),\n@@ -557,10 +562,15 @@ static void prepare_revs(struct rev_info *revs, struct replay_opts *opts)\n \t\tdie(_(\"empty commit set passed\"));\n }\n \n-static void read_and_refresh_cache(const char *me, struct replay_opts *opts)\n+static void read_and_refresh_cache(struct replay_opts *opts)\n {\n \tstatic struct lock_file index_lock;\n-\tint index_fd = hold_locked_index(&index_lock, 0);\n+\tint index_fd;\n+\tconst char *me;\n+\n+\tme = action_name(opts);\n+\n+\tindex_fd = hold_locked_index(&index_lock, 0);\n \tif (read_index_preload(&the_index, NULL) < 0)\n \t\tdie(_(\"git %s: failed to read the index\"), me);\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);\n@@ -578,8 +588,7 @@ static int revert_or_cherry_pick(int argc, const char **argv,\n \tstruct rev_info revs;\n \n \tgit_config(git_default_config, NULL);\n-\tme = opts->action == REVERT ? \"revert\" : \"cherry-pick\";\n-\tsetenv(GIT_REFLOG_ACTION, me, 0);\n+\tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n \tparse_args(argc, argv, opts);\n \n \tif (opts->allow_ff) {\n@@ -593,7 +602,7 @@ static int revert_or_cherry_pick(int argc, const char **argv,\n \t\t\tdie(_(\"cherry-pick --ff cannot be used with --edit\"));\n \t}\n \n-\tread_and_refresh_cache(me, opts);\n+\tread_and_refresh_cache(opts);\n \n \tprepare_revs(&revs, opts);\n \n"},{"id":"171171","messageId":"20110712182046.GD14120@elie","threadId":"27786","inReplyTo":"1310396048-24925-9-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 08/17] revert: Separate cmdline parsing from functional code","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T18:20:46Z","receivedAt":"2011-07-12T18:20:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> Currently, revert_or_cherry_pick does too many things including\n> argument parsing and setting up to pick the commits; this doesn't make\n> a good API.\n\nOn the contrary, generally speaking single-call APIs are often very\npleasant to work with.  Consider the difference between\n\n\tstruct compressor c;\n\tmemset(&c, 0, sizeof(c));\n\tinit_compressor(&c);\n\tset_compressor_opts(c, COMPRESSOR_OPT_FAST);\n\tset_compressor_input(\"foo.c\");\n\tset_compressor_output(\"foo.c.compressed\");\n\twhile (compressor_pump() != COMPRESSOR_DONE)\n\t\t; /* just looping */\n\tfini_compressor(&c);\n\nand\n\n\tcompress_file(\"foo.c.compressed\", \"foo.c\", COMPRESSOR_OPT_FAST);\n\nThe latter is more pleasant, right?\n\nSo this is probably not about the function doing too many things but\nsomething else.\n\nBy the way, the API still has the problem described in [1]: it could\nnot be used from another translation unit, since one of the parameters\n(the \"me\" variable) is passed through a global instead of on the stack\nor in registers.\n\nIf the goal is a pleasant API, a good way to explain it is sometimes\n\n\tCurrently you have to do:\n\n\t\t...\n\n\tAfter this change, you can write:\n\n\t\t...\n\n\tIsn't that nice?\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176647/focus=176668\n"},{"id":"171174","messageId":"20110712182958.GE14120@elie","threadId":"27786","inReplyTo":"1310396048-24925-10-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T18:29:58Z","receivedAt":"2011-07-12T18:29:58Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> The \"--ff\" command-line option cannot be used with four other\n> command-line options.\n\nThe above sounds like --ff is a bit of a diva and does not like to\nbe on a commandline with argc >= 6.  But I get the idea.\n\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n"},{"id":"171176","messageId":"20110712185638.GA14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-11-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T18:56:38Z","receivedAt":"2011-07-12T18:56:38Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> The plan to build a generic sequencer involves fist writing the\n> functionality into builtin/revert.c (for cherry-pick and revert), and\n> then factoring it out into sequencer.c and exposing it through\n> sequencer.h as a nice API.  As a prelude to this, announce the\n> location of the sequencer state in sequencer.h and write a function to\n> remove it.\n\nWait, so what is the actual impact of this patch?\n\nAs far as I can tell, it is to introduce a remove_sequencer_state()\nfunction whose eventual purpose would be to remove the .git/sequencer\ndirectory used by \"git cherry-pick\" to record its progress.  Paraphrased,\nthe function does this:\n\n\trm -fr \"$GIT_DIR/sequencer-old\"\n\tmv \"$GIT_DIR/sequencer\" \"$GIT_DIR/sequencer-old\"\n\nThis way, a person has one level of \"undo\" possible, assuming git\ncommands and scripts use the function carefully enough not to call it\ntwice.\n\nIs the \"undo\" feature advertised anywhere?  Should this function write\na message to stderr to inform the operator about how to get back the\nprecious cherry-pick state?\n\nIf I were doing it, I'd squash this with the patch that introduces\n\"git cherry-pick --quit\", to give an example of how the new function is\nmeant to be used (and tests!).\n\n> --- /dev/null\n> +++ b/sequencer.h\n> @@ -0,0 +1,14 @@\n[...]\n> +/* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring\n> + * any errors.  Intended to be used by 'git reset --hard'.\n> + */\n> +void remove_sequencer_state(void);\n\nhttp://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=scripts/checkpatch.pl\n"},{"id":"171179","messageId":"20110712193716.GB14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-12-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T19:37:16Z","receivedAt":"2011-07-12T19:37:16Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> It is imperative to note that these two files alone are not enough to\n> implement \"--continue\"; we will also need to persist the options that\n> were specified on the command-line, and this is done later in the\n> series.\n\nI think you could remove the phrase \"It is imperative to note that\"\nand this would say the same thing. :)\n\nBy the way, those two files are enough to implement --continue in some\nsense, no?  One implementation of --continue would forget options\npassed on the first run and require the user to specify them again; it\nwould just be less useful.  The reminder that \"head\" and \"todo\" are\nnot the only files in the .git/sequencer dir is useful, though; thanks\nfor it.\n\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n[...]\n> +static void format_todo(struct strbuf *buf, struct commit_list *todo_list,\n> +\t\t\tstruct replay_opts *opts)\n> +{\n> +\tstruct commit_list *cur = NULL;\n> +\tstruct commit_message msg = { NULL, NULL, NULL, NULL, NULL };\n> +\tconst char *sha1_abbrev = NULL;\n> +\tconst char *action;\n> +\n> +\taction = (opts->action == REVERT ? \"revert\" : \"pick\");\n> +\tfor (cur = todo_list; cur; cur = cur->next) {\n> +\t\tsha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);\n> +\t\tif (get_message(cur->item, &msg))\n> +\t\t\tdie(_(\"Cannot get commit message for %s\"), sha1_abbrev);\n> +\t\tstrbuf_addf(buf, \"%s %s %s\\n\", action, sha1_abbrev, msg.subject);\n\nThis die() seems odd in the context of a series that starts by\nconverting various die() calls to \"return error()\".\n\n> +static struct commit *parse_insn_line(char *start, struct replay_opts *opts)\n> +{\n> +\tunsigned char commit_sha1[20];\n> +\tchar sha1_abbrev[40];\n> +\tstruct commit *commit;\n> +\tenum replay_action action;\n> +\tint insn_len = 0;\n> +\tchar *p;\n> +\n> +\tp = start;\n> +\tif (!(p = strchr(p, ' ')))\n> +\t\treturn NULL;\n\nStyle: it is much, much clearer to write\n\n\tp = strchr(start, ' ');\n\tif (!p)\n\t\treturn NULL;\n\nIn the git codebase, assignments in \"if\" conditionals are very rare, so\ncode like the above sticks out.\n\n> +\tinsn_len = p - start;\n> +\tif (!(p = strchr(p + 1, ' ')))\n> +\t\treturn NULL;\n> +\tp += 1;\n\nLikewise.  This could say:\n\n\tinsn_len = p - start;\n\tp = strchr(p + 1, ' ');\n\tif (!p)\n\t\treturn NULL;\n\tp++;\n\nor:\n\n\tp = strchrnul(start, ' ');\n\tif (!*p)\n\t\treturn error(\"no commit name in todo file line: %s\", start);\n\tp++;\n\tq = strchrnul(p, ' ');\n\tif (q - p > sizeof(sha1_abbrev) - 1)\n\t\treturn error(\"commit name in todo file is too long: %s\", start);\n\t*mempcpy(sha1_abbrev, p, q - p) = '\\0';\n\n> +\tif (!strncmp(start, \"pick\", insn_len))\n> +\t\taction = CHERRY_PICK;\n> +\telse if (!strncmp(start, \"revert\", insn_len))\n> +\t\taction = REVERT;\n\nThis code means that \"p\", \"pi\", and \"pic\" are accepted as\nabbreviations for \"pick\".   Maybe a comment would help to clarify\nthat.  Are we okay with reserving these names, so \"r\" in a todo\nfile means to \"revert\" and not to \"reword\" like it does in a\nrebase -i todo list?\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\treturn NULL;\n\nIf I try \"git cherry-pick foo..bar\" and then \"git revert --continue\",\nwhat error message will I get?\n\n> +static void read_populate_todo(struct commit_list **todo_list,\n> +\t\t\tstruct replay_opts *opts)\n> +{\n[...]\n> +\tfor (p = buf.buf; *p; p = strchr(p, '\\n') + 1) {\n> +\t\tif (!(commit = parse_insn_line(p, opts)))\n> +\t\t\tgoto error;\n> +\t\tnew = xmalloc(sizeof(struct commit_list));\n> +\t\tnew->item = commit;\n> +\t\t*next = new;\n> +\t\tnext = &new->next;\n\ncommit_list_append()?\n\n> +static void create_seq_dir(void)\n> +{\n> +\tif (file_exists(git_path(SEQ_DIR))) {\n> +\t\tif (!is_directory(git_path(SEQ_DIR)) && remove_path(git_path(SEQ_DIR)) < 0)\n> +\t\t\tdie(_(\"Could not remove %s\"), git_path(SEQ_DIR));\n> +\t} else if (mkdir(git_path(SEQ_DIR), 0777) < 0)\n> +\t\tdie_errno(_(\"Could not create sequencer directory '%s'.\"), git_path(SEQ_DIR));\n> +}\n\nAs mentioned in [1], a local would make this more readable.  And it's\nnot clear to me why one would want to delete a .git/sequencer file\nthat the user carefully placed there (I don't think git itself ever\nwrites such a thing).\n\n> +\n> +static void save_head(const char *head)\n> +{\n> +\tstatic struct lock_file head_lock;\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tint fd;\n> +\n> +\tfd = hold_lock_file_for_update(&head_lock, git_path(SEQ_HEAD_FILE), LOCK_DIE_ON_ERROR);\n> +\tstrbuf_addf(&buf, \"%s\\n\", head);\n> +\tif (write_in_full(fd, buf.buf, buf.len) < 0)\n> +\t\tdie_errno(_(\"Could not write to %s.\"), git_path(SEQ_HEAD_FILE));\n> +\tif (commit_lock_file(&head_lock) < 0)\n> +\t\tdie(_(\"Error wrapping up %s\"), git_path(SEQ_HEAD_FILE));\n> +}\n\nA local would be helpful here, too.\n\n> +static void save_todo(struct commit_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> +\n> +\tfd = hold_lock_file_for_update(&todo_lock, git_path(SEQ_TODO_FILE), LOCK_DIE_ON_ERROR);\n> +\tformat_todo(&buf, todo_list, opts);\n> +\tif (write_in_full(fd, buf.buf, buf.len) < 0) {\n> +\t\tstrbuf_release(&buf);\n> +\t\tdie_errno(_(\"Could not write to %s.\"), git_path(SEQ_TODO_FILE));\n> +\t}\n> +\tif (commit_lock_file(&todo_lock) < 0) {\n> +\t\tstrbuf_release(&buf);\n> +\t\tdie(_(\"Error wrapping up %s\"), git_path(SEQ_TODO_FILE));\n> +\t}\n> +\tstrbuf_release(&buf);\n> +}\n\nLikewise here.  As mentioned before, git_path() clobbers errno, so the\nabove is likely to print a wrong error message on some systems (e.g.,\n\"fatal: Cannot write to .git/sequencer/todo: Success\").\n\n> +\n> +static int pick_commits(struct replay_opts *opts)\n> +{\n> +\tstruct commit_list *todo_list = NULL;\n> +\tunsigned char sha1[20];\n> +\tstruct commit_list *cur;\n> +\tint res;\n>  \n>  \tsetenv(GIT_REFLOG_ACTION, me, 0);\n>  \tif (opts->allow_ff)\n> @@ -580,14 +764,24 @@ static int pick_commits(struct replay_opts *opts)\n>  \t\t\t\topts->record_origin || opts->edit));\n>  \tread_and_refresh_cache(me, opts);\n>  \n> -\tprepare_revs(&revs, opts);\n> +\twalk_revs_populate_todo(&todo_list, opts);\n> +\tcreate_seq_dir();\n> +\tif (!get_sha1(\"HEAD\", sha1))\n> +\t\tsave_head(sha1_to_hex(sha1));\n\nWhat happens if the .git/sequencer dir already exists (e.g., we were\nin the middle of a multiple-cherry-pick)?  What happens if I try to\ncherry-pick onto an unborn branch, or get_sha1() fails for some other\nreason?\n\nRegards,\nJonathan\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/176647/focus=176675\n"},{"id":"171183","messageId":"20110712195246.GC14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-13-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 12/17] revert: Save command-line options for continuing operation","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T19:52:46Z","receivedAt":"2011-07-12T19:52:46Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -596,6 +596,32 @@ struct commit_list **commit_list_append(struct commit *commit,\n>  \treturn &new->next;\n>  }\n>  \n> +static void format_opts(struct strbuf *buf, struct replay_opts *opts)\n> +{\n> +\tint i;\n> +\n> +\tif (opts->no_commit)\n> +\t\tstrbuf_addstr(buf, \"no-commit = true\\n\");\n> +\tif (opts->edit)\n> +\t\tstrbuf_addstr(buf, \"edit = true\\n\");\n[...]\n\nSomewhat repetitive.  Would it make sense to do something like\n\n\tadd_opt_bool(buf, \"no-commit\", opts->no_commit);\n\tadd_opt_bool(buf, \"edit\", opts->edit);\n\tadd_opt_bool(buf, \"signoff\", opts->signoff);\n\tif (opts->mainline)\n\t\tadd_opt_int(buf, \"mainline\", opts->mainline);\n\tadd_opt_string(buf, \"strategy\", opts->strategy);\n\tadd_opt_strings(buf, \"strategy-option\", opts->xopts, opts->xopts_nr);\n\n> @@ -694,6 +720,184 @@ error:\n>  \tdie(_(\"Malformed instruction sheet: %s\"), git_path(SEQ_TODO_FILE));\n>  }\n>  \n> +static struct strbuf *parse_value(const char *start, char **end_ptr)\n> +{\n> +\tstatic struct strbuf value = STRBUF_INIT;\n> +\tint quote = 0;\n> +\tchar *p = (char *)start;\n\nAre all callers passing a modifiable buffer?  If so, why not make the\nparameter non-const?  Is it necessary to modify the buffer to parse it?\n\n> +\tchar *end;\n> +\n> +\t/* Find and strip '\\n', '\\r' */\n> +\tif ((end = strchr(start, '\\n'))) {\n\nStyle:\n\n\tend = strchrnul(start, '\\n');\n\tif (*end && end > start && end[-1] == '\\r')\n\t\tend--;\n\n\tfor (p = start; p != end; p++) {\n\t\t...\n\t}\n\n> +\tfor (; *p != '\\0'; p ++) {\n> +\t\tif (!quote && (*p == ';' || *p == '#'))\n> +\t\t\t/* Ignore comments */\n> +\t\t\tgoto ok;\n> +\t\tif (*p == '\\\\') {\n\nWhat is this syntax?\n\n*thinks*  Oh, this looks eerily similar to config.c::parse_value().\nShouldn't the commit message say so?  Why not factor out a function so\nthey can share code?\n\n> +\t\t\tp += 1;\n[...]\n> +\t\t\t/* Some pharapters escape as themselves */\n\nSubstitution error.\n\n> +static char *parse_opt_value(const char *start, void *key,\n> +\t\t\tenum parse_opt_type type, parse_opt_cb *cb_function)\n> +{\n> +\tstruct strbuf *value, *subvalue;\n> +\tstruct option opt;\n> +\tchar *p, *cur, *val, *end;\n> +\n> +\t/* Remove spaces before '=' */\n> +\tfor (p = (char *)start; isspace(*p); p++);\n\nSame questions apply.  Stopping here.\n\nHope that helps,\nJonathan\n"},{"id":"171185","messageId":"20110712200324.GD14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-14-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 13/17] revert: Introduce a layer of indirection over pick_commits","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T20:03:24Z","receivedAt":"2011-07-12T20:03:24Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Write a new function called process_subcommand to prepare a todo_list\n> to call pick_commits with; the job of pick_commits is simplified into\n> performing the tasks listed in todo_list.  This will be useful when\n> subcommands like \"--reset\" and \"--continue\" are introduced later in\n> the series.\n\nCould you give an example of how this function is used?  The name\n\"process_foo\" does not mean much more to me than \"do_it\" --- i.e., it\ndoes not tell what the function actually does.\n\nLooking at this code, it does not just prepare a todo_list (so\nfill_todo_list would not be a good name for it); it actually calls\npick_commits.  This is the main (only?) entry point to the cherry-pick\nmachinery, so it's worthwhile to give it a good name.  How about\npick_commits?\n\nMeanwhile I would prefer to have multiple entry points to the\ncherry-pick machinery, which would avoid this question altogether,\nthough I imagine you have some reason not to do that.\n\nThe mechanics of the patch (splitting out a separate function for\nthe actual \"for each commit\" loop) look like a good idea.\n"},{"id":"171186","messageId":"20110712201532.GE14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-15-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 14/17] reset: Make hard reset remove the sequencer state","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T20:15:32Z","receivedAt":"2011-07-12T20:15:32Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> Years of muscle memory have trained users to use \"git reset --hard\" to\n> remove away the branch state after any sort of operation.  In\n> retrospect, while this may not have been the best design decision, we\n> are stuck with it for historical reasons.\n\nWait, wait!  If that was a bad design decision, we should try to find\na way to smoothly transition to a world without it, instead of\nlayering workarounds on top of it.\n\nBut actually I think it is good UI.  When you do \"git merge\", it works\nlike this:\n\n\tgit merge <foo>; # conflicts!\n\t... hack hack hack ...\n\t# Oh, bother, let me go back to a state I know well and am\n\t# comfortable with.\n\tgit reset --hard <bar>\n\nAnd the same psychological effect applies in the cherry-pick case:\n\n\tgit cherry-pick <foo>; # conflicts!\n\t... hack hack hack ...\n\t# Oh, bother, let me go back to a state I know well and am\n\t# comfortable with.\n\tgit reset --hard <bar>\n\nSee, it's about the tool working with you.  When I abandon a merge,\nI don't want to have to search through the owner's manual for the\nbutton to get git to clear away this unpleasant and unfamiliar state.\n\nNow, by contrast, sometimes one wants something less aggressive.\nFor example, to abandon a partial merge conflict resolution but\nkeep unrelated changes in the worktree:\n\n\tgit reset --merge HEAD\n\nOr to get out of the \"mergy\" state but leave the worktree alone:\n\n\tgit reset\n\nThere's no porcelain or plumbing to abandon a rebase without\nadditional side-effects, but \"git status\" suggests a command for\nit if I remember correctly.\n\n\trm -fr .git/rebase-merge\n\n[...]\n> Additionally, this patch ensures that some existing tests don't break\n> when features like \"--reset\" and \"--continue\" are introduced later in\n> the series.\n\nThat's not \"Additionally\" --- it's the same problem.  One way to\nphrase it would be \"Noticed by running such-and-such test after\nsuch-and-such change\".\n\n> +test_expect_success 'reset --hard cleans up sequencer state' '\n\nHoorah!  Thanks.\n\nWhy isn't the .git/sequencer removal in remove_branch_state() like\nMERGE_MSG and other similar examples are?  (Not a rhetorical question;\nit would be interesting to know.)\n"},{"id":"171187","messageId":"20110712203011.GF14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-17-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 16/17] revert: Introduce --reset to remove sequencer state","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T20:30:11Z","receivedAt":"2011-07-12T20:30:11Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Protect the sequencer state from accidentally being stomped by a new\n> cherry-pick or revert invocation by ensuring that an existing one\n> isn't in progress.\n\nI first read this as \"an existing sequencer state isn't in progress\".\nBut anyway, if I understand correctly the goal isn't to protect the\nsequencer state from corruption but to protect the user from forgetting\nabout a pending cherry-pick.\n\n> While this patch would normally be expected to\n> break many tests, the earlier patches \"reset: Make hard reset remove\n> the sequencer state\" and \"revert: Remove sequencer state when no\n> commits are pending\" make sure that they don't.\n\nWhy would I expect a nice change to break tests?\n\nI suppose you mean: \"A naive version of this would break the following\nestablished way of working:\n\n\tgit cherry-pick X; # has conflicts\n\tgit reset --hard; # no, no!\n\tgit cherry-pick Y\n\nOr even:\n\n\tgit cherry-pick X; # has conflicts\n\t# ... resolve ...\n\tgit commit\n\tgit cherry-pick Y\n\nBut a previous patch takes care of that by making \"git reset --hard\"\ncancel the pending cherry-pick and by making \"git commit\" clean up\nafter a pending cherry-pick when making the commit that would finish\nit.\"\n\nThe above text quoted with \">\" describes the main impact of the\nchange.  The subject line, on the other hand, describes a less\nimportant part:\n\n> [Subject: revert: Introduce --reset to remove sequencer state]\n\nIs that fixable?  Maybe this could be split into two patches (since it\ndoes two different things), or maybe the subject line could be tweaked\nto describe both.\n\n[...]\n> Ensure that the \"rebase -i\" script which invokes cherry-pick or revert\n> doesn't change its behavior by using '--reset' to to clear the state\n> after every failed pick.\n\nThis should be avoidable by noticing that commands like \"rebase -i\"\nuse GIT_CHERRY_PICK_HELP to clobber our nice instructions about how to\nresume a cherry-pick anyway and therefore are unlikely to need\ncherry-pick --continue/--abort facilities, no?\n\nRegards,\nJonathan\n"},{"id":"171188","messageId":"20110712204650.GG14909@elie","threadId":"27786","inReplyTo":"1310396048-24925-18-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-12T20:46:50Z","receivedAt":"2011-07-12T20:46:50Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Using the information in \".git/sequencer\", it is now possible to\n> continue a cherry-pick or continue after a conflict.  To do this, we\n> have to parse the information in \".git/sequencer/opts\" into the\n> replay_opts structure and\n[...]\n\nMight be simpler to say:\n\n\tIntroduce a new \"git cherry-pick --continue\" command which uses\n\tthe information in \".git/sequencer\" to continue a cherry-pick that\n\tstopped because of a conflict or other error.  It works by dropping\n\tthe first instruction from .git/sequencer/todo and performing the\n\tremaining cherry-picks listed there, with options (think \"-s\" and\n\t\"-X\") from the initial command listed in .git/sequencer/opts.\n\n\tSo now you can do:\n\n\t\t$ git cherry-pick -Xpatience foo..bar\n\t\t... description conflict in commit moo ...\n\t\t$ git cherry-pick --continue\n\t\terror: 'cherry-pick' is not possible because you have unmerged files.\n\t\tfatal: failed to resume cherry-pick\n\t\t$ echo resolved >conflictingfile\n\t\t$ git add conflictingfile && git commit\n\t\t$ git cherry-pick --continue; # resumes with the commit after \"moo\"\n\n> During the \"git commit\" stage, CHERRY_PICK_HEAD will aid by providing\n> the commit message from the conflicting \"moo\" commit.  Note that the\n> cherry-pick mechanism has no control at this stage, so the user is\n> free to violate anything that was specified during the first\n> cherry-pick invocation.  For example, if \"-x\" was specified during the\n> first cherry-pick invocation, the user is free to edit out the message\n> during commit time.  One glitch to note is that the \"--signoff\" option\n> specified at cherry-pick invocation time is not reflected in the\n> commit message provided by CHERRY_PICK_HEAD; the user must take care\n> to add \"--signoff\" during the \"git commit\" invocation.\n\nThe -s thing doesn't have much to do with this change.  But is it a\nbug or not?  If it's not a bug, then this is not so much a glitch to\nnote as an important feature to ensure people don't sign off on a\nconflict resolution without thinking about it.  (I guess I think it's\na bug.  It's hard to decide.)\n\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -101,4 +101,97 @@ test_expect_success '--reset cleans up sequencer state' '\n[...]\n> +test_expect_success '--continue complains when no cherry-pick is in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --continue >actual 2>&1 &&\n> +\ttest_i18ngrep \"error\" actual\n\nThis would start to fail if the message ever changed from \"error\" to\n\"fatal\", right?  I don't think that's a good thing.\n\n> +test_expect_success '--continue complains when there are unresolved conflicts' '\n> +\tpristine_detach initial &&\n> +\thead=$(git rev-parse HEAD) &&\n> +\ttest_must_fail git cherry-pick base..picked &&\n> +\ttest_must_fail git cherry-pick --continue &&\n> +\tgit cherry-pick --reset\n> +'\n> +\n> +test_expect_success '--continue continues after conflicts are resolved' '\n> +\tpristine_detach initial &&\n> +\thead=$(git rev-parse HEAD) &&\n\nHow is $head used?\n\n> +\ttest_must_fail git cherry-pick base..anotherpick &&\n> +\techo \"c\" >foo &&\n> +\tgit add foo &&\n> +\tgit commit &&\n> +\tgit cherry-pick --continue &&\n> +\ttest_path_is_missing .git/sequencer &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/[0-9a-f]\\{40\\}/OBJID/g\"\n> +\t} >actual &&\n\n$_x40 is idiomatic and safer with old seds.\n\n> +test_expect_success '--continue respects opts' '\n> +\tpristine_detach initial &&\n> +\thead=$(git rev-parse HEAD) &&\n> +\ttest_must_fail git cherry-pick -s -x base..anotherpick &&\n> +\techo \"c\" >foo &&\n> +\tgit add foo &&\n> +\tgit commit -s &&\n> +\tgit cherry-pick --continue &&\n> +\ttest_path_is_missing .git/sequencer &&\n> +\tgit cat-file commit HEAD >anotherpick_msg &&\n> +\tgit cat-file commit HEAD~1 >picked_msg &&\n> +\tgit cat-file commit HEAD~2 >unrelatedpick_msg &&\n> +\tgit cat-file commit HEAD~3 >initial_msg &&\n> +\ttest_must_fail test_i18ngrep \"Signed-off-by:\" initial_msg &&\n\nThis will break when GETTEXT_POISON is set --- test_i18ngrep\nautomatically succeeds in that case.\n\nIs \"Signed-off-by\" meant to be translated anyway?  I would use\n\n\t! grep\n\nif testing that.\n\nBy the way, that probably should go in a separate test assertion\n(\"-s is not automatically propagated to resolved conflict\") to make\nit easier to change the behavior later.\n"},{"id":"171200","messageId":"CALkWK0kHutr41aH7OrmW3REV+YBUeHSryA9n62yxyF0qRd1FEw@mail.gmail.com","threadId":"27786","inReplyTo":"20110712165302.GA13578@elie","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T06:00:40Z","receivedAt":"2011-07-13T06:00:40Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>\n>> The add_message_to_msg function is poorly implemented, has an unclear\n>> API, and only one callsite.  Replace the callsite with a cleaner\n>> implementation.  Additionally, fix a bug introduced in 9509af6 (Make\n>> git-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\n>> was being incremented when \"\\n\\n\" was not found in \"message\".\n>\n> Rather than being an optimization, the main impact of this change is\n> to avoid a NULL pointer dereference in some cases, right?\n>\n> If so, the subject line should say so.  Is it possible to reproduce\n> this?  Could we add a test to avoid regressing in the future?\n>\n> Less importantly:\n>\n>> --- a/builtin/revert.c\n>> +++ b/builtin/revert.c\n> [...]\n>> @@ -462,11 +449,16 @@ static int do_pick_commit(void)\n>>               }\n>>               strbuf_addstr(&msgbuf, \".\\n\");\n>>       } else {\n>> +             const char *p = strstr(msg.message, \"\\n\\n\");\n>> +\n>>               base = parent;\n>>               base_label = msg.parent_label;\n>>               next = commit;\n>>               next_label = msg.label;\n>> -             add_message_to_msg(&msgbuf, msg.message);\n>> +\n>> +             p = p ? p + 2 : sha1_to_hex(commit->object.sha1);\n>> +             strbuf_addstr(&msgbuf, p);\n>\n> I think this would be clearer like so:\n>\n>                const char *p;\n>                ...\n>                p = strstr(...);\n>                if (p)\n>                        p += 2;\n>                else\n>                        p = sha1_to_hex...\n>                strbuf_addstr(&msgbuf, p);\n>\n> i.e., putting all the code that manipulates p together.  Besides,\n> pre-C99 compilers don't like \"p\" to be initialized to a non-constant.\n> :)\n>\n> At [1], I also see a suggestion of a comment that could clarify the\n> code a little.\n\nFixed all issues.  The commit message now reads\n\nrevert: Inline add_message_to_msg function\n\nThe add_message_to_msg function is poorly implemented, has an unclear\nAPI, and only one callsite.  Replace the callsite with a cleaner\nimplementation.  Additionally, fix a bug introduced in 9509af6 (Make\ngit-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\nwas being dereferenced when \"\\n\\n\" was not found in \"message\".\n\nThanks.\n\n-- Ram\n"},{"id":"171201","messageId":"CALkWK0mWFvDFdOhQuZK-E-_78YGdXve42NX=Zj6S4BTDu+pTzA@mail.gmail.com","threadId":"27786","inReplyTo":"20110712165949.GB13578@elie","subject":"Re: [PATCH 03/17] revert: Don't check lone argument in get_encoding","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T06:14:09Z","receivedAt":"2011-07-13T06:14:09Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> The get_encoding function has only one callsite, and its caller makes\n>> sure that a NULL argument isn't passed.  Don't unnecessarily double\n>> check the same argument in get_encoding.\n>\n> Such a double-check is not a huge maintenance burden, is it?  As I\n> mentioned at [1], I am guessing the actual motivation is (1) to avoid\n> having to pass \"commit\" around and (2) to avoid burdening translators\n> with a message that will never be shown.\n>\n> Would it be possible to clarify the commit message so it is no longer\n> necessary to guess?\n\nI should have done this earlier.  Thanks for being so patient :)\n\nrevert: Don't check lone argument in get_encoding\n\nThe get_encoding function has only one callsite, and its caller makes\nsure that a NULL argument isn't passed.  Don't unnecessarily double\ncheck the same argument in get_encoding.  As a result, avoid passing\n\"commit\" around, and remove a string marked for translation that will\nnever be shown.\n\n-- Ram\n"},{"id":"171202","messageId":"20110713063011.GB31003@elie","threadId":"27786","inReplyTo":"CALkWK0mWFvDFdOhQuZK-E-_78YGdXve42NX=Zj6S4BTDu+pTzA@mail.gmail.com","subject":"Re: [PATCH 03/17] revert: Don't check lone argument in get_encoding","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-13T06:30:11Z","receivedAt":"2011-07-13T06:30:11Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> I should have done this earlier.  Thanks for being so patient :)\n>\n> revert: Don't check lone argument in get_encoding\n>\n> The get_encoding function has only one callsite, and its caller makes\n> sure that a NULL argument isn't passed.  Don't unnecessarily double\n> check the same argument in get_encoding.  As a result, avoid passing\n> \"commit\" around, and remove a string marked for translation that will\n> never be shown.\n\nGetting closer.  This still leaves the motivation unclear --- when I\nread it it sounds to me like you're saying that avoiding unnecessary\ncode is the motivation, and that not passing \"commit\" around and\nremoving a string marked for translation are means to that end.\n"},{"id":"171204","messageId":"20110713064240.GC31003@elie","threadId":"27786","inReplyTo":"CALkWK0kHutr41aH7OrmW3REV+YBUeHSryA9n62yxyF0qRd1FEw@mail.gmail.com","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-13T06:42:40Z","receivedAt":"2011-07-13T06:42:40Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> Fixed all issues.  The commit message now reads\n>\n> revert: Inline add_message_to_msg function\n>\n> The add_message_to_msg function is poorly implemented, has an unclear\n> API, and only one callsite.  Replace the callsite with a cleaner\n> implementation.  Additionally, fix a bug introduced in 9509af6 (Make\n> git-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\n> was being dereferenced when \"\\n\\n\" was not found in \"message\".\n\nThat's basically the same as before, with \"dereferenced\" in place of\n\"incremented\".  An improvement, sure, but it still doesn't answer the\nbasic questions like \"how can I reproduce the bug?\".\n\nSo no, in the commit message at least I don't think all issues are\nfixed.  The subject line says the idea is to inline this function, but\nit's actually a behavior change.  The description of the behavior\nchange makes reference to a variable \"message\" without saying what the\ncontent of that variable is --- e.g., will trying to cherry-pick a\ncommit with a one-line commit message trigger this bug?  (No, it\nwon't.)\n\nAnd honestly, making that small change and calling it fixed just feels\nhalf-hearted and rushed.  After changing it, did you look back over\nthe message, read it as though unknowledgeable about the patch, and\ndecide whether it conveyed the right impression, which is the\nequivalent of testing when writing documentation?\n"},{"id":"171207","messageId":"CALkWK0k3muAi_h7GRqgJ9vY8SwHK40-AwMdjA=uCDO8Ng4utCA@mail.gmail.com","threadId":"27786","inReplyTo":"20110712174518.GB14120@elie","subject":"Re: [PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T06:57:58Z","receivedAt":"2011-07-13T06:57:58Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Since we want to develop the functionality to either pick or revert\n>> individual commits atomically later in the series, make \"commit\" a\n>> variable to be passed around explicitly as an argument for clarity.\n>\n> The above explanation is not so clear to me, but the patch looks good.\n> Isn't the idea something like\n>\n>        commit = grab_a_nice_commit();\n>        res = do_pick_commit();\n>\n> being just an unpleasant API relative to\n>\n>        res = do_pick_commit(grab_a_nice_commit());\n>\n> because in the latter it is more obvious which commit is being\n> cherry-picked?  Likewise with the functions it calls.\n>\n> Or perhaps the idea is that eventually we will want to expose something\n> like do_pick_commit to other translation units, but a static variable\n> like \"commit\" would not be appropriate for exposing.  Or that we save\n> a word of global memory.  Or that this way if do_pick_commit or a\n> function it calls ever ends up recursing by mistake it won't get\n> broken.  Or that we can use multiple threads some day.  Or...\n>\n> Oh, the uncertainty! :)  It is not clear to me what any of the above\n> have to do with wanting the functionality to replay an individual\n> commit atomically.  By the way, what does pickiing or reverting a\n> commit atomically mean, and how is it different from ordinary\n> cherry-picks?\n\nRight.  How about this?\n\nrevert: Eliminate global \"commit\" variable\n\nFunctions which act on commits currently rely on a file-scope static\nvariable to be set before they're called.  Consequently, the API and\ncorresponding callsites are ugly and unclear.  Remove this variable\nand change their API to accept the commit to act on as additional\nargument so that the callsites change from looking like\n\ncommit = prepare_a_commit();\nact_on_commit();\n\nto looking like\n\ncommit = prepare_a_commit();\nact_on_commit(commit);\n\nThis change is also in line with our long-term goal of exposing some\nof these functions through a public API.\n\n-- Ram\n"},{"id":"171213","messageId":"20110713071029.GA31285@elie","threadId":"27786","inReplyTo":"CALkWK0k3muAi_h7GRqgJ9vY8SwHK40-AwMdjA=uCDO8Ng4utCA@mail.gmail.com","subject":"Re: [PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-13T07:10:29Z","receivedAt":"2011-07-13T07:10:29Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Right.  How about this?\n>\n> revert: Eliminate global \"commit\" variable\n>\n> Functions which act on commits currently rely on a file-scope static\n> variable to be set before they're called.  Consequently, the API and\n> corresponding callsites are ugly and unclear.  Remove this variable\n> and change their API to accept the commit to act on as additional\n> argument so that the callsites change from looking like\n>\n> commit = prepare_a_commit();\n> act_on_commit();\n>\n> to looking like\n>\n> commit = prepare_a_commit();\n> act_on_commit(commit);\n>\n> This change is also in line with our long-term goal of exposing some\n> of these functions through a public API.\n\nSounds fine to me.  I could nitpick by saying that \"Functions which\nact on commits\" is a little vague (I think the actual story is\nsomething like \"The global 'commit' variable used to represent one of\nthe arguments passed to 'git cherry-pick' or 'git revert' and thus was\nstatic along with the options.  When cherry-pick learned to replay\nmultiple commits in sequence, that wasn't changed, resulting in a\nsomewhat unnatural calling sequence that uses a global to pass in a\nparameters:\n\n\tfor each commit c {\n\t\tcommit = c;\n\t\tres = do_pick_commit();\n\t\tif (res)\n\t\t\treturn res;\n\t}\n\nTeach do_pick_commit and the functions it calls to accept the commit\nto act on as an argument, like we always should have.  Part of a\ncampaign to clean up cherry-pick/revert's internal APIs before\nexposing them.\")\n"},{"id":"171217","messageId":"CALkWK0nm-gX9-3pGxT31VO-06mimd0cg1O8xhk-0QbsbdN7aLg@mail.gmail.com","threadId":"27786","inReplyTo":"20110712170256.GC13578@elie","subject":"Re: [PATCH 04/17] revert: Rename no_replay to record_origin","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T07:35:55Z","receivedAt":"2011-07-13T07:35:55Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Rename the variable corresponding to the \"-x\" command-line option from\n>> \"no_replay\" to a more apt \"record_origin\".\n>\n> Why is it more apt?  What does \"-x\" do?  Why was it called \"no_replay\"\n> before?  Is there some other motivation to this change (e.g., does this\n> pave the way to using the name \"replay\" for something else)?\n\nThanks for probing.  Found out the reason after some digging.\n\nrevert: Rename no_replay to record_origin\n\nThe \"-x\" command-line option is used to record the name of the\noriginal commits being picked in the commit message.  The variable\ncorresponding to this option is named \"no_replay\" for historical\nreasons.  This name was introduced in f810379 (Make builtin-revert.c\nuse parse_options, 2007-10-07) to replace \"replay\", the opposite of\n\"no_replay\".  The name \"replay\" was introduced in 9509af6 (Make\ngit-revert & git-cherry-pick a builtin, 2007-03-01).  Back then, \"-x\"\nwas the only command-line option that modified the commit message of\nthe commit being picked, and was in effect replaying a slightly\ndifferent commit; hence the names \"replay\" and \"no_replay\".\n\nToday, there are many other options like \"-s\" which append various\nthings to the commit message, and the term \"replay\" doesn't mean what\nit used to.  So, give the variable corresponding to the \"-x\"\ncommand-line option a better name: \"record_origin\".\n\n-- Ram\n"},{"id":"171218","messageId":"CALkWK0n6gOBC4ET5E+_R9x2_gxqxO1ZUP9wwVVcbXvSXgqPQmA@mail.gmail.com","threadId":"27786","inReplyTo":"20110712180549.GC14120@elie","subject":"Re: [PATCH 07/17] revert: Introduce struct to keep command-line options","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T07:56:04Z","receivedAt":"2011-07-13T07:56:04Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> The variable \"me\" is left as a file-scope static variable because it\n>> is not an independent option.  \"me\" is simply a string that needs to\n>> be inferred from the \"action\" option, and is kept global to save each\n>> function the trouble of determining it independently.\n>\n> Why not do something like this[1]?\n>\n> [1] http://thread.gmane.org/gmane.comp.version-control.git/176647/focus=176730\n\nFixed and rebased all.  Thanks.\n\nrevert: Introduce struct to keep command-line options\n\nThe current code uses a set of file-scope static variables to tell the\ncherry-pick/ revert machinery how to replay the changes, and\ninitializes them by parsing the command-line arguments.  In later\nsteps in this series, we would like to introduce an API function that\ncalls into this machinery directly and have a way to tell it what to\ndo.  Hence, introduce a structure to group these variables, so that\nthe API can take them as a single replay_options parameter.  The only\nexception is the variable \"me\" -- remove it since it not an\nindependent option, and can be inferred from the action.\n\nUnfortunately, this patch introduces a minor regression.  Parsing\nstrategy-option violates a C89 rule: Initializers cannot refer to\nvariables whose address is not known at compile time.  Currently, this\nrule is violated by some other parts of Git as well, and it is\npossible to get GCC to report these instances using the \"-std=c89\n-pedantic\" option.\n\n-- Ram\n"},{"id":"171222","messageId":"CALkWK0mUbEXCjUYVPi8Kvctkh0+bnnk0VoAHjUjT_8M5druzqQ@mail.gmail.com","threadId":"27786","inReplyTo":"20110713071029.GA31285@elie","subject":"Re: [PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T08:33:22Z","receivedAt":"2011-07-13T08:33:22Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Sounds fine to me.  I could nitpick by saying that \"Functions which\n> act on commits\" is a little vague (I think the actual story is\n> something like \"The global 'commit' variable used to represent one of\n> the arguments passed to 'git cherry-pick' or 'git revert' and thus was\n> static along with the options.  When cherry-pick learned to replay\n> multiple commits in sequence, that wasn't changed, resulting in a\n> somewhat unnatural calling sequence that uses a global to pass in a\n> parameters:\n>\n>        for each commit c {\n>                commit = c;\n>                res = do_pick_commit();\n>                if (res)\n>                        return res;\n>        }\n>\n> Teach do_pick_commit and the functions it calls to accept the commit\n> to act on as an argument, like we always should have.  Part of a\n> campaign to clean up cherry-pick/revert's internal APIs before\n> exposing them.\")\n\nYes.  Thanks.  How about this?\n\nrevert: Eliminate global \"commit\" variable\n\nPrior to v1.7.2-rc1~4^2~7 (revert: allow cherry-picking more than one\ncommit, 2010-06-02), the file-scope static \"commit\" variable used to\nrepresent one of the arguments passed to the \"git cherry-pick\" or \"git\nrevert\".  This was not changed after cherry-pick learnt to replay\nmultiple commits in a sequence, resulting in ugly and unclear\ncallsites which rely on setting the global variable before calling a\nfunction to act on it:\n\nfor each c in commits {\n    commit = c;\n    act_on_commit();\n}\n\n\nRemove the global variable and modify the API of various functions to\npass \"commit\" around as an argument, so that the callsites become\nclearer:\n\nfor each c in commits {\n    act_on_commit(c);\n}\n\nThe change is also in line with our long-term goal of exposing the\ncherry-picking machinery through a public API.\n\n-- Ram\n"},{"id":"171229","messageId":"CALkWK0=EDZ9E1qYg=bEt2h3jmUUvERoiR1TpkUupRO2XrYyt9A@mail.gmail.com","threadId":"27786","inReplyTo":"20110712064706.GA13375@sigill.intra.peff.net","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-13T09:41:54Z","receivedAt":"2011-07-13T09:41:54Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jeff,\n\nJeff King writes:\n> On Tue, Jul 12, 2011 at 12:11:44PM +0530, Ramkumar Ramachandra wrote:\n>> Yes, it's a little like the information in .git/rebase-apply.  We\n>> should give the user the ability to tweak it by hand: the result from\n>> sq_quote_argv and sq_dequote_argv would look very ugly.  Hm, I don't\n>> like the one-file-per-command-line-option approach because: we might\n>> only have a few options now, but when the sequencer is built to\n>> support many actions and options, the directory will be polluted with\n>> lots of files.  I was thinking more along the lines of something that\n>> can be parsed using gitconfig.\n>\n> I don't consider having lots of files there \"pollution\", but rather \"a\n> well-used key/value store\". But I suppose it is in the eye of the\n> beholder. :)\n\nHa, true.  After all .git/objects/ is \"polluted\" with lots of files :p\nA couple of questions arise:\n1. Would opening, writing, closing many files not put too much strain\non I/O, and hence affect performance significantly?\n2. Will two options from different instructions (when we extend the\ninstruction sheet to accommodate them) have the same name, but\ndifferent effects?  Having a gitconfig-like configuration file doesn't\nsolve this problem either, so it's not a \"configfile versus key-value\nstore\" question.\n\n> Using git-config is maybe a little more self-documenting than something\n> like \"sq_quote_argv\". And probably not much more code (maybe even less,\n> since it can handle the file update for you).\n\nYeah :)\n\n> I recently used the config code to write out a non-standard config file.\n> My two complaints were:\n>\n>  1. You can't queue up a bunch of changes and then write the file once.\n>     Every time you call git_config_set, it rewrites the whole file.\n>\n>  2. There's no way to write to a nonstandard file short of the horribly\n>     hack-ish:\n>\n>       const char *saved = config_exclusive_filename;\n>       config_exclusive_filename = \"foo.conf\";\n>       git_config_set(...);\n>       config_exclusive_filename = saved;\n>\n> Point (2) is pretty easy to fix. But point (1) might be a bit more\n> involved. I haven't really looked yet.\n\nThanks for pointing these out.  Yes, I'm aware of these issues, and\nit's part of the reason I implemented my own parser.  It'll take some\ntime to refactor config.c so that it's usable by others in a sane\nmanner, no?  What do you suggest I do until then?  Can I try to get my\ncustom parser merged (and replaced by a more generic configparser when\nit's ready), or should I throw away my parser and go with the\nkey-value store?\n\nJust to clarify, here's an example to illustrate what I understand\nwhen you say key-value store (please correct me if I got the idea\nwrong):\n.git/sequencer/opts/ will have files like:\n$ cat ff\ntrue\n$ cat record-origin\ntrue\n$ cat mainline\n1\n$ cat strategy\nours\n$ cat strategy-option\npatience + renormalize\n\n-- Ram\n"},{"id":"171232","messageId":"CAGdFq_ijTh-m7+zRFAyqvhN5k_BrC1TPdc3y47h=tBUiz6QF2A@mail.gmail.com","threadId":"27786","inReplyTo":"20110712185638.GA14909@elie","subject":"Re: [PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2011-07-13T12:10:54Z","receivedAt":"2011-07-13T12:10:54Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Tue, Jul 12, 2011 at 20:56, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> As far as I can tell, it is to introduce a remove_sequencer_state()\n> function whose eventual purpose would be to remove the .git/sequencer\n> directory used by \"git cherry-pick\" to record its progress.  Paraphrased,\n> the function does this:\n\nI think we can learn from hg here and just use a datetime stamp. So\ninstead of moving to sequencer-old move to sequencer-20110713-141022\nor such. That way there's as many undo as you need.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"171267","messageId":"20110713164031.GB747@elie","threadId":"27786","inReplyTo":"CALkWK0mUbEXCjUYVPi8Kvctkh0+bnnk0VoAHjUjT_8M5druzqQ@mail.gmail.com","subject":"Re: [PATCH 06/17] revert: Eliminate global \"commit\" variable","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-13T16:40:31Z","receivedAt":"2011-07-13T16:40:31Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Yes.  Thanks.  How about this?\n>\n> revert: Eliminate global \"commit\" variable\n>\n> Prior to v1.7.2-rc1~4^2~7 (revert: allow cherry-picking more than one\n> commit, 2010-06-02), the file-scope static \"commit\" variable used to\n> represent one of the arguments passed to the \"git cherry-pick\" or \"git\n> revert\".  This was not changed after cherry-pick learnt to replay\n\nMeh, I prefer the version starting with \"Functions which act on\ncommits\", which was already readable and not too confusing.\n\nThe point of the just-so story I wrote is that the \"commit\" variable\nwas probably static _because_ of an analogy with command-line options\nthat needed to be static to be pointed to by the \"struct options\"\ninitializer.  But that is not a very important detail; it just helped\nmy understanding.\n\nRegards,\nJonatahn\n"},{"id":"171277","messageId":"20110713190724.GA31965@sigill.intra.peff.net","threadId":"27786","inReplyTo":"CALkWK0=EDZ9E1qYg=bEt2h3jmUUvERoiR1TpkUupRO2XrYyt9A@mail.gmail.com","subject":"Re: [GSoC update] Sequencer for inclusion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-13T19:07:24Z","receivedAt":"2011-07-13T19:07:24Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jul 13, 2011 at 03:11:54PM +0530, Ramkumar Ramachandra wrote:\n\n> Ha, true.  After all .git/objects/ is \"polluted\" with lots of files :p\n> A couple of questions arise:\n> 1. Would opening, writing, closing many files not put too much strain\n> on I/O, and hence affect performance significantly?\n\nIn a tight loop, perhaps. At the begining of invoking a program,\nprobably not. We're talking about what, a dozen or so files?\n\nIf you have doubts, then measure.\n\n> 2. Will two options from different instructions (when we extend the\n> instruction sheet to accommodate them) have the same name, but\n> different effects?  Having a gitconfig-like configuration file doesn't\n> solve this problem either, so it's not a \"configfile versus key-value\n> store\" question.\n\nIf you have per-instruction options, then I think you would want your\nstorage of options to be per-instruction. Whether it's a config file or\nfiles in a directory, you'd want to be accessing \".../opts/$hash\" as a\nconfig file (or \".../opts/$hash/*\" for a directory).\n\nBut I have only been paying a little attention to the deeper parts of\nthis topic, so I may be misunderstanding what you're asking.\n\n> > Using git-config is maybe a little more self-documenting than something\n> > like \"sq_quote_argv\". And probably not much more code (maybe even less,\n> > since it can handle the file update for you).\n> \n> Yeah :)\n\nOne other advantage of \"git config\" over sq_quote_argv is that it is\nfairly transparent to outside programs. You can just say \"git config\n--file=.git/sequencer/opts --get-all strategy\" or whatever.\n\nThat transparency is one of the things I liked about the \"files in a\ndirectory\" approach taken by rebase currently. But given that the \"git\nconfig\" command exists, they are probably equivalent in that respect.\n\n> > I recently used the config code to write out a non-standard config file.\n> > My two complaints were:\n> >\n> >  1. You can't queue up a bunch of changes and then write the file once.\n> >     Every time you call git_config_set, it rewrites the whole file.\n> >\n> >  2. There's no way to write to a nonstandard file short of the horribly\n> >     hack-ish:\n> >\n> >       const char *saved = config_exclusive_filename;\n> >       config_exclusive_filename = \"foo.conf\";\n> >       git_config_set(...);\n> >       config_exclusive_filename = saved;\n> >\n> > Point (2) is pretty easy to fix. But point (1) might be a bit more\n> > involved. I haven't really looked yet.\n> \n> Thanks for pointing these out.  Yes, I'm aware of these issues, and\n> it's part of the reason I implemented my own parser.  It'll take some\n> time to refactor config.c so that it's usable by others in a sane\n> manner, no?  What do you suggest I do until then?  Can I try to get my\n> custom parser merged (and replaced by a more generic configparser when\n> it's ready), or should I throw away my parser and go with the\n> key-value store?\n\nI think a reasonable strategy is:\n\n  1. Refactor git_config_set into git_config_set_in_file with a file\n     argument (and make git_config_set a wrapper that uses the current\n     file-selection). This should be easy to do.\n\n  2. Ignore the fact that you are writing the file multiple times. It's\n     not a correctness issue, but rather an optimization. If and when\n     the config code shows itself to be too slow, then we can do that\n     optimization (which will benefit not just your code, but all config\n     writers).\n\nAnd then throw away your parser and just use git_config_from_file and\ngit_config_set_in_file.\n\nBetween config and a key/value store of files, I think it is largely a\nmatter of taste.\n\n> Just to clarify, here's an example to illustrate what I understand\n> when you say key-value store (please correct me if I got the idea\n> wrong):\n> .git/sequencer/opts/ will have files like:\n> $ cat ff\n> true\n> $ cat record-origin\n> true\n> $ cat mainline\n> 1\n> $ cat strategy\n> ours\n> $ cat strategy-option\n> patience + renormalize\n\nYeah, exactly. Though I would probably use \"\\n\" to split list items in\nstrategy-options, which is a little more traditional. I.e.,:\n\n  $ cat strategy-option\n  patience\n  renormalize\n\n-Peff\n"},{"id":"171497","messageId":"CALkWK0=6A=2z5BShsiHeMCS2Movn+L3V4P1WJTTQ-HexTasAhg@mail.gmail.com","threadId":"27786","inReplyTo":"20110712173220.GA14120@elie","subject":"Re: [PATCH 05/17] revert: Propogate errors upwards from do_pick_commit","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T10:46:08Z","receivedAt":"2011-07-17T10:46:08Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Currently, the return value from revert_or_cherry_pick is a\n>> non-negative number representing the intended exit status from `git\n>> revert` or `git cherry-pick`.  Change this by replacing some of the\n>> calls to \"die\" with calls to \"error\", so that it can return negative\n>> values too.  Postive return values indicate conflicts, while negative\n>> ones indicate other errors.  This return status is propogated updwards\n>> from do_pick_commit, to be finally handled in cmd_cherry_pick and\n>> cmd_revert.\n>\n> As mentioned at [1], this accurately describes the effect, but not the\n> motivation.  (In tricky cases like this, knowing the motivation would\n> help with review immensely.)\n\nSorry, I should have done this earlier.  Does this look alright?\n\nrevert: Propogate errors upwards from do_pick_commit\n\nCurrently, revert_or_cherry_pick can fail in two ways.  If it\nencounters a conflict, it returns a positive number indicating the\nintended exit status for the git wrapper to pass on; for all other\nerrors, it calls die().  The latter behavior is inconsiderate towards\ncallers, as it denies them the opportunity to do some post-processing\nor cleanup before exiting.  For instance, later in the series, callers\nwill want to save some data about the current operation before\nexiting.\n\nChange this by replacing some of the calls to \"die\" with calls to\n\"error\", so that revert_or_cherry_pick can return negative values too.\nWhile postive return values indicate conflicts as before, negative\nones indicate other errors.  This return status is propogated updwards\nfrom do_pick_commit, to be finally handled in cmd_cherry_pick and\ncmd_revert.\n\nIn the same spirit, also introduce a new function error_dirty_index,\nbased on die_dirty_index, which prints some hints and returns an error\nto its caller do_pick_commit.\n\nWhile the full benefits of this patch will only be seen once all the\n\"die\" calls are replaced with calls to \"error\", its immediate impact\nis to change some of the \"fatal:\" messages to \"error:\" messages and\nprint a new \"fatal: cherry-pick failed\" message when the operation\nfails.\n\n\n>> --- a/builtin/revert.c\n>> +++ b/builtin/revert.c\n> [...]\n>> @@ -373,12 +368,12 @@ static int do_pick_commit(void)\n>>                * to work on.\n>>                */\n>>               if (write_cache_as_tree(head, 0, NULL))\n>> -                     die (_(\"Your index file is unmerged.\"));\n>> +                     return error(_(\"Your index file is unmerged.\"));\n>\n> write_cache_as_tree() locks the index and does not always commit or\n> roll it back except on success.  Current callers aren't likely to try\n> to lock the index again (since they just die()), but presumably the\n> goal of returning error() here is to allow for callers that want to\n> stay alive and do something more.  How should they recover (i.e., what\n> is the intended API)?\n\nHm, there was supposed to be a discard_cache() before this error as I\nrecall -- fixed now.  Thanks for catching.\n\n> Similar questions probably apply to calls to other APIs that return -1\n> to mean \"I failed; please print an appropriate message about that and\n> exit\".  I haven't checked carefully, since the answer to this example\n> could help in knowing what to look for in the others.\n\nI think the others are fairly clear actually.  Let me know if you find\nsomething.\n\n-- Ram\n"},{"id":"171499","messageId":"CALkWK0nyu6W2Nd=qcrjZZwkAdFGqTqAe53FmecS_n2cK_4UWMg@mail.gmail.com","threadId":"27786","inReplyTo":"20110712193716.GB14909@elie","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T11:48:31Z","receivedAt":"2011-07-17T11:48:31Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>\n>> It is imperative to note that these two files alone are not enough to\n>> implement \"--continue\"; we will also need to persist the options that\n>> were specified on the command-line, and this is done later in the\n>> series.\n>\n> I think you could remove the phrase \"It is imperative to note that\"\n> and this would say the same thing. :)\n>\n> By the way, those two files are enough to implement --continue in some\n> sense, no?  One implementation of --continue would forget options\n> passed on the first run and require the user to specify them again; it\n> would just be less useful.  The reminder that \"head\" and \"todo\" are\n> not the only files in the .git/sequencer dir is useful, though; thanks\n> for it.\n\nNew commit message:\n\nrevert: Save data for continuing after conflict resolution\n\nEver since v1.7.2-rc1~4^2~7 (revert: allow cherry-picking more than\none commit, 2010-06-02), a single invocation of \"git cherry-pick\" or\n\"git revert\" can perform picks of several individual commits.  To\nimplement features like \"--continue\" to continue the whole operation,\nwe will need to store some information about the state and the plan at\nthe beginning.  Introduce a \".git/sequencer/head\" file to store this\nstate, and \".git/sequencer/todo\" file to store the plan.  The head\nfile contains the SHA-1 of the HEAD before the start of the operation,\nand the todo file contains an instruction sheet whose format is\ninspired by the format of the \"rebase -i\" instruction sheet.  As a\nresult, a typical todo file looks like:\n\npick 8537f0e submodule add: test failure when url is not configured\npick 4d68932 submodule add: allow relative repository path\npick f22a17e submodule add: clean up duplicated code\npick 59a5775 make copy_ref globally available\n\nSince SHA-1 hex is abbreviated using an find_unique_abbrev(), it is\nunambiguous.  This does not guarantee that there will be no ambiguity\nwhen more objects are added to the repository.\n\nThat these two files alone are not enough to implement a \"--continue\"\nthat remembers the command-line options specified; later patches in\nthe series save them too.\n\nThese new files are unrelated to the existing .git/CHERRY_PICK_HEAD,\nwhich will still be useful while committing after a conflict\nresolution.\n\n>> --- a/builtin/revert.c\n>> +++ b/builtin/revert.c\n> [...]\n>> +static void format_todo(struct strbuf *buf, struct commit_list *todo_list,\n>> +                     struct replay_opts *opts)\n>> +{\n>> +     struct commit_list *cur = NULL;\n>> +     struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };\n>> +     const char *sha1_abbrev = NULL;\n>> +     const char *action;\n>> +\n>> +     action = (opts->action == REVERT ? \"revert\" : \"pick\");\n>> +     for (cur = todo_list; cur; cur = cur->next) {\n>> +             sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);\n>> +             if (get_message(cur->item, &msg))\n>> +                     die(_(\"Cannot get commit message for %s\"), sha1_abbrev);\n>> +             strbuf_addf(buf, \"%s %s %s\\n\", action, sha1_abbrev, msg.subject);\n>\n> This die() seems odd in the context of a series that starts by\n> converting various die() calls to \"return error()\".\n\nFixed.  I made format_todo return an int now.\n\n>> +static struct commit *parse_insn_line(char *start, struct replay_opts *opts)\n>> +{\n>> +     unsigned char commit_sha1[20];\n>> +     char sha1_abbrev[40];\n>> +     struct commit *commit;\n>> +     enum replay_action action;\n>> +     int insn_len = 0;\n>> +     char *p;\n>> +\n>> +     p = start;\n>> +     if (!(p = strchr(p, ' ')))\n>> +             return NULL;\n>\n> Style: it is much, much clearer to write\n>\n>        p = strchr(start, ' ');\n>        if (!p)\n>                return NULL;\n>\n> In the git codebase, assignments in \"if\" conditionals are very rare, so\n> code like the above sticks out.\n>\n>> +     insn_len = p - start;\n>> +     if (!(p = strchr(p + 1, ' ')))\n>> +             return NULL;\n>> +     p += 1;\n>\n> Likewise.  This could say:\n>\n>        insn_len = p - start;\n>        p = strchr(p + 1, ' ');\n>        if (!p)\n>                return NULL;\n>        p++;\n\nRight, got it.  Fixed.\n\n>> +     if (!strncmp(start, \"pick\", insn_len))\n>> +             action = CHERRY_PICK;\n>> +     else if (!strncmp(start, \"revert\", insn_len))\n>> +             action = REVERT;\n>\n> This code means that \"p\", \"pi\", and \"pic\" are accepted as\n> abbreviations for \"pick\".   Maybe a comment would help to clarify\n> that.  Are we okay with reserving these names, so \"r\" in a todo\n> file means to \"revert\" and not to \"reword\" like it does in a\n> rebase -i todo list?\n\nThat was the original intent, but I clearly hadn't thought about it\nhard enough.  Changed this to accept only full words.\n\n>> +     /*\n>> +      * Verify that the action matches up with the one in\n>> +      * opts; we don't support arbitrary instructions\n>> +      */\n>> +     if (action != opts->action)\n>> +             return NULL;\n>\n> If I try \"git cherry-pick foo..bar\" and then \"git revert --continue\",\n> what error message will I get?\n\nfatal: Malformed instruction sheet: .git/sequencer/todo\nTechnically speaking, this is correct.  However, this may not be ideal\nfrom an end-user's perspective.  Anyway, this is going to change soon\n-- do you think this is worth correcting here and now?\n\n>> +static void read_populate_todo(struct commit_list **todo_list,\n>> +                     struct replay_opts *opts)\n>> +{\n> [...]\n>> +     for (p = buf.buf; *p; p = strchr(p, '\\n') + 1) {\n>> +             if (!(commit = parse_insn_line(p, opts)))\n>> +                     goto error;\n>> +             new = xmalloc(sizeof(struct commit_list));\n>> +             new->item = commit;\n>> +             *next = new;\n>> +             next = &new->next;\n>\n> commit_list_append()?\n\nUgh.  Fixed.\n\n>> +static void create_seq_dir(void)\n>> +{\n>> +     if (file_exists(git_path(SEQ_DIR))) {\n>> +             if (!is_directory(git_path(SEQ_DIR)) && remove_path(git_path(SEQ_DIR)) < 0)\n>> +                     die(_(\"Could not remove %s\"), git_path(SEQ_DIR));\n>> +     } else if (mkdir(git_path(SEQ_DIR), 0777) < 0)\n>> +             die_errno(_(\"Could not create sequencer directory '%s'.\"), git_path(SEQ_DIR));\n>> +}\n>\n> As mentioned in [1], a local would make this more readable.  And it's\n> not clear to me why one would want to delete a .git/sequencer file\n> that the user carefully placed there (I don't think git itself ever\n> writes such a thing).\n\nOkay,  removed that hunk.\n\n>> +static void save_head(const char *head)\n>> +{\n>> +     static struct lock_file head_lock;\n>> +     struct strbuf buf = STRBUF_INIT;\n>> +     int fd;\n>> +\n>> +     fd = hold_lock_file_for_update(&head_lock, git_path(SEQ_HEAD_FILE), LOCK_DIE_ON_ERROR);\n>> +     strbuf_addf(&buf, \"%s\\n\", head);\n>> +     if (write_in_full(fd, buf.buf, buf.len) < 0)\n>> +             die_errno(_(\"Could not write to %s.\"), git_path(SEQ_HEAD_FILE));\n>> +     if (commit_lock_file(&head_lock) < 0)\n>> +             die(_(\"Error wrapping up %s\"), git_path(SEQ_HEAD_FILE));\n>> +}\n>\n> A local would be helpful here, too.\n>\n>> +static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)\n>> +{\n>> +     static struct lock_file todo_lock;\n>> +     struct strbuf buf = STRBUF_INIT;\n>> +     int fd;\n>> +\n>> +     fd = hold_lock_file_for_update(&todo_lock, git_path(SEQ_TODO_FILE), LOCK_DIE_ON_ERROR);\n>> +     format_todo(&buf, todo_list, opts);\n>> +     if (write_in_full(fd, buf.buf, buf.len) < 0) {\n>> +             strbuf_release(&buf);\n>> +             die_errno(_(\"Could not write to %s.\"), git_path(SEQ_TODO_FILE));\n>> +     }\n>> +     if (commit_lock_file(&todo_lock) < 0) {\n>> +             strbuf_release(&buf);\n>> +             die(_(\"Error wrapping up %s\"), git_path(SEQ_TODO_FILE));\n>> +     }\n>> +     strbuf_release(&buf);\n>> +}\n>\n> Likewise here.  As mentioned before, git_path() clobbers errno, so the\n> above is likely to print a wrong error message on some systems (e.g.,\n> \"fatal: Cannot write to .git/sequencer/todo: Success\").\n\nFixed these.  Thanks.\n\n>> +static int pick_commits(struct replay_opts *opts)\n>> +{\n>> +     struct commit_list *todo_list = NULL;\n>> +     unsigned char sha1[20];\n>> +     struct commit_list *cur;\n>> +     int res;\n>>\n>>       setenv(GIT_REFLOG_ACTION, me, 0);\n>>       if (opts->allow_ff)\n>> @@ -580,14 +764,24 @@ static int pick_commits(struct replay_opts *opts)\n>>                               opts->record_origin || opts->edit));\n>>       read_and_refresh_cache(me, opts);\n>>\n>> -     prepare_revs(&revs, opts);\n>> +     walk_revs_populate_todo(&todo_list, opts);\n>> +     create_seq_dir();\n>> +     if (!get_sha1(\"HEAD\", sha1))\n>> +             save_head(sha1_to_hex(sha1));\n>\n> What happens if the .git/sequencer dir already exists (e.g., we were\n> in the middle of a multiple-cherry-pick)?  What happens if I try to\n> cherry-pick onto an unborn branch, or get_sha1() fails for some other\n> reason?\n\nOops.  I lost this somewhere along the way -- fixed now.  Thanks :)\n\n-- Ram\n"},{"id":"171500","messageId":"CALkWK0kcZi87watFTZCFUJpNf1T-wnRPyQ6FcDxmvFzAZE3osg@mail.gmail.com","threadId":"27786","inReplyTo":"20110712182958.GE14120@elie","subject":"Re: [PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T11:56:52Z","receivedAt":"2011-07-17T11:56:52Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> The \"--ff\" command-line option cannot be used with four other\n>> command-line options.\n>\n> The above sounds like --ff is a bit of a diva and does not like to\n> be on a commandline with argc >= 6.  But I get the idea.\n>\n> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>\n\nThanks.  New commit message de-emphasizing \"four\":\n\nrevert: Don't create invalid replay_opts in parse_args\n\nThe \"--ff\" command-line option cannot be used with some other\ncommand-line options.  However, parse_args still parses these\nincompatible options into a replay_opts structure for use by the rest\nof the program.  Although pick_commits, the current gatekeeper to the\ncherry-pick machinery, checks the validity of the replay_opts\nstructure before before starting its operation, there will be multiple\nentry points to the cherry-pick machinery in future.  To futureproof\nthe code and catch these errors in one place, make sure that an\ninvalid replay_opts structure is not created by parse_args in the\nfirst place.  Also ensure that regressions in maintaining this\ninvariant are caught in the future by adding an assertion in\npick_commits.\n\n-- Ram\n"},{"id":"171505","messageId":"CALkWK0==A1a-kzqXuEkjS+FMR1CAzJox8MBdkQGMLukoU15L9w@mail.gmail.com","threadId":"27786","inReplyTo":"20110712204650.GG14909@elie","subject":"Re: [PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T16:11:34Z","receivedAt":"2011-07-17T16:11:34Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Using the information in \".git/sequencer\", it is now possible to\n>> continue a cherry-pick or continue after a conflict.  To do this, we\n>> have to parse the information in \".git/sequencer/opts\" into the\n>> replay_opts structure and\n> [...]\n>\n> Might be simpler to say:\n>\n>        Introduce a new \"git cherry-pick --continue\" command which uses\n>        the information in \".git/sequencer\" to continue a cherry-pick that\n>        stopped because of a conflict or other error.  It works by dropping\n>        the first instruction from .git/sequencer/todo and performing the\n>        remaining cherry-picks listed there, with options (think \"-s\" and\n>        \"-X\") from the initial command listed in .git/sequencer/opts.\n>\n>        So now you can do:\n>\n>                $ git cherry-pick -Xpatience foo..bar\n>                ... description conflict in commit moo ...\n>                $ git cherry-pick --continue\n>                error: 'cherry-pick' is not possible because you have unmerged files.\n>                fatal: failed to resume cherry-pick\n>                $ echo resolved >conflictingfile\n>                $ git add conflictingfile && git commit\n>                $ git cherry-pick --continue; # resumes with the commit after \"moo\"\n\nYep, thanks for the pretty commit message :)\n\n>> During the \"git commit\" stage, CHERRY_PICK_HEAD will aid by providing\n>> the commit message from the conflicting \"moo\" commit.  Note that the\n>> cherry-pick mechanism has no control at this stage, so the user is\n>> free to violate anything that was specified during the first\n>> cherry-pick invocation.  For example, if \"-x\" was specified during the\n>> first cherry-pick invocation, the user is free to edit out the message\n>> during commit time.  One glitch to note is that the \"--signoff\" option\n>> specified at cherry-pick invocation time is not reflected in the\n>> commit message provided by CHERRY_PICK_HEAD; the user must take care\n>> to add \"--signoff\" during the \"git commit\" invocation.\n>\n> The -s thing doesn't have much to do with this change.  But is it a\n> bug or not?  If it's not a bug, then this is not so much a glitch to\n> note as an important feature to ensure people don't sign off on a\n> conflict resolution without thinking about it.  (I guess I think it's\n> a bug.  It's hard to decide.)\n\nBug, definitely.  It happens because unlike \"-x\" where the\ncherry-picking machinery appends to the commit message, \"-s\" is\nhandled at commit-time (when it spawns `git commit`).  Ofcourse, if I\nwere never to write the sequencing features, this would never been\nseen as a bug -- hence the term \"glitch\"; an implementation detail\nthat doesn't suit our future plans (namely, this series) very well.\n\n>> --- a/t/t3510-cherry-pick-sequence.sh\n>> +++ b/t/t3510-cherry-pick-sequence.sh\n>> @@ -101,4 +101,97 @@ test_expect_success '--reset cleans up sequencer state' '\n> [...]\n>> +test_expect_success '--continue complains when no cherry-pick is in progress' '\n>> +     pristine_detach initial &&\n>> +     test_must_fail git cherry-pick --continue >actual 2>&1 &&\n>> +     test_i18ngrep \"error\" actual\n>\n> This would start to fail if the message ever changed from \"error\" to\n> \"fatal\", right?  I don't think that's a good thing.\n\nOkay, removed this and all similar checks.\n\n>> +test_expect_success '--continue complains when there are unresolved conflicts' '\n>> +     pristine_detach initial &&\n>> +     head=$(git rev-parse HEAD) &&\n>> +     test_must_fail git cherry-pick base..picked &&\n>> +     test_must_fail git cherry-pick --continue &&\n>> +     git cherry-pick --reset\n>> +'\n>> +\n>> +test_expect_success '--continue continues after conflicts are resolved' '\n>> +     pristine_detach initial &&\n>> +     head=$(git rev-parse HEAD) &&\n>\n> How is $head used?\n\nStray line -- copy-pasting from an older version on my own tests.\nRemoved everywhere.\n\n>> +     test_must_fail git cherry-pick base..anotherpick &&\n>> +     echo \"c\" >foo &&\n>> +     git add foo &&\n>> +     git commit &&\n>> +     git cherry-pick --continue &&\n>> +     test_path_is_missing .git/sequencer &&\n>> +     {\n>> +             git rev-list HEAD |\n>> +             git diff-tree --root --stdin |\n>> +             sed \"s/[0-9a-f]\\{40\\}/OBJID/g\"\n>> +     } >actual &&\n>\n> $_x40 is idiomatic and safer with old seds.\n\nI see.  I actually thought '[0-9a-f]\\{40\\}' would be more traditional,\nand that's why I picked in the first place :p\n\n>> +test_expect_success '--continue respects opts' '\n>> +     pristine_detach initial &&\n>> +     head=$(git rev-parse HEAD) &&\n>> +     test_must_fail git cherry-pick -s -x base..anotherpick &&\n>> +     echo \"c\" >foo &&\n>> +     git add foo &&\n>> +     git commit -s &&\n>> +     git cherry-pick --continue &&\n>> +     test_path_is_missing .git/sequencer &&\n>> +     git cat-file commit HEAD >anotherpick_msg &&\n>> +     git cat-file commit HEAD~1 >picked_msg &&\n>> +     git cat-file commit HEAD~2 >unrelatedpick_msg &&\n>> +     git cat-file commit HEAD~3 >initial_msg &&\n>> +     test_must_fail test_i18ngrep \"Signed-off-by:\" initial_msg &&\n>\n> This will break when GETTEXT_POISON is set --- test_i18ngrep\n> automatically succeeds in that case.\n>\n> Is \"Signed-off-by\" meant to be translated anyway?  I would use\n>\n>        ! grep\n>\n> if testing that.\n\nMy bad.  Replaced with grep.  Thanks.\n\n> By the way, that probably should go in a separate test assertion\n> (\"-s is not automatically propagated to resolved conflict\") to make\n> it easier to change the behavior later.\n\nSeparated into another test.  Thanks.\n\n-- Ram\n"},{"id":"171506","messageId":"CALkWK0k1pX6rjGh8U6ZdDFk3qFcbj-UjU-Q-Z76hn6HV46pncg@mail.gmail.com","threadId":"27786","inReplyTo":"CAGdFq_ijTh-m7+zRFAyqvhN5k_BrC1TPdc3y47h=tBUiz6QF2A@mail.gmail.com","subject":"Re: [PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T16:23:26Z","receivedAt":"2011-07-17T16:23:26Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Jonathan and Sverre,\n\nJonathan Nieder writes:\n> Wait, so what is the actual impact of this patch?\n>\n> As far as I can tell, it is to introduce a remove_sequencer_state()\n> function whose eventual purpose would be to remove the .git/sequencer\n> directory used by \"git cherry-pick\" to record its progress.  Paraphrased,\n> the function does this:\n>\n>        rm -fr \"$GIT_DIR/sequencer-old\"\n>        mv \"$GIT_DIR/sequencer\" \"$GIT_DIR/sequencer-old\"\n>\n> This way, a person has one level of \"undo\" possible, assuming git\n> commands and scripts use the function carefully enough not to call it\n> twice.\n>\n> Is the \"undo\" feature advertised anywhere?  Should this function write\n> a message to stderr to inform the operator about how to get back the\n> precious cherry-pick state?\n\nI don't think we should advertise it on stdout or stderr.  I think of\na safeguard that only very few people will use.  Ofcourse, documenting\nit somewhere like Documentation/technical will make sense once we have\nsomething usable.\n\n> If I were doing it, I'd squash this with the patch that introduces\n> \"git cherry-pick --quit\", to give an example of how the new function is\n> meant to be used (and tests!).\n\nI would have done that too, except that the \"reset: Make hard reset\nremove the sequencer state\" patch depends on this.  So, I don't think\nit's fair to squash it into either patch.\nI can definitely write a better commit message though (wait for the\nnext iteration to see it).\n\nSverre Rabbelier writes:\n> I think we can learn from hg here and just use a datetime stamp. So\n> instead of moving to sequencer-old move to sequencer-20110713-141022\n> or such. That way there's as many undo as you need.\n\nThat's a great example in general, but I'm wondering if it would\nreally be useful for this particular usecase.  Are sequencer states so\nvaluable that we want to allow so many levels of undo?\n\n-- Ram\n"},{"id":"171508","messageId":"CALkWK0=XP=hwsN8vVmTc2Rs3mYuZnLZOpg4=OE7mrYbAYm6nCQ@mail.gmail.com","threadId":"27786","inReplyTo":"20110712201532.GE14909@elie","subject":"Re: [PATCH 14/17] reset: Make hard reset remove the sequencer state","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T16:40:03Z","receivedAt":"2011-07-17T16:40:03Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Years of muscle memory have trained users to use \"git reset --hard\" to\n>> remove away the branch state after any sort of operation.  In\n>> retrospect, while this may not have been the best design decision, we\n>> are stuck with it for historical reasons.\n>\n> Wait, wait!  If that was a bad design decision, we should try to find\n> a way to smoothly transition to a world without it, instead of\n> layering workarounds on top of it.\n>\n> But actually I think it is good UI.  When you do \"git merge\", it works\n> like this:\n>\n>        git merge <foo>; # conflicts!\n>        ... hack hack hack ...\n>        # Oh, bother, let me go back to a state I know well and am\n>        # comfortable with.\n>        git reset --hard <bar>\n>\n> And the same psychological effect applies in the cherry-pick case:\n>\n>        git cherry-pick <foo>; # conflicts!\n>        ... hack hack hack ...\n>        # Oh, bother, let me go back to a state I know well and am\n>        # comfortable with.\n>        git reset --hard <bar>\n>\n> See, it's about the tool working with you.  When I abandon a merge,\n> I don't want to have to search through the owner's manual for the\n> button to get git to clear away this unpleasant and unfamiliar state.\n\nFair enough.  It's a large hammer to solve the problem, and it's used\nby many people; I use it a lot myself.\n\n> Now, by contrast, sometimes one wants something less aggressive.\n> For example, to abandon a partial merge conflict resolution but\n> keep unrelated changes in the worktree:\n>\n>        git reset --merge HEAD\n>\n> Or to get out of the \"mergy\" state but leave the worktree alone:\n>\n>        git reset\n>\n> There's no porcelain or plumbing to abandon a rebase without\n> additional side-effects, but \"git status\" suggests a command for\n> it if I remember correctly.\n>\n>        rm -fr .git/rebase-merge\n\nWe're not making this mistake with the sequencer :)\n\n>> Additionally, this patch ensures that some existing tests don't break\n>> when features like \"--reset\" and \"--continue\" are introduced later in\n>> the series.\n>\n> That's not \"Additionally\" --- it's the same problem.  One way to\n> phrase it would be \"Noticed by running such-and-such test after\n> such-and-such change\".\n\nRight.  Minor tweaks made to the commit message.\n\nreset: Make reset remove the sequencer state\n\nYears of muscle memory have trained users to use \"git reset --hard\" to\nremove the branch state after any sort operation.  Make it also remove\nthe sequencer state so that this sort of workflow is now possible:\n\n$ git cherry-pick foo..bar\n... conflict encountered ...\n$ git reset --hard # Oops, I didn't mean that\n$ git cherry-pick quux..bar\n... cherry-pick succeeded ...\n\nAlso, guard against accidental removal of the sequencer state by\nmoving \".git/sequencer\" to \".git/sequencer-old\" in the first \"git\nreset --hard\" call, and only remove it completely only after the\nsecond call.\n\nThis patch ensures that some existing tests don't break when features\nlike \"--reset\" and \"--continue\" are introduced later in the series.\nWithout this patch, we would expect the last cherry-pick call in the\nexample to fail with the complaint that an existing cherry-pick\noperation is in progress.\n\n>> +test_expect_success 'reset --hard cleans up sequencer state' '\n>\n> Hoorah!  Thanks.\n>\n> Why isn't the .git/sequencer removal in remove_branch_state() like\n> MERGE_MSG and other similar examples are?  (Not a rhetorical question;\n> it would be interesting to know.)\n\nI thought we should only make a hard reset clear it, but all the reset\ncodepaths reach remove_branch_state().  However, in view of\nconsistency, I've put the removal code in remove_branch_state() now.\n\n-- Ram\n"},{"id":"171509","messageId":"20110717165904.GA27787@elie","threadId":"27786","inReplyTo":"CALkWK0=6A=2z5BShsiHeMCS2Movn+L3V4P1WJTTQ-HexTasAhg@mail.gmail.com","subject":"Re: [PATCH 05/17] revert: Propogate errors upwards from do_pick_commit","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T16:59:04Z","receivedAt":"2011-07-17T16:59:04Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nRamkumar Ramachandra wrote:\n\n> revert: Propogate errors upwards from do_pick_commit\n>\n> Currently, revert_or_cherry_pick can fail in two ways.  If it\n> encounters a conflict, it returns a positive number indicating the\n> intended exit status for the git wrapper to pass on; for all other\n> errors, it calls die().  The latter behavior is inconsiderate towards\n> callers, as it denies them the opportunity to do some post-processing\n> or cleanup before exiting.  For instance, later in the series, callers\n> will want to save some data about the current operation before\n> exiting.\n\nThanks for explaining.  Why can't callers use set_die_routine() or\natexit()?  Is the last sentence true?\n\n> Change this by replacing some of the calls to \"die\" with calls to\n> \"error\", so that revert_or_cherry_pick can return negative values too.\n> While postive return values indicate conflicts as before, negative\n> ones indicate other errors.  This return status is propogated updwards\n> from do_pick_commit, to be finally handled in cmd_cherry_pick and\n> cmd_revert.\n>\n> In the same spirit, also introduce a new function error_dirty_index,\n> based on die_dirty_index, which prints some hints and returns an error\n> to its caller do_pick_commit.\n>\n> While the full benefits of this patch will only be seen once all the\n> \"die\" calls are replaced with calls to \"error\", its immediate impact\n> is to change some of the \"fatal:\" messages to \"error:\" messages and\n> print a new \"fatal: cherry-pick failed\" message when the operation\n> fails.\n\nStarting to get long.  It's not immediately obvious to me why\nerror_dirty_index is a detail that needs to be singled out.  Maybe\nthese three paragraphs could be summarized by saying:\n\n After this patch, revert_or_cherry_pick will still return a positive\n return value to indicate an exit status for conflicts as before,\n while for other (fatal) errors it will print an error message and\n return -1 instead of die()-ing.  The cmd_revert and cmd_cherry_pick\n are adjusted to handle the fatal errors by die()-ing themselves.\n\n Thus for now, the only user-visible impact would be to change some\n \"fatal:\" messages to say \"error:\" and to add a new \"fatal:\n cherry-pick failed\" message at the end when the operation fails.\n\n Since no callers take advantage of the ability to recover from\n errors yet, it is possible and even likely that these functions do\n not completely clean up after themselves on (fatal) error but leave\n some state to be cleared away by exit().  Callers beware!\n\nThat last paragraph summarizes my worry.  Since this API change does\nnot seem to be used by the other patches, I would prefer not to\nleave such a trap for unwary new callers, at least until the intended\nlegitimate use is a little clearer.\n\n[...]\n>> write_cache_as_tree() locks the index and does not always commit or\n>> roll it back except on success.  Current callers aren't likely to try\n>> to lock the index again (since they just die()), but presumably the\n>> goal of returning error() here is to allow for callers that want to\n>> stay alive and do something more.  How should they recover (i.e., what\n>> is the intended API)?\n>\n> Hm, there was supposed to be a discard_cache() before this error as I\n> recall -- fixed now.  Thanks for catching.\n\ndiscard_index() does not unlock the index.\n\nI had wondered what the discard_cache() stuff was about before; thanks\nfor explaining.\n\n>> Similar questions probably apply to calls to other APIs that return -1\n>> to mean \"I failed; please print an appropriate message about that and\n>> exit\".  I haven't checked carefully, since the answer to this example\n>> could help in knowing what to look for in the others.\n>\n> I think the others are fairly clear actually.\n\nRoughly speaking, there are two kinds of functions that return error()\ninstead of die()-ing in the git codebase:\n\n 1. Those that recover from their errors, leaving the process in a\n    sane state that allows the caller (e.g., a long-lived interactive\n    porcelain) to go on to do other things\n\n 2. Those that do not have enough information to give a useful error\n    message themselves, so delegate to the caller the responsibility\n    to die() with an error message about where in the program the\n    failure occured.\n\nThe commit message suggests that you are introducing a new category:\n\n 3. Those that could die() without trouble, _except_ that some callers\n    want to do cleanup of private state on exit and atexit() is not\n    working for them for some reason\n\nBut from this description of it you can see that the category seems\nquestionable and unlikely to be necessary to me.\n\nHow do callers know which of the three categories a function being\ncalled falls into?  That question is relevant because the caller must\nrespond accordingly:\n\n a. In case (1), the caller can go on with its work.\n b. In case (2), the caller writes a good error message and die()s ASAP.\n c. In the new case (3), the caller needs to exit() or die() ASAP,\n    but there is no message that especially needs to be written.\n\nI had thought the idea was to put pick_commits() in case (1) (usable\nby long-lived porcelain like cgit that don't want to exit).  To\naccomplish that, when you call a function of type (2), you would need\nto audit its implementation to see what changes it needs to move to\ntype (1), if any.  (FWIW, I am not convinced you've tried to do this,\nhence the comment above about it.)\n\nIt clearly is not part of case (2).  All the useful context has\nalready been written to stderr when pick_commits() returns.\n\nIf it is case (3), the reader is going to wonder why you didn't just\nuse atexit() or set_die_handler() and why it is worth the\ncomplication.\n\nDoes that make sense?\nJonathan\n"},{"id":"171510","messageId":"CALkWK0mfNNfpyyMDFgVD_gnEC7OxHuPAPc+27-PepYNKPOR8-w@mail.gmail.com","threadId":"27786","inReplyTo":"20110712203011.GF14909@elie","subject":"Re: [PATCH 16/17] revert: Introduce --reset to remove sequencer state","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-17T17:10:51Z","receivedAt":"2011-07-17T17:10:51Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nOn Wed, Jul 13, 2011 at 2:00 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Ramkumar Ramachandra wrote:\n>> Protect the sequencer state from accidentally being stomped by a new\n>> cherry-pick or revert invocation by ensuring that an existing one\n>> isn't in progress.\n>\n> I first read this as \"an existing sequencer state isn't in progress\".\n> But anyway, if I understand correctly the goal isn't to protect the\n> sequencer state from corruption but to protect the user from forgetting\n> about a pending cherry-pick.\n>\n>> While this patch would normally be expected to\n>> break many tests, the earlier patches \"reset: Make hard reset remove\n>> the sequencer state\" and \"revert: Remove sequencer state when no\n>> commits are pending\" make sure that they don't.\n>\n> Why would I expect a nice change to break tests?\n>\n> I suppose you mean: \"A naive version of this would break the following\n> established way of working:\n>\n>        git cherry-pick X; # has conflicts\n>        git reset --hard; # no, no!\n>        git cherry-pick Y\n>\n> Or even:\n>\n>        git cherry-pick X; # has conflicts\n>        # ... resolve ...\n>        git commit\n>        git cherry-pick Y\n>\n> But a previous patch takes care of that by making \"git reset --hard\"\n> cancel the pending cherry-pick and by making \"git commit\" clean up\n> after a pending cherry-pick when making the commit that would finish\n> it.\"\n>\n> The above text quoted with \">\" describes the main impact of the\n> change.  The subject line, on the other hand, describes a less\n> important part:\n>\n>> [Subject: revert: Introduce --reset to remove sequencer state]\n>\n> Is that fixable?  Maybe this could be split into two patches (since it\n> does two different things), or maybe the subject line could be tweaked\n> to describe both.\n\nNew commit message.\n\nrevert: Don't clobber sequencer state; introduce --reset\n\nProtect the user from forgetting about a pending operation by\nimmediately erroring out when an existing cherry-pick or revert\noperation is in progress.  A naive version of this would break the\nfollowing established ways of working:\n\n$ git cherry-pick foo\n... conflict ...\n$ git reset --hard  # I actually meant \"moo\" when I said \"foo\"\n$ git cherry-pick moo\n\n$ git cherry-pick foo\n... conflict ...\n# resolve the conflict\n$ git commit # commit the resolution\n$ git cherry-pick moo # New operation\n\nBut the previous patches \"reset: Make hard reset remove the sequencer\nstate\" and \"revert: Remove sequencer state when no commits are\npending\" make sure that this does not happen.\n\nTo explicitly remove the sequencer state for a fresh cherry-pick or\nrevert invocation, introduce a new subcommand called '--reset' which\nreally removes the sequencer state on the very first invocation.\n\n>> Ensure that the \"rebase -i\" script which invokes cherry-pick or revert\n>> doesn't change its behavior by using '--reset' to to clear the state\n>> after every failed pick.\n>\n> This should be avoidable by noticing that commands like \"rebase -i\"\n> use GIT_CHERRY_PICK_HELP to clobber our nice instructions about how to\n> resume a cherry-pick anyway and therefore are unlikely to need\n> cherry-pick --continue/--abort facilities, no?\n\nRight.  Removed hunk and corresponding segment in commit message.\n\nThanks.\n\n-- Ram\n"},{"id":"171512","messageId":"20110717183219.GB27787@elie","threadId":"27786","inReplyTo":"CALkWK0==A1a-kzqXuEkjS+FMR1CAzJox8MBdkQGMLukoU15L9w@mail.gmail.com","subject":"Re: [PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T18:32:19Z","receivedAt":"2011-07-17T18:32:19Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n> Jonathan Nieder writes:\n\n>> The -s thing doesn't have much to do with this change.  But is it a\n>> bug or not?  If it's not a bug, then this is not so much a glitch to\n>> note as an important feature to ensure people don't sign off on a\n>> conflict resolution without thinking about it.  (I guess I think it's\n>> a bug.  It's hard to decide.)\n>\n> Bug, definitely.  It happens because unlike \"-x\" where the\n> cherry-picking machinery appends to the commit message, \"-s\" is\n> handled at commit-time (when it spawns `git commit`).  Ofcourse, if I\n> were never to write the sequencing features, this would never been\n> seen as a bug -- hence the term \"glitch\"; an implementation detail\n> that doesn't suit our future plans (namely, this series) very well.\n\nHmm, I thought I remembered this coming up previously and Junio\nmentioning that it was intentional (maybe in the context of\nCHERRY_HEAD?), but I haven't been able to find the relevant message.\n"},{"id":"171513","messageId":"20110717184057.GD27787@elie","threadId":"27786","inReplyTo":"CALkWK0nyu6W2Nd=qcrjZZwkAdFGqTqAe53FmecS_n2cK_4UWMg@mail.gmail.com","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T18:40:57Z","receivedAt":"2011-07-17T18:40:57Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> fatal: Malformed instruction sheet: .git/sequencer/todo\n> Technically speaking, this is correct.  However, this may not be ideal\n> from an end-user's perspective.  Anyway, this is going to change soon\n> -- do you think this is worth correcting here and now?\n\nYes, thanks.  (A bird in the hand and all that.)\n"},{"id":"171514","messageId":"20110717184319.GE27787@elie","threadId":"27786","inReplyTo":"CALkWK0kcZi87watFTZCFUJpNf1T-wnRPyQ6FcDxmvFzAZE3osg@mail.gmail.com","subject":"Re: [PATCH 09/17] revert: Don't create invalid replay_opts in parse_args","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T18:43:19Z","receivedAt":"2011-07-17T18:43:19Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Thanks.  New commit message de-emphasizing \"four\":\n\nLooks good.  While at it, it might be nice to simplify the final\nsentence:\n\n> revert: Don't create invalid replay_opts in parse_args\n>\n> The \"--ff\" command-line option cannot be used with some other\n> command-line options.  However, parse_args still parses these\n> incompatible options into a replay_opts structure for use by the rest\n> of the program.  Although pick_commits, the current gatekeeper to the\n> cherry-pick machinery, checks the validity of the replay_opts\n> structure before before starting its operation, there will be multiple\n> entry points to the cherry-pick machinery in future.  To futureproof\n> the code and catch these errors in one place, make sure that an\n> invalid replay_opts structure is not created by parse_args in the\n> first place.  Also ensure that regressions in maintaining this\n> invariant are caught in the future by adding an assertion in\n> pick_commits.\n\nI think the idea is \"we still check the options struct for validity\nin pick_commits, but this is an assert() call now to emphasize that\nit's the caller's responsibility to get it right\".\n"},{"id":"171516","messageId":"20110717191931.GH27787@elie","threadId":"27786","inReplyTo":"CALkWK0k1pX6rjGh8U6ZdDFk3qFcbj-UjU-Q-Z76hn6HV46pncg@mail.gmail.com","subject":"Re: [PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T19:19:31Z","receivedAt":"2011-07-17T19:19:31Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> I don't think we should advertise it on stdout or stderr.  I think of\n> a safeguard that only very few people will use.  Ofcourse, documenting\n> it somewhere like Documentation/technical will make sense once we have\n> something usable.\n\nYuck.  Documentation/technical is for API, protocol, and design\ndocumentation.  One should not need to read Documentation/technical in\norder to be able to use git!\n\nIf the worry is that such a hint would be too noisy, it can be\nprotected by a configuration variable using the usual advice\nmechanism.\n\n>> If I were doing it, I'd squash this with the patch that introduces\n>> \"git cherry-pick --quit\", to give an example of how the new function is\n>> meant to be used (and tests!).\n>\n> I would have done that too, except that the \"reset: Make hard reset\n> remove the sequencer state\" patch depends on this.  So, I don't think\n> it's fair to squash it into either patch.\n> I can definitely write a better commit message though (wait for the\n> next iteration to see it).\n\nWould it be possible to introduce \"cherry-pick --quit\" here, and make\nthe later patch only do one thing, namely adding the check to prevent\na cherry-pick in the middle of a pending cherry-pick?\n\nIn other words, I don't understand why the \"reset --hard\" workaround\nwould need to come before \"cherry-pick --quit\".\n\nThanks for explaining.\nJonathan\n"},{"id":"171517","messageId":"20110717192548.GI27787@elie","threadId":"27786","inReplyTo":"CALkWK0mfNNfpyyMDFgVD_gnEC7OxHuPAPc+27-PepYNKPOR8-w@mail.gmail.com","subject":"Re: [PATCH 16/17] revert: Introduce --reset to remove sequencer state","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T19:25:49Z","receivedAt":"2011-07-17T19:25:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> New commit message.\n\nMuch clearer.  Thank you.\n"},{"id":"171519","messageId":"20110717193657.GJ27787@elie","threadId":"27786","inReplyTo":"CALkWK0nm-gX9-3pGxT31VO-06mimd0cg1O8xhk-0QbsbdN7aLg@mail.gmail.com","subject":"Re: [PATCH 04/17] revert: Rename no_replay to record_origin","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-17T19:36:57Z","receivedAt":"2011-07-17T19:36:57Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Thanks for probing.  Found out the reason after some digging.\n>\n> revert: Rename no_replay to record_origin\n>\n> The \"-x\" command-line option is used to record the name of the\n> original commits being picked in the commit message.  The variable\n> corresponding to this option is named \"no_replay\" for historical\n> reasons.\n\nHeh.  I guess \"for crazy historical reasons no one remembers, and it's\nespecially confusing because the term 'replay' is used to describe\nfrom time to time to describe what cherry-pick does (e.g., in the\ndocumentation for the --mainline option)\" would be enough of a summary\nto justify the change.\n\n> This name was introduced in f810379 (Make builtin-revert.c\n> use parse_options, 2007-10-07) to replace \"replay\", the opposite of\n> \"no_replay\".  The name \"replay\" was introduced in 9509af6 (Make\n> git-revert & git-cherry-pick a builtin, 2007-03-01).\n\nIt's actually older than that: it comes from the scripted version:\n\n\t-x|--i-really-want-to-expose-my-private-commit-object-name)\n\t\treplay=\n\t\t;;\n\n>From v1.4.3-rc2~12 (cherry-pick: make -r the default, 2006-10-05;\nit's of course older than that), we learn that this used to be the\ndefault, disabled by a --replay option that meant\n\n\tUsually the command appends which commit was\n\tcherry-picked after the original commit message when\n\tmaking a commit.  This option, '--replay', causes it to\n\tuse the original commit message intact.  This is useful\n\twhen you are reordering the patches in your private tree\n\tbefore publishing.\n\nor in other words, \"simulate making the commit anew again, instead\nof explicitly recording that this is a new commit based on that\nold one\".\n\nIn other words, \"replay\" originally essentially meant what\n\"cherry-pick\" does now.\n\nThanks, that was interesting.\n\nCheers,\nJonathan\n"},{"id":"171602","messageId":"CALkWK0kZ3nWnnGe1OHXWgiZ8ik9iNW803wi2d6kUiNDpiOWNDA@mail.gmail.com","threadId":"27786","inReplyTo":"20110717184057.GD27787@elie","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T19:31:55Z","receivedAt":"2011-07-18T19:31:55Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> fatal: Malformed instruction sheet: .git/sequencer/todo\n>> Technically speaking, this is correct.  However, this may not be ideal\n>> from an end-user's perspective.  Anyway, this is going to change soon\n>> -- do you think this is worth correcting here and now?\n>\n> Yes, thanks.  (A bird in the hand and all that.)\n\nOkay, I thought about this for a while.  Either we can:\n1. Assume that there'll never be a stray \"revert\" somewhere in the\nmiddle of the instruction sheet when we invoke a \"cherry-pick\n--continue\" and viceversa (ie. the instruction sheet is not corrupt/\nhand-edited).  We can return a special exit status from the parser the\nmoment we encounter a \"revert\" during a \"cherry-pick\" assuming that\nthe entire sheet is filled with \"revert\" instructions, and die in\nprocess_subcommand (now changed to pick_revisions) with a beautiful\nmessage like \"You're trying to resume a previous revert using\ncherry-pick --continue, and we don't currently support this\".\n2. We can modify the API of the parser heavily to parse action +\ncommit instead of just commits.  Then, we can iterate through the list\nand find/ report inconsistencies in process_subcommand.  In this case,\nwe can say \"You're trying to resume a cherry-pick, but your\ninstruction sheet contains some revert instructions\" or \"You're trying\nto resume a previous revert using cherry-pick --continue, and we don't\ncurrently support this\" as appropriate (after counting).  Although\nthis has a very beautiful end-user effect, I don't like the idea of\nreturning action + commit and counting.\n3. Instead of just saying \"fatal: Malformed instruction sheet\" like we\ndo now, we can put in something a little more helpful like \"error:\nCannot cherry-pick during a revert\" before this message.  So:\n\n$ git cherry-pick moo\n... conflict ...\n# resolve conflict\n$ git revert --continue\nerror: Cannot cherry-pick during a revert\nfatal: Malformed instruction sheet\n\nThis makes it clear to the user that the instruction sheet is to\nblame, and in what way.  This is simple, and makes no assumptions\nabout whether or not the instruction sheet was hand-edited by the\nuser, so I like this.\n\nThoughts?\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 0df724f..fcbf2a1 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -667,8 +667,13 @@ static struct commit *parse_insn_line(char\n*start, struct replay_opts *opts)\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+\tif (action != opts->action) {\n+\t\tconst char *action_str;\n+\t\taction_str = action == REVERT ? \"revert\" : \"cherry-pick\";\n+\t\terror(_(\"Cannot %s during a %s\"), action_str,\n+\t\t\taction_name(opts));\n \t\treturn NULL;\n+\t}\n\n \tif ((get_sha1(sha1_abbrev, commit_sha1) < 0)\n \t\t|| !(commit = lookup_commit_reference(commit_sha1)))\n"},{"id":"171603","messageId":"CALkWK0n4yXJ8HvCzcXMUda6oUyC2M32n25Sn5oKPzw0Huqvo8g@mail.gmail.com","threadId":"27786","inReplyTo":"20110717191931.GH27787@elie","subject":"Re: [PATCH 10/17] sequencer: Announce sequencer state location","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T19:44:31Z","receivedAt":"2011-07-18T19:44:31Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> I don't think we should advertise it on stdout or stderr.  I think of\n>> a safeguard that only very few people will use.  Ofcourse, documenting\n>> it somewhere like Documentation/technical will make sense once we have\n>> something usable.\n>\n> Yuck.  Documentation/technical is for API, protocol, and design\n> documentation.  One should not need to read Documentation/technical in\n> order to be able to use git!\n>\n> If the worry is that such a hint would be too noisy, it can be\n> protected by a configuration variable using the usual advice\n> mechanism.\n\nOkay, although I'm not inclined to do this right away.\n\n>>> If I were doing it, I'd squash this with the patch that introduces\n>>> \"git cherry-pick --quit\", to give an example of how the new function is\n>>> meant to be used (and tests!).\n>>\n>> I would have done that too, except that the \"reset: Make hard reset\n>> remove the sequencer state\" patch depends on this.  So, I don't think\n>> it's fair to squash it into either patch.\n>> I can definitely write a better commit message though (wait for the\n>> next iteration to see it).\n>\n> Would it be possible to introduce \"cherry-pick --quit\" here, and make\n> the later patch only do one thing, namely adding the check to prevent\n> a cherry-pick in the middle of a pending cherry-pick?\n>\n> In other words, I don't understand why the \"reset --hard\" workaround\n> would need to come before \"cherry-pick --quit\".\n\n*pants* That was quite a challenging rebase.\nI think I managed to get it right after several attempts -- we'll find\nout soon enough.\n\n-- Ram\n"},{"id":"171604","messageId":"CALkWK0mfRR4M_VRQbpXzM97i4-fjF9=S+xPpCuwL-EQmaA9jfw@mail.gmail.com","threadId":"27786","inReplyTo":"20110717183219.GB27787@elie","subject":"Re: [PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T20:00:37Z","receivedAt":"2011-07-18T20:00:37Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Jonathan Nieder writes:\n>>> The -s thing doesn't have much to do with this change.  But is it a\n>>> bug or not?  If it's not a bug, then this is not so much a glitch to\n>>> note as an important feature to ensure people don't sign off on a\n>>> conflict resolution without thinking about it.  (I guess I think it's\n>>> a bug.  It's hard to decide.)\n>>\n>> Bug, definitely.  It happens because unlike \"-x\" where the\n>> cherry-picking machinery appends to the commit message, \"-s\" is\n>> handled at commit-time (when it spawns `git commit`).  Ofcourse, if I\n>> were never to write the sequencing features, this would never been\n>> seen as a bug -- hence the term \"glitch\"; an implementation detail\n>> that doesn't suit our future plans (namely, this series) very well.\n>\n> Hmm, I thought I remembered this coming up previously and Junio\n> mentioning that it was intentional (maybe in the context of\n> CHERRY_HEAD?), but I haven't been able to find the relevant message.\n\nHm, not automatically signing off on a commit resolution.  I'm not\nsure I understand why.  What does it mean to signoff? It proof of\norigin, more than anything else -- it means that you didn't pick up\nthe code from some random place, right? Why would you want to signoff\non commits you're picking from another branch? A topic branch that you\nwant to merge into 'master' -- all the commits in the topic branch are\nyours (or you atleast know where the code came from), but there are\nprobably commits from other developers in 'master'.  So what happens\nwhen you resolve a conflict?\n1. You modify some of your own code to fit into the code in 'master'.\nAuto-signoff is alright here.\n2. You modify someone else's code to accommodate your code in\n'master'.  Here, your commit contains hunks which either modify or\nremove someone else's code, but how is this sort of thing different\nfrom a normal patch? Intent is different- I would've never made that\nchange unless I tried accommodating this topic branch in 'master', but\nit has no effect on the origin of the code.  Are you saying that\nauto-signoff is not alright here? Why?\n\nWait.  There's another explanation.  You resolved the conflict and got\neverything into 'master' successfully, but some bugs crept into the\nprogram (that aren't present in the topic branch) because you resolved\nthe conflict in a hurry.  Still, what does all this have to do with\ncertificate of origin?\n\nThanks.\n\n-- Ram\n"},{"id":"171605","messageId":"20110718200943.GB6657@elie.gateway.2wire.net","threadId":"27786","inReplyTo":"CALkWK0mfRR4M_VRQbpXzM97i4-fjF9=S+xPpCuwL-EQmaA9jfw@mail.gmail.com","subject":"Re: [PATCH 17/17] revert: Introduce --continue to continue the operation","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-18T20:09:43Z","receivedAt":"2011-07-18T20:09:43Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n> Jonathan Nieder writes:\n\n>> Hmm, I thought I remembered this coming up previously and Junio\n>> mentioning that it was intentional (maybe in the context of\n>> CHERRY_HEAD?), but I haven't been able to find the relevant message.\n>\n> Hm, not automatically signing off on a commit resolution.  I'm not\n> sure I understand why.\n\nWell, \"intentional\" doesn't mean \"good behavior\".  I've already said I\ndon't like it. :)  If you remind me, I'll write a patch to make the\nsign-off from cherry-pick -s persist.\n\n[...]\n> Wait.\n\nThanks for a nice explanation.  The detail that seems to be missing is\nthat the meaning of --signoff is intended to be per-project.  In some\nprojects, it might represent \"I reviewed this\" or something else\nrather than the developer's certificate of origin.\n"},{"id":"171607","messageId":"CALkWK0=O-z4yw+dETkpZ2+1_eB6Z1pn55C0ggK0Q9-Hsoh53QA@mail.gmail.com","threadId":"27786","inReplyTo":"20110712195246.GC14909@elie","subject":"Re: [PATCH 12/17] revert: Save command-line options for continuing operation","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T20:18:34Z","receivedAt":"2011-07-18T20:18:34Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\n> Subject: [PATCH 12/17] revert: Save command-line options for continuing operation\n\nI threw away my custom parser and re-used gitconfig as Jeff suggested.\n Complete rewrite.\n\n-- Ram\n"},{"id":"171611","messageId":"CALkWK0mQ0M7ZjJk=dwZjuK=fp4p1+Cz4OfeWpdi+CTO1pZVH0Q@mail.gmail.com","threadId":"27786","inReplyTo":"20110712182046.GD14120@elie","subject":"Re: [PATCH 08/17] revert: Separate cmdline parsing from functional code","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T20:53:26Z","receivedAt":"2011-07-18T20:53:26Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Currently, revert_or_cherry_pick does too many things including\n>> argument parsing and setting up to pick the commits; this doesn't make\n>> a good API.\n>\n> On the contrary, generally speaking single-call APIs are often very\n> pleasant to work with.\n[...]\n> So this is probably not about the function doing too many things but\n> something else.\n\nTook me some time to figure this out.  I suppose I could also phrase\nthis as \"prepare to make revert_or_cherry_pick the starting point for\ncontinuing in future\", but it might result in a huge explanation about\nwhat continuing means, and why continuing won't need to do argument\nparsing.  I think I'll put in a more superficial intent (Justified\nbecause I like this change even if we never support continuing in the\nfuture).\n\nNew commit message.\n\nrevert: Separate cmdline parsing from functional code\n\nCurrently, revert_or_cherry_pick sets up a default git config, parses\ncommand-line arguments, before preparing to pick commits.  This makes\nfor a bad API as the central worry of callers is to assert whether or\nnot a conflict occured while cherry picking.  The current API is like:\n\nif (revert_or_cherry_pick(argc, argv, opts) < 0)\n   print \"Something failed, I'm not sure what\"\n\nSimplify and rename revert_or_cherry_pick to pick_commits so that it\nonly has the responsibility of setting up the revision walker and\npicking commits in a loop.  Transfer the remaining work to its\ncallers.  Now, the API is simplified as:\n\nif (parse_args(argc, argv, opts) < 0)\n   print \"Can't parse arguments\"\nif (pick_commits(opts) < 0)\n   print \"Something in the picking mechanism failed\"\n\nLater in the series, pick_commits will serve as the starting point for\ncontinuing a cherry-pick or revert.\n\n-- Ram\n"},{"id":"171612","messageId":"20110718210300.GA6941@elie.gateway.2wire.net","threadId":"27786","inReplyTo":"CALkWK0mQ0M7ZjJk=dwZjuK=fp4p1+Cz4OfeWpdi+CTO1pZVH0Q@mail.gmail.com","subject":"Re: [PATCH 08/17] revert: Separate cmdline parsing from functional code","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-18T21:03:00Z","receivedAt":"2011-07-18T21:03:00Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> New commit message.\n>\n> revert: Separate cmdline parsing from functional code\n>\n> Currently, revert_or_cherry_pick sets up a default git config, parses\n> command-line arguments, before preparing to pick commits.  This makes\n> for a bad API as the central worry of callers is to assert whether or\n> not a conflict occured while cherry picking.  The current API is like:\n>\n> if (revert_or_cherry_pick(argc, argv, opts) < 0)\n>    print \"Something failed, I'm not sure what\"\n\nNice.  That's much clearer.\n\n[...]\n> Later in the series, pick_commits will serve as the starting point for\n> continuing a cherry-pick or revert.\n\nWith the addition of \"also\" between will and serve, it looks good to\nme now.  Thank you.\n"},{"id":"171613","messageId":"CALkWK0nYMuDeoGuvGWtmcs6Odoo0g7B_CkY63MBo38UvOHyX8g@mail.gmail.com","threadId":"27786","inReplyTo":"20110712200324.GD14909@elie","subject":"Re: [PATCH 13/17] revert: Introduce a layer of indirection over pick_commits","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T21:24:23Z","receivedAt":"2011-07-18T21:24:23Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nNew commit message.  The \"--reset\" part might jump out, but it's a\nresult of the recent rebasing.\n\nrevert: Make pick_commits functionally act on a commit list\n\nApart from its central objective of calling into the picking\nmechanism, pick_commits creates a sequencer directory, prepares a todo\nlist, and even acts upon the \"--reset\" subcommand.  This makes for a\nbad API since the central worry of callers is to figure out whether or\nnot any conflicts were encountered during the cherry picking.  The\ncurrent API is like:\n\nif (pick_commits(opts) < 0)\n   print \"Something failed, we're not sure what\"\n\nSo, change pick_commits so that it's only responsible for picking\ncommits in a loop and reporting any errors, leaving the rest to a new\nfunction called pick_revisions.  Consequently, the API of pick_commits\nbecomes much clearer:\n\nact_on_subcommand(opts->subcommand);\ntodo_list = prepare_todo_list();\nif (pick_commits(todo_list, opts) < 0)\n   print \"Error encountered while picking commits\"\n\nNow, callers can easily call-in to the cherry-picking machinery by\nconstructing an arbitrary todo list along with some options.\n\n-- Ram\n"},{"id":"171614","messageId":"1311025032-835-1-git-send-email-artagnon@gmail.com","threadId":"27786","inReplyTo":"20110713190724.GA31965@sigill.intra.peff.net","subject":"[RFC PATCH] config: Introduce functions to write non-standard file","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-18T21:37:12Z","receivedAt":"2011-07-18T21:37:12Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Introduce two new functions corresponding to \"git_config_set\" and\n\"git_config_set_multivar\" to write a non-standard configuration file.\nExpose thse new functions in cache.h for other git programs to use.\n\nSuggested-by: Jeff King <peff@peff.net>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Although this patch is ready for inclusion as far as I'm concerned,\n I'm marking it an RFC because I will post it along with the latest\n iteration of the Sequencer -- there's some usage examples in that\n series that can justify the creation of two new functions.\n\n It may be classified as a workaround -- the more we encourage patches\n like this, the more cruft config.c will accumulate, and the harder\n it'll become to refactor completely.\n\n cache.h  |    2 ++\n config.c |   29 ++++++++++++++++++++++++++++-\n 2 files changed, 30 insertions(+), 1 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex bc9e5eb..833ee75 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1056,9 +1056,11 @@ extern int git_config_bool(const char *, const char *);\n extern int git_config_maybe_bool(const char *, const char *);\n extern int git_config_string(const char **, const char *, const char *);\n extern int git_config_pathname(const char **, const char *, const char *);\n+extern int git_config_set_in_file(const char *, const char *, const char *);\n extern int git_config_set(const char *, const char *);\n extern int git_config_parse_key(const char *, char **, int *);\n extern int git_config_set_multivar(const char *, const char *, const char *, int);\n+extern int git_config_set_multivar_in_file(const char *, const char *, const char *, int, const char *);\n extern int git_config_rename_section(const char *, const char *);\n extern const char *git_etc_gitconfig(void);\n extern int check_repository_format_version(const char *var, const char *value, void *cb);\ndiff --git a/config.c b/config.c\nindex 1fc063b..3d9da6b 100644\n--- a/config.c\n+++ b/config.c\n@@ -1092,9 +1092,22 @@ contline:\n \treturn offset;\n }\n \n+int git_config_set_in_file(const char *key, const char *value,\n+\t\t\tconst char *filename)\n+{\n+\tconst char *saved;\n+\tint ret;\n+\n+\tsaved = config_exclusive_filename;\n+\tconfig_exclusive_filename = filename;\n+\tret = git_config_set_multivar(key, value, NULL, 0);\n+\tconfig_exclusive_filename = saved;\n+\treturn ret;\n+}\n+\n int git_config_set(const char *key, const char *value)\n {\n-\treturn git_config_set_multivar(key, value, NULL, 0);\n+\treturn git_config_set_in_file(key, value, config_exclusive_filename);\n }\n \n /*\n@@ -1387,6 +1400,20 @@ write_err_out:\n \n }\n \n+int git_config_set_multivar_in_file(const char *key, const char *value,\n+\t\t\t\tconst char *value_regex, int multi_replace,\n+\t\t\t\tconst char *filename)\n+{\n+\tconst char *saved;\n+\tint ret;\n+\n+\tsaved = config_exclusive_filename;\n+\tconfig_exclusive_filename = filename;\n+\tret = git_config_set_multivar(key, value, value_regex, multi_replace);\n+\tconfig_exclusive_filename = saved;\n+\treturn ret;\n+}\n+\n static int section_name_match (const char *buf, const char *name)\n {\n \tint i = 0, j = 0, dot = 0;\n-- \n1.7.4.rc1.7.g2cf08.dirty\n"},{"id":"171632","messageId":"7vr55n9mc3.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"1311025032-835-1-git-send-email-artagnon@gmail.com","subject":"Re: [RFC PATCH] config: Introduce functions to write non-standard file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-18T23:54:20Z","receivedAt":"2011-07-18T23:54:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> +int git_config_set_in_file(const char *key, const char *value,\n> +\t\t\tconst char *filename)\n> +{\n> +\tconst char *saved;\n> +\tint ret;\n> +\n> +\tsaved = config_exclusive_filename;\n> +\tconfig_exclusive_filename = filename;\n> +\tret = git_config_set_multivar(key, value, NULL, 0);\n> +\tconfig_exclusive_filename = saved;\n> +\treturn ret;\n> +}\n\nYuck, what an ugly hack when you are so close.  Why not restructure the\ncode in such a way that the updated config-set-multivar and set-in-file\nshare the code better?  If the former takes a hardcoded logic to decide\nwhich file to write to while the latter takes the filename to write to as\nits argument, wouldn't it be a lot more natural to make config-set-multivar\ncall set-in-file after computing what filename parameter to pass?\n"},{"id":"171646","messageId":"CALkWK0mSWxkGZOrZor0+bZNd4V-OrU+6-0n_Lo+F8qCyd=72vA@mail.gmail.com","threadId":"27786","inReplyTo":"7vr55n9mc3.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC PATCH] config: Introduce functions to write non-standard file","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-19T08:52:45Z","receivedAt":"2011-07-19T08:52:45Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n[...]\n> Yuck, what an ugly hack when you are so close.  Why not restructure the\n> code in such a way that the updated config-set-multivar and set-in-file\n> share the code better?  If the former takes a hardcoded logic to decide\n> which file to write to while the latter takes the filename to write to as\n> its argument, wouldn't it be a lot more natural to make config-set-multivar\n> call set-in-file after computing what filename parameter to pass?\n\nUgh, sorry. Fixed now.\n\n-- Ram\n"},{"id":"171649","messageId":"CALkWK0ntcPR5y6m3O6SoTc_8B3xi4dsKFs6zFMJrcwOtRQoQbA@mail.gmail.com","threadId":"27786","inReplyTo":"20110717165904.GA27787@elie","subject":"Re: [PATCH 05/17] revert: Propogate errors upwards from do_pick_commit","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-19T10:09:29Z","receivedAt":"2011-07-19T10:09:29Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> revert: Propogate errors upwards from do_pick_commit\n>>\n>> Currently, revert_or_cherry_pick can fail in two ways.  If it\n>> encounters a conflict, it returns a positive number indicating the\n>> intended exit status for the git wrapper to pass on; for all other\n>> errors, it calls die().  The latter behavior is inconsiderate towards\n>> callers, as it denies them the opportunity to do some post-processing\n>> or cleanup before exiting.  For instance, later in the series, callers\n>> will want to save some data about the current operation before\n>> exiting.\n>\n> Thanks for explaining.  Why can't callers use set_die_routine() or\n> atexit()?  Is the last sentence true?\n\nDefinitely a misguided commit message.\nNew commit message.\n\nrevert: Propogate errors upwards from do_pick_commit\n\nCurrently, revert_or_cherry_pick can fail in two ways.  If it\nencounters a conflict, it returns a positive number indicating the\nintended exit status for the git wrapper to pass on; for all other\nerrors, it calls die().  The latter behavior is inconsiderate towards\ncallers, as it denies them the opportunity to recover from errors and\ndo other things.\n\nAfter this patch, revert_or_cherry_pick will still return a positive\nreturn value to indicate an exit status for conflicts as before, while\nfor some other errors, it will print an error message and return -1\ninstead of die()-ing.  The cmd_revert and cmd_cherry_pick are adjusted\nto handle the fatal errors by die()-ing themselves.\n\nWhile the full benefits of this patch will only be seen once all the\n\"die\" calls are replaced with calls to \"error\", its immediate impact\nis to change some \"fatal:\" messages to say \"error:\" and to add a new\n\"fatal: cherry-pick failed\" message at the end when the operation\nfails.\n\n>  Since no callers take advantage of the ability to recover from\n>  errors yet, it is possible and even likely that these functions do\n>  not completely clean up after themselves on (fatal) error but leave\n>  some state to be cleared away by exit().  Callers beware!\n>\n> That last paragraph summarizes my worry.  Since this API change does\n> not seem to be used by the other patches, I would prefer not to\n> leave such a trap for unwary new callers, at least until the intended\n> legitimate use is a little clearer.\n\nVery legitimate.  Thanks for explaining.  However, I don't think I've\nintroduced any new traps for callers except for the\nwrite_cache_as_tree() thing which is fixed now -- so, I've omitted\nyour warning in the commit message because I'm not entirely sure it's\ntrue.  Yes, we don't have callers that take advantage of this yet, but\nthe idea of the patch is to work in the right direction -- we have to\nconvert all the \"die\" calls to \"error\" calls and make a nice public\nAPI out of it sometime in the future.\n\nAlso, should we worry about it so much at this stage? We haven't set\nup a public API\n\n>>> write_cache_as_tree() locks the index and does not always commit or\n>>> roll it back except on success.  Current callers aren't likely to try\n>>> to lock the index again (since they just die()), but presumably the\n>>> goal of returning error() here is to allow for callers that want to\n>>> stay alive and do something more.  How should they recover (i.e., what\n>>> is the intended API)?\n>>\n>> Hm, there was supposed to be a discard_cache() before this error as I\n>> recall -- fixed now.  Thanks for catching.\n>\n> discard_index() does not unlock the index.\n\nUgh, sorry.  I realize now that you were talking about the lockfile,\nwhich will only be cleaned up by exit().  I thought about this for a\nwhile and decided to classify this as an unrecoverable error for the\nmoment -- we have no way to clean up the lockfile at this stage, so\nmight as well die() instead of setting a trap for callers.\n\n>>> Similar questions probably apply to calls to other APIs that return -1\n>>> to mean \"I failed; please print an appropriate message about that and\n>>> exit\".  I haven't checked carefully, since the answer to this example\n>>> could help in knowing what to look for in the others.\n>>\n>> I think the others are fairly clear actually.\n>\n> Roughly speaking, there are two kinds of functions that return error()\n> instead of die()-ing in the git codebase:\n>\n>  1. Those that recover from their errors, leaving the process in a\n>    sane state that allows the caller (e.g., a long-lived interactive\n>    porcelain) to go on to do other things\n>\n>  2. Those that do not have enough information to give a useful error\n>    message themselves, so delegate to the caller the responsibility\n>    to die() with an error message about where in the program the\n>    failure occured.\n>\n> The commit message suggests that you are introducing a new category:\n>\n>  3. Those that could die() without trouble, _except_ that some callers\n>    want to do cleanup of private state on exit and atexit() is not\n>    working for them for some reason\n\nThanks for the excellent categorization -- this change falls mostly in\ncategory (1), and a little bit in (2) too.  When we work towards a\ngeneral sequencer, do_pick_commit has no idea about the name of git\nwrapper that invoked it (\"git cherry-pick\" or \"git revert\" in this\ncase).  Thinking about these things helped me write a better commit\nmessage.\n\nThanks.\n\n-- Ram\n"},{"id":"171653","messageId":"20110719122102.GA26330@elie.gateway.2wire.net","threadId":"27786","inReplyTo":"CALkWK0kZ3nWnnGe1OHXWgiZ8ik9iNW803wi2d6kUiNDpiOWNDA@mail.gmail.com","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-19T12:21:02Z","receivedAt":"2011-07-19T12:21:02Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> 3. Instead of just saying \"fatal: Malformed instruction sheet\" like we\n> do now, we can put in something a little more helpful like \"error:\n> Cannot cherry-pick during a revert\" before this message.  So:\n>\n> $ git cherry-pick moo\n> ... conflict ...\n> # resolve conflict\n> $ git revert --continue\n> error: Cannot cherry-pick during a revert\n> fatal: Malformed instruction sheet\n>\n> This makes it clear to the user that the instruction sheet is to\n> blame, and in what way.\n\nMakes sense.  Would it be possible to rephrase the message \"Malformed\ninstruction sheet\" to encompass this error?  After all, the\ninstruction sheet is grammatically well formed and the only mistake it\nmade was to do something unexpected.\n\nMaybe\n\n\terror: cannot resume a cherry-pick with \"git revert --continue\"\n\tfatal: unusable instruction sheet\n\nor something along those lines.  I dunno.\n"},{"id":"171654","messageId":"CALkWK0=7OcEEkf2qxSMvG0=W+M=nEJa6shMp7LffokX=yPxLPQ@mail.gmail.com","threadId":"27786","inReplyTo":"20110719122102.GA26330@elie.gateway.2wire.net","subject":"Re: [PATCH 11/17] revert: Save data for continuing after conflict resolution","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-19T12:34:00Z","receivedAt":"2011-07-19T12:34:00Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Maybe\n>\n>        error: cannot resume a cherry-pick with \"git revert --continue\"\n>        fatal: unusable instruction sheet\n\nGood suggestion.  Implemented.  Thanks.\n\n-- Ram\n"},{"id":"171661","messageId":"CALkWK0mmPeYawqF-Dd3Sv_0qYjfYA-36POengYupfjwNBRDj-g@mail.gmail.com","threadId":"27786","inReplyTo":"20110713064240.GC31003@elie","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-19T16:36:15Z","receivedAt":"2011-07-19T16:36:15Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi again,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Fixed all issues.  The commit message now reads\n>>\n>> revert: Inline add_message_to_msg function\n>>\n>> The add_message_to_msg function is poorly implemented, has an unclear\n>> API, and only one callsite.  Replace the callsite with a cleaner\n>> implementation.  Additionally, fix a bug introduced in 9509af6 (Make\n>> git-revert & git-cherry-pick a builtin, 2007-03-01) -- a NULL pointer\n>> was being dereferenced when \"\\n\\n\" was not found in \"message\".\n>\n> That's basically the same as before, with \"dereferenced\" in place of\n> \"incremented\".  An improvement, sure, but it still doesn't answer the\n> basic questions like \"how can I reproduce the bug?\".\n\nThanks for poking -- I figured out what's going on.  The msg.message\ndoesn't just contain the commit message; it contains information like\ntree, parent etc (all the information shown by cat-file).  A typical\nmsg.message looks like:\n\n>>\ntree cb35cb5a8736245fd669729ce40d790062f1d74b\nparent dcab267d57895e9e8710f5a954e8b9bdfa459c71\nauthor Ramkumar Ramachandra <artagnon@gmail.com> 1311091028 +0530\ncommitter Ramkumar Ramachandra <artagnon@gmail.com> 1311091028 +0530\n\nThis is the subject of the message\n\nThis is the description of the message\n<<\n\nThe strstr(msg.message, \"\\n\\n\") actually stops after the 0 in the\ncommitter line.  It's trying to find out where the commit message\nactually begins.  I even created a commit using commit-tree (not using\nporcelain), but it's impossible to find a msg.message that doesn't\nhave a \"\\n\\n\" -- even one with an empty commit message looks like:\n\n>>\ntree cb35cb5a8736245fd669729ce40d790062f1d74b\nparent dcab267d57895e9e8710f5a954e8b9bdfa459c71\nauthor Ramkumar Ramachandra <artagnon@gmail.com> 1311091028 +0530\ncommitter Ramkumar Ramachandra <artagnon@gmail.com> 1311091028 +0530\n\n<<\n\nThe earlier logic was flawed:\n\n\twhile (*p && (*p != '\\n' || p[1] != '\\n'))\n\t\tp++;\n\n\tif (!*p)\n\t\tstrbuf_addstr(msgbuf, sha1_to_hex(commit->object.sha1));\n\nHere, the !*p will never be satisfied even in the case of the empty\ncommit message because p reads \"\\n\\n\" at this point: the picked commit\nwill be filled up with an empty commit message as well.  This is also\nshown by the tests in t3505-cherry-pick-emtpy.sh.  Perhaps this really\nis the desired behavior: why should cherry-pick try to add something\nto the commit message when we're picking a commit with an empty commit\nmessage? Now I realize that the new logic is flawed too.  Since it's\ntotally impossible to reproduce this bug, it's not really a bug --\nthere's just some dead code in the older implementation, and we want\nto remove it and make it clear.\n\nNew commit message and commit.\n\n-- 8< --\nSubject: [PATCH] revert: Simplify and inline add_message_to_msg\n\nThe add_message_to_msg function has some dead code, an unclear API,\nonly one callsite.  While it originally intended fill up an empty\ncommit message with the commit object name while picking, it really\ndoesn't do this -- a bug introduced in 9509af6 (Make git-revert &\ngit-cherry-pick a builtin, 2007-03-01).  Today, tests in\nt3505-cherry-pick-empty.sh indicate that not filling up an empty\ncommit message is the desired behavior.  Re-implement and inline the\nfunction accordingly.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nMentored-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/revert.c |   26 ++++++++++++--------------\n 1 files changed, 12 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 2df3f3b..2b5f261 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -185,19 +185,6 @@ static char *get_encoding(const char *message)\n        return NULL;\n }\n\n-static void add_message_to_msg(struct strbuf *msgbuf, const char *message)\n-{\n-       const char *p = message;\n-       while (*p && (*p != '\\n' || p[1] != '\\n'))\n-               p++;\n-\n-       if (!*p)\n-               strbuf_addstr(msgbuf, sha1_to_hex(commit->object.sha1));\n-\n-       p += 2;\n-       strbuf_addstr(msgbuf, p);\n-}\n-\n static void write_cherry_pick_head(void)\n {\n        int fd;\n@@ -462,11 +449,22 @@ static int do_pick_commit(void)\n                }\n                strbuf_addstr(&msgbuf, \".\\n\");\n        } else {\n+               const char *p;\n+\n                base = parent;\n                base_label = msg.parent_label;\n                next = commit;\n                next_label = msg.label;\n-               add_message_to_msg(&msgbuf, msg.message);\n+\n+               /*\n+                * Append the commit log message to msgbuf; it starts\n+                * after the tree, parent, author, committer\n+                * information followed by \"\\n\\n\".\n+                */\n+               p = strstr(msg.message, \"\\n\\n\");\n+               p += 2;\n+               strbuf_addstr(&msgbuf, p);\n+\n                if (no_replay) {\n                        strbuf_addstr(&msgbuf, \"(cherry picked from commit \");\n                        strbuf_addstr(&msgbuf,\nsha1_to_hex(commit->object.sha1));\n-- \n1.7.4.rc1.7.g2cf08.dirty\n"},{"id":"171662","messageId":"7vfwm29pqz.fsf@alter.siamese.dyndns.org","threadId":"27786","inReplyTo":"CALkWK0mmPeYawqF-Dd3Sv_0qYjfYA-36POengYupfjwNBRDj-g@mail.gmail.com","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-19T16:52:52Z","receivedAt":"2011-07-19T16:52:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> The strstr(msg.message, \"\\n\\n\") actually stops after the 0 in the\n> committer line.  It's trying to find out where the commit message\n> actually begins.  I even created a commit using commit-tree (not using\n> porcelain), but it's impossible to find a msg.message that doesn't\n> have a \"\\n\\n\" -- even one with an empty commit message looks like:\n> ...\n\n... with current git, sure, but I think the code to check for \"just in\ncase we didn't find \\n\\n\" is there because prehistoric versions of git\ncould write such a commit object.\n\nHence...\n\n> @@ -462,11 +449,22 @@ static int do_pick_commit(void)\n>                 }\n>                 strbuf_addstr(&msgbuf, \".\\n\");\n>         } else {\n> +               const char *p;\n> +\n>                 base = parent;\n>                 base_label = msg.parent_label;\n>                 next = commit;\n>                 next_label = msg.label;\n> +\n> +               /*\n> +                * Append the commit log message to msgbuf; it starts\n> +                * after the tree, parent, author, committer\n> +                * information followed by \"\\n\\n\".\n> +                */\n> +               p = strstr(msg.message, \"\\n\\n\");\n\nI would prefer to have if (p) { ... } around the two lines below.\n\n> +               p += 2;\n> +               strbuf_addstr(&msgbuf, p);\n> +\n>                 if (no_replay) {\n>                         strbuf_addstr(&msgbuf, \"(cherry picked from commit \");\n>                         strbuf_addstr(&msgbuf,\n> sha1_to_hex(commit->object.sha1));\n"},{"id":"171664","messageId":"CALkWK0n62+bk1iWgxftfG5KS4xt41bddVuYXe6djrA5CWiFkAw@mail.gmail.com","threadId":"27786","inReplyTo":"7vfwm29pqz.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-19T17:08:38Z","receivedAt":"2011-07-19T17:08:38Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>> The strstr(msg.message, \"\\n\\n\") actually stops after the 0 in the\n>> committer line.  It's trying to find out where the commit message\n>> actually begins.  I even created a commit using commit-tree (not using\n>> porcelain), but it's impossible to find a msg.message that doesn't\n>> have a \"\\n\\n\" -- even one with an empty commit message looks like:\n>> ...\n>\n> ... with current git, sure, but I think the code to check for \"just in\n> case we didn't find \\n\\n\" is there because prehistoric versions of git\n> could write such a commit object.\n\nAh, I see :)\n\n> I would prefer to have if (p) { ... } around the two lines below.\n>\n>> +               p += 2;\n>> +               strbuf_addstr(&msgbuf, p);\n\nDone.  Thanks.\n\n-- Ram\n"},{"id":"171694","messageId":"20110719193608.GA26557@elie.gateway.2wire.net","threadId":"27786","inReplyTo":"CALkWK0mmPeYawqF-Dd3Sv_0qYjfYA-36POengYupfjwNBRDj-g@mail.gmail.com","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-07-19T19:36:08Z","receivedAt":"2011-07-19T19:36:08Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Ramkumar Ramachandra wrote:\n\n> Since it's\n> totally impossible to reproduce this bug, it's not really a bug --\n\nHuh?\n\n\tgit cat-file commit HEAD | sed -e '/^$/ q' >newcommit &&\n\tcmit=$(git hash-object -t commit -w newcommit) &&\n\tgit cherry-pick $cmit\n\nFun bonus:\n\n\tgit log $cmit\n"},{"id":"171717","messageId":"CALkWK0=shto-FaRvtc0EXuD8kM6z=TzU=VEztznSNwJ6n2RhXA@mail.gmail.com","threadId":"27786","inReplyTo":"20110719193608.GA26557@elie.gateway.2wire.net","subject":"Re: [PATCH 02/17] revert: Inline add_message_to_msg function","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2011-07-20T05:32:30Z","receivedAt":"2011-07-20T05:32:30Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nJonathan Nieder writes:\n> Ramkumar Ramachandra wrote:\n>> Since it's\n>> totally impossible to reproduce this bug, it's not really a bug --\n>\n> Huh?\n>\n>        git cat-file commit HEAD | sed -e '/^$/ q' >newcommit &&\n>        cmit=$(git hash-object -t commit -w newcommit) &&\n>        git cherry-pick $cmit\n\nOh.  I should've been clearer -- it's totally impossible to reproduce\nthis bug, except by hand-crafting a commit object.\nThanks for the interesting exercise.\n\n-- Ram\n"}]}