{"thread":{"id":"20768","subject":"[PATCH v4 02/15] sequencer: add \"make_patch\" function to save a patch","startedAt":"2009-08-28T04:47:30Z","lastAt":"2009-08-28T06:08:54Z","messageCount":17,"participants":["Christian Couder","Eric Raible"],"isPatch":true,"patchVersion":4,"patchTotal":15},"messages":[{"id":"121961","messageId":"20090828043913.4307.34708.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":null,"subject":"[PATCH v4 00/15] complete reroll of my \"port rebase -i to C\" series","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:30Z","receivedAt":"2009-08-28T04:47:30Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"So unlike previous series, this is a complete reroll of all my previous\npatches to port rebase -i to C using code from the sequencer project.\n\nThe main changes are in the commit messages that I tried to improve\naccording to Junio's feedback. But some patches were also squashed\ntogether and there are a few minor changes too:\n\n- comments have been added before the pick_commit() function (patch\n11/15: revert: libify cherry-pick and revert functionnality),\n\n- and a line in the usage message as been removed from patch 13/15\n(sequencer: add \"do_commit()\" and related functions) because it should\nbe added by the next patch instead.\n\nChristian Couder (9):\n  sequencer: add \"builtin-sequencer--helper.c\"\n  rebase -i: use \"git sequencer--helper --make-patch\"\n  sequencer: add \"--reset-hard\" option to \"git sequencer--helper\"\n  rebase -i: use \"git sequencer--helper --reset-hard\"\n  sequencer: add \"--fast-forward\" option to \"git sequencer--helper\"\n  sequencer: let \"git sequencer--helper\" callers set \"allow_dirty\"\n  rebase -i: use \"git sequencer--helper --fast-forward\"\n  pick: libify \"pick_help_msg()\"\n  rebase -i: use \"git sequencer--helper --cherry-pick\"\n\nStephan Beyer (6):\n  sequencer: add \"make_patch\" function to save a patch\n  sequencer: add \"reset_almost_hard()\" and related functions\n  sequencer: add \"do_fast_forward()\" to perform a fast forward\n  revert: libify cherry-pick and revert functionnality\n  sequencer: add \"do_commit()\" and related functions working on\n    \"next_commit\"\n  sequencer: add \"--cherry-pick\" option to \"git sequencer--helper\"\n\n .gitignore                  |    1 +\n Makefile                    |    3 +\n builtin-revert.c            |  293 ++++--------------------\n builtin-sequencer--helper.c |  543 +++++++++++++++++++++++++++++++++++++++++++\n builtin.h                   |    1 +\n git-rebase--interactive.sh  |   42 ++--\n git.c                       |    1 +\n pick.c                      |  240 +++++++++++++++++++\n pick.h                      |   14 ++\n 9 files changed, 865 insertions(+), 273 deletions(-)\n create mode 100644 builtin-sequencer--helper.c\n create mode 100644 pick.c\n create mode 100644 pick.h\n"},{"id":"121959","messageId":"20090828044746.4307.60033.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 01/15] sequencer: add \"builtin-sequencer--helper.c\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:31Z","receivedAt":"2009-08-28T04:47:31Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This a helper builtin that will be used to port some parts of\n\"git-rebase--interactive.sh\" to C.\n\nIt currently does nothing except checking arguments it is passed.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n .gitignore                  |    1 +\n Makefile                    |    1 +\n builtin-sequencer--helper.c |   27 +++++++++++++++++++++++++++\n builtin.h                   |    1 +\n git.c                       |    1 +\n 5 files changed, 31 insertions(+), 0 deletions(-)\n create mode 100644 builtin-sequencer--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex c446290..adbe7cc 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -119,6 +119,7 @@ git-revert\n git-rm\n git-send-email\n git-send-pack\n+git-sequencer--helper\n git-sh-setup\n git-shell\n git-shortlog\ndiff --git a/Makefile b/Makefile\nindex 4190a5d..4aab6bc 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -628,6 +628,7 @@ BUILTIN_OBJS += builtin-rev-parse.o\n BUILTIN_OBJS += builtin-revert.o\n BUILTIN_OBJS += builtin-rm.o\n BUILTIN_OBJS += builtin-send-pack.o\n+BUILTIN_OBJS += builtin-sequencer--helper.o\n BUILTIN_OBJS += builtin-shortlog.o\n BUILTIN_OBJS += builtin-show-branch.o\n BUILTIN_OBJS += builtin-show-ref.o\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nnew file mode 100644\nindex 0000000..721c0d8\n--- /dev/null\n+++ b/builtin-sequencer--helper.c\n@@ -0,0 +1,27 @@\n+#include \"builtin.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+\n+static const char * const git_sequencer_helper_usage[] = {\n+\t\"git sequencer--helper --make-patch <commit>\",\n+\tNULL\n+};\n+\n+int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *commit = NULL;\n+\tstruct option options[] = {\n+\t\tOPT_STRING(0, \"make-patch\", &commit, \"commit\",\n+\t\t\t   \"create a patch from commit\"),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     git_sequencer_helper_usage, 0);\n+\n+\tif (!commit)\n+\t\tusage_with_options(git_sequencer_helper_usage, options);\n+\n+\t/* Nothing to do yet */\n+\treturn 0;\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 51e4ba7..0a60e81 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -91,6 +91,7 @@ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);\n extern int cmd_revert(int argc, const char **argv, const char *prefix);\n extern int cmd_rm(int argc, const char **argv, const char *prefix);\n extern int cmd_send_pack(int argc, const char **argv, const char *prefix);\n+extern int cmd_sequencer__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_shortlog(int argc, const char **argv, const char *prefix);\n extern int cmd_show(int argc, const char **argv, const char *prefix);\n extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\ndiff --git a/git.c b/git.c\nindex 0021a29..d510758 100644\n--- a/git.c\n+++ b/git.c\n@@ -345,6 +345,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"revert\", cmd_revert, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"rm\", cmd_rm, RUN_SETUP },\n \t\t{ \"send-pack\", cmd_send_pack, RUN_SETUP },\n+\t\t{ \"sequencer--helper\", cmd_sequencer__helper, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"shortlog\", cmd_shortlog, USE_PAGER },\n \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n-- \n1.6.4.271.ge010d\n"},{"id":"121958","messageId":"20090828044746.4307.75314.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 02/15] sequencer: add \"make_patch\" function to save a patch","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:32Z","receivedAt":"2009-08-28T04:47:32Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThis function generates an informational patch file. The file name\nis fixed to \"$SEQ_DIR/patch\".\n\nThe \"make_patch\" and the \"get_commit\" functions are copied from the\nGSoC sequencer project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |   79 ++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 78 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex 721c0d8..1dda525 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -1,15 +1,87 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"run-command.h\"\n+\n+#define SEQ_DIR \"rebase-merge\"\n+\n+#define PATCH_FILE\tgit_path(SEQ_DIR \"/patch\")\n \n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n \tNULL\n };\n \n+/* Generate purely informational patch file */\n+static void make_patch(struct commit *commit)\n+{\n+\tstruct commit_list *parents = commit->parents;\n+\tconst char **args;\n+\tstruct child_process chld;\n+\tint i;\n+\tint fd = open(PATCH_FILE, O_WRONLY | O_CREAT, 0666);\n+\tif (fd < 0)\n+\t\treturn;\n+\n+\tmemset(&chld, 0, sizeof(chld));\n+\tif (!parents) {\n+\t\twrite(fd, \"Root commit\\n\", 12);\n+\t\tclose(fd);\n+\t\treturn;\n+\t} else if (!parents->next) {\n+\t\targs = xcalloc(5, sizeof(char *));\n+\t\targs[0] = \"diff-tree\";\n+\t\targs[1] = \"-p\";\n+\t\targs[2] = xstrdup(sha1_to_hex(parents->item->object.sha1));\n+\t\targs[3] = xstrdup(sha1_to_hex(((struct object *)commit)->sha1));\n+\t} else {\n+\t\tint count = 1;\n+\n+\t\tfor (; parents; parents = parents->next)\n+\t\t\t++count;\n+\n+\t\ti = 0;\n+\t\targs = xcalloc(count + 3, sizeof(char *));\n+\t\targs[i++] = \"diff\";\n+\t\targs[i++] = \"--cc\";\n+\t\targs[i++] = xstrdup(sha1_to_hex(commit->object.sha1));\n+\n+\t\tfor (parents = commit->parents; parents;\n+\t\t     parents = parents->next) {\n+\t\t\tchar *hex = sha1_to_hex(parents->item->object.sha1);\n+\t\t\targs[i++] = xstrdup(hex);\n+\t\t}\n+\t}\n+\n+\tchld.argv = args;\n+\tchld.git_cmd = 1;\n+\tchld.out = fd;\n+\n+\t/* Run, ignore errors. */\n+\tif (!start_command(&chld))\n+\t\tfinish_command(&chld);\n+\n+\tfor (i = 2; args[i]; i++)\n+\t\tfree((char *)args[i]);\n+\tfree(args);\n+}\n+\n+/* Return a commit object of \"arg\" */\n+static struct commit *get_commit(const char *arg)\n+{\n+\tunsigned char sha1[20];\n+\n+\tif (get_sha1(arg, sha1)) {\n+\t\terror(\"Could not find '%s'\", arg);\n+\t\treturn NULL;\n+\t}\n+\treturn lookup_commit_reference(sha1);\n+}\n+\n int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n {\n \tchar *commit = NULL;\n+\tstruct commit *c;\n \tstruct option options[] = {\n \t\tOPT_STRING(0, \"make-patch\", &commit, \"commit\",\n \t\t\t   \"create a patch from commit\"),\n@@ -22,6 +94,11 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \tif (!commit)\n \t\tusage_with_options(git_sequencer_helper_usage, options);\n \n-\t/* Nothing to do yet */\n+\tc = get_commit(commit);\n+\tif (!c)\n+\t\treturn 1;\n+\n+\tmake_patch(c);\n+\n \treturn 0;\n }\n-- \n1.6.4.271.ge010d\n"},{"id":"121973","messageId":"20090828044746.4307.95146.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 03/15] rebase -i: use \"git sequencer--helper --make-patch\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:33Z","receivedAt":"2009-08-28T04:47:33Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"to simplify the \"make_patch\" function.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n git-rebase--interactive.sh |   13 +------------\n 1 files changed, 1 insertions(+), 12 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 23ded48..c9c75c0 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -117,18 +117,7 @@ mark_action_done () {\n }\n \n make_patch () {\n-\tsha1_and_parents=\"$(git rev-list --parents -1 \"$1\")\"\n-\tcase \"$sha1_and_parents\" in\n-\t?*' '?*' '?*)\n-\t\tgit diff --cc $sha1_and_parents\n-\t\t;;\n-\t?*' '?*)\n-\t\tgit diff-tree -p \"$1^!\"\n-\t\t;;\n-\t*)\n-\t\techo \"Root commit\"\n-\t\t;;\n-\tesac > \"$DOTEST\"/patch\n+\tgit sequencer--helper --make-patch \"$1\"\n \ttest -f \"$DOTEST\"/message ||\n \t\tgit cat-file commit \"$1\" | sed \"1,/^$/d\" > \"$DOTEST\"/message\n \ttest -f \"$DOTEST\"/author-script ||\n-- \n1.6.4.271.ge010d\n"},{"id":"121960","messageId":"20090828044746.4307.88742.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 04/15] sequencer: add \"reset_almost_hard()\" and related functions","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:34Z","receivedAt":"2009-08-28T04:47:34Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThis patch adds the \"reset_almost_hard()\" function, some related\nstatic variables and the related following functions:\n\n\t- parse_and_init_tree_desc()\n\t- reset_index_file()\n\t- set_verbosity()\n\n\"reset_almost_hard()\" can be used to do a \"git reset --hard\". It\nshould be faster as it calls \"unpack_trees()\" directly, and it can\noptionnaly preserve changes in the work tree if the \"allow_dirty\"\nglobal is set. Preserving changes in the work tree can be usefull\nif for example you want to get rid of the last commit but keep\nyour current not yet commited work.\n\nIn this patch the \"allow_dirty\" global is not used but a following\npatch will make it possible to set it, and in the end the code\nshould be simpler with a global.\n\nThe code comes as is from the sequencer GSoC project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |  107 +++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 107 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex 1dda525..a15139c 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -2,16 +2,108 @@\n #include \"cache.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\n+#include \"refs.h\"\n+#include \"diff.h\"\n+#include \"unpack-trees.h\"\n \n #define SEQ_DIR \"rebase-merge\"\n \n #define PATCH_FILE\tgit_path(SEQ_DIR \"/patch\")\n \n+static char *reflog;\n+\n+static int allow_dirty = 0, verbosity = 1, advice = 1;\n+\n+static unsigned char head_sha1[20];\n+\n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n \tNULL\n };\n \n+static int parse_and_init_tree_desc(const unsigned char *sha1,\n+\t\t\t\t    struct tree_desc *desc)\n+{\n+\tstruct tree *tree = parse_tree_indirect(sha1);\n+\tif (!tree)\n+\t\treturn 1;\n+\tinit_tree_desc(desc, tree->buffer, tree->size);\n+\treturn 0;\n+}\n+\n+static int reset_index_file(const unsigned char *sha1, int update, int dirty)\n+{\n+\tint nr = 1;\n+\tint newfd;\n+\tstruct tree_desc desc[2];\n+\tstruct unpack_trees_options opts;\n+\tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\topts.head_idx = 1;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.reset = 1; /* ignore unmerged entries and overwrite wt files */\n+\topts.merge = 1;\n+\topts.fn = oneway_merge;\n+\tif (verbosity > 2)\n+\t\topts.verbose_update = 1;\n+\tif (update) /* update working tree */\n+\t\topts.update = 1;\n+\n+\tnewfd = hold_locked_index(lock, 1);\n+\n+\tread_cache_unmerged();\n+\n+\tif (dirty) {\n+\t\tif (get_sha1(\"HEAD\", head_sha1))\n+\t\t\treturn error(\"You do not have a valid HEAD.\");\n+\t\tif (parse_and_init_tree_desc(head_sha1, desc))\n+\t\t\treturn error(\"Failed to find tree of HEAD.\");\n+\t\tnr++;\n+\t\topts.fn = twoway_merge;\n+\t}\n+\n+\tif (parse_and_init_tree_desc(sha1, desc + nr - 1))\n+\t\treturn error(\"Failed to find tree of %s.\", sha1_to_hex(sha1));\n+\tif (unpack_trees(nr, desc, &opts))\n+\t\treturn -1;\n+\tif (write_cache(newfd, active_cache, active_nr) ||\n+\t    commit_locked_index(lock))\n+\t\treturn error(\"Could not write new index file.\");\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Realize reset --hard behavior.\n+ * If allow_dirty is set and there is a dirty work tree,\n+ * then the changes in the work tree are to be kept.\n+ *\n+ * This should be faster than calling \"git reset --hard\" because\n+ * this calls \"unpack_trees()\" directly (instead of forking and\n+ * execing \"git read-tree\").\n+ *\n+ * Unmerged entries in the index will be discarded.\n+ *\n+ * If allow_dirty is set and fast forwarding the work tree\n+ * fails because it is dirty, then the work tree will not be\n+ * updated.\n+ *\n+ * No need to read or discard the index before calling this\n+ * function.\n+ */\n+static int reset_almost_hard(const unsigned char *sha)\n+{\n+\tint err = allow_dirty ?\n+\t\t(reset_index_file(sha, 1, 1) || reset_index_file(sha, 0, 0)) :\n+\t\treset_index_file(sha, 1, 0);\n+\tif (err)\n+\t\treturn error(\"Could not reset index.\");\n+\n+\treturn update_ref(reflog, \"HEAD\", sha, NULL, 0, MSG_ON_ERR);\n+}\n+\n /* Generate purely informational patch file */\n static void make_patch(struct commit *commit)\n {\n@@ -78,6 +170,21 @@ static struct commit *get_commit(const char *arg)\n \treturn lookup_commit_reference(sha1);\n }\n \n+static int set_verbosity(int verbose)\n+{\n+\tchar tmp[] = \"0\";\n+\tverbosity = verbose;\n+\tif (verbosity <= 0) {\n+\t\tverbosity = 0;\n+\t\tadvice = 0;\n+\t} else if (verbosity > 5)\n+\t\tverbosity = 5;\n+\t/* Git does not run on EBCDIC, so we rely on ASCII: */\n+\ttmp[0] += verbosity;\n+\tsetenv(\"GIT_MERGE_VERBOSITY\", tmp, 1);\n+\treturn 0;\n+}\n+\n int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n {\n \tchar *commit = NULL;\n-- \n1.6.4.271.ge010d\n"},{"id":"121962","messageId":"20090828044746.4307.86010.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 05/15] sequencer: add \"--reset-hard\" option to \"git sequencer--helper\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:35Z","receivedAt":"2009-08-28T04:47:35Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This new option uses the \"reset_almost_hard()\" function to perform\na reset.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |   65 ++++++++++++++++++++++++++++++++++++------\n 1 files changed, 55 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex a15139c..be030bc 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -18,6 +18,7 @@ static unsigned char head_sha1[20];\n \n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n+\t\"git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>\",\n \tNULL\n };\n \n@@ -185,27 +186,71 @@ static int set_verbosity(int verbose)\n \treturn 0;\n }\n \n+/* v should be \"\" or \"t\" or \"\\d\" */\n+static int parse_verbosity(const char *v)\n+{\n+\t/* \"\" means verbosity = 1 */\n+\tif (!v[0])\n+\t\treturn set_verbosity(1);\n+\n+\tif (v[1])\n+\t\treturn 1;\n+\n+\tif (v[0] == 't')\n+\t\treturn set_verbosity(2);\n+\n+\tif (!isdigit(v[0]))\n+\t\treturn 1;\n+\n+\treturn set_verbosity(v[0] - '0');\n+}\n+\n int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n {\n-\tchar *commit = NULL;\n-\tstruct commit *c;\n+\tchar *patch_commit = NULL;\n+\tchar *reset_commit = NULL;\n \tstruct option options[] = {\n-\t\tOPT_STRING(0, \"make-patch\", &commit, \"commit\",\n+\t\tOPT_STRING(0, \"make-patch\", &patch_commit, \"commit\",\n \t\t\t   \"create a patch from commit\"),\n+\t\tOPT_STRING(0, \"reset-hard\", &reset_commit, \"commit\",\n+\t\t\t   \"reset to commit\"),\n \t\tOPT_END()\n \t};\n \n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_sequencer_helper_usage, 0);\n \n-\tif (!commit)\n-\t\tusage_with_options(git_sequencer_helper_usage, options);\n+\tif (patch_commit) {\n+\t\tstruct commit *c = get_commit(patch_commit);\n+\t\tif (!c)\n+\t\t\treturn 1;\n \n-\tc = get_commit(commit);\n-\tif (!c)\n-\t\treturn 1;\n+\t\tmake_patch(c);\n \n-\tmake_patch(c);\n+\t\treturn 0;\n+\t}\n \n-\treturn 0;\n+\tif (reset_commit) {\n+\t\tunsigned char sha1[20];\n+\n+\t\tif (argc != 2)\n+\t\t\tusage_with_options(git_sequencer_helper_usage,\n+\t\t\t\t\t   options);\n+\n+\t\tif (get_sha1(reset_commit, sha1)) {\n+\t\t\terror(\"Could not find '%s'\", reset_commit);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\treflog = (char *)argv[0];\n+\n+\t\tif (parse_verbosity(argv[1])) {\n+\t\t\terror(\"bad verbosity '%s'\", argv[1]);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\treturn reset_almost_hard(sha1);\n+\t}\n+\n+\tusage_with_options(git_sequencer_helper_usage, options);\n }\n-- \n1.6.4.271.ge010d\n"},{"id":"121963","messageId":"20090828044746.4307.71321.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 06/15] rebase -i: use \"git sequencer--helper --reset-hard\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:36Z","receivedAt":"2009-08-28T04:47:36Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"instead of \"git reset --hard\"\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n git-rebase--interactive.sh |   13 +++++++++----\n 1 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c9c75c0..0041994 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -154,7 +154,8 @@ pick_one () {\n \t\tdie \"Could not get the parent of $sha1\"\n \tcurrent_sha1=$(git rev-parse --verify HEAD)\n \tif test \"$no_ff$current_sha1\" = \"$parent_sha1\"; then\n-\t\toutput git reset --hard $sha1\n+\t\tgit sequencer--helper --reset-hard $sha1 \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\"\n \t\ttest \"a$1\" = a-n && output git reset --soft $current_sha1\n \t\tsha1=$(git rev-parse --short $sha1)\n \t\toutput warn Fast forward to $sha1\n@@ -238,7 +239,8 @@ pick_one_preserving_merges () {\n \tcase $fast_forward in\n \tt)\n \t\toutput warn \"Fast forward to $sha1\"\n-\t\toutput git reset --hard $sha1 ||\n+\t\tgit sequencer--helper --reset-hard $sha1 \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" ||\n \t\t\tdie \"Cannot fast forward to $sha1\"\n \t\t;;\n \tf)\n@@ -536,7 +538,8 @@ first and then run 'git rebase --continue' again.\"\n \t\t\tgit symbolic-ref HEAD $HEADNAME\n \t\t\t;;\n \t\tesac &&\n-\t\toutput git reset --hard $HEAD &&\n+\t\tgit sequencer--helper --reset-hard $HEAD \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" &&\n \t\trm -rf \"$DOTEST\"\n \t\texit\n \t\t;;\n@@ -548,7 +551,9 @@ first and then run 'git rebase --continue' again.\"\n \t\tgit rerere clear\n \t\ttest -d \"$DOTEST\" || die \"No interactive rebase running\"\n \n-\t\toutput git reset --hard && do_rest\n+\t\tgit sequencer--helper --reset-hard HEAD \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" &&\n+\t\tdo_rest\n \t\t;;\n \t-s)\n \t\tcase \"$#,$1\" in\n-- \n1.6.4.271.ge010d\n"},{"id":"121967","messageId":"20090828044746.4307.88217.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 07/15] sequencer: add \"do_fast_forward()\" to perform a fast forward","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:37Z","receivedAt":"2009-08-28T04:47:37Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThis function is a thin wrapper around \"reset_almost_hard()\".\nIt is usefull because it will help reduce a little the shell\ncode line count.\n\nThis code is taken from the sequencer GSoC project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nbut the messages have been changed a little to be the same as\nthose displayed by \"git-rebase--interactive.sh\".\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |    9 +++++++++\n 1 files changed, 9 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex be030bc..0cd7e98 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -171,6 +171,15 @@ static struct commit *get_commit(const char *arg)\n \treturn lookup_commit_reference(sha1);\n }\n \n+static int do_fast_forward(const unsigned char *sha)\n+{\n+\tif (reset_almost_hard(sha))\n+\t\treturn error(\"Cannot fast forward to %s\", sha1_to_hex(sha));\n+\tif (verbosity > 1)\n+\t\tprintf(\"Fast forward to %s\\n\", sha1_to_hex(sha));\n+\treturn 0;\n+}\n+\n static int set_verbosity(int verbose)\n {\n \tchar tmp[] = \"0\";\n-- \n1.6.4.271.ge010d\n"},{"id":"121970","messageId":"20090828044746.4307.9864.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 08/15] sequencer: add \"--fast-forward\" option to \"git sequencer--helper\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:38Z","receivedAt":"2009-08-28T04:47:38Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This new option uses the \"do_fast_forward()\" function to perform\na fast forward.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |   16 ++++++++++++----\n 1 files changed, 12 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex 0cd7e98..bd72f65 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -19,6 +19,7 @@ static unsigned char head_sha1[20];\n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n \t\"git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>\",\n+\t\"git sequencer--helper --fast-forward <commit> <reflog-msg> <verbosity>\",\n \tNULL\n };\n \n@@ -218,11 +219,14 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n {\n \tchar *patch_commit = NULL;\n \tchar *reset_commit = NULL;\n+\tchar *ff_commit = NULL;\n \tstruct option options[] = {\n \t\tOPT_STRING(0, \"make-patch\", &patch_commit, \"commit\",\n \t\t\t   \"create a patch from commit\"),\n \t\tOPT_STRING(0, \"reset-hard\", &reset_commit, \"commit\",\n \t\t\t   \"reset to commit\"),\n+\t\tOPT_STRING(0, \"fast-forward\", &ff_commit, \"commit\",\n+\t\t\t   \"fast forward to commit\"),\n \t\tOPT_END()\n \t};\n \n@@ -239,15 +243,16 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\treturn 0;\n \t}\n \n-\tif (reset_commit) {\n+\tif (ff_commit || reset_commit) {\n \t\tunsigned char sha1[20];\n+\t\tchar *commit = ff_commit ? ff_commit : reset_commit;\n \n \t\tif (argc != 2)\n \t\t\tusage_with_options(git_sequencer_helper_usage,\n \t\t\t\t\t   options);\n \n-\t\tif (get_sha1(reset_commit, sha1)) {\n-\t\t\terror(\"Could not find '%s'\", reset_commit);\n+\t\tif (get_sha1(commit, sha1)) {\n+\t\t\terror(\"Could not find '%s'\", commit);\n \t\t\treturn 1;\n \t\t}\n \n@@ -258,7 +263,10 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\t\treturn 1;\n \t\t}\n \n-\t\treturn reset_almost_hard(sha1);\n+\t\tif (ff_commit)\n+\t\t\treturn do_fast_forward(sha1);\n+\t\telse\n+\t\t\treturn reset_almost_hard(sha1);\n \t}\n \n \tusage_with_options(git_sequencer_helper_usage, options);\n-- \n1.6.4.271.ge010d\n"},{"id":"121969","messageId":"20090828044746.4307.53606.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 09/15] sequencer: let \"git sequencer--helper\" callers set \"allow_dirty\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:39Z","receivedAt":"2009-08-28T04:47:39Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This flag can be set when using --reset-hard or --fast-forward, and\nin this case changes in the work tree will be kept.\n\nThis change is usefull to let people play with the \"allow_dirty\"\nfeature.\n\nSuggested-by: Daniel Barkalow <barkalow@iabervon.org>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-sequencer--helper.c |   11 ++++++++---\n 1 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex bd72f65..71a7fef 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -18,8 +18,10 @@ static unsigned char head_sha1[20];\n \n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n-\t\"git sequencer--helper --reset-hard <commit> <reflog-msg> <verbosity>\",\n-\t\"git sequencer--helper --fast-forward <commit> <reflog-msg> <verbosity>\",\n+\t\"git sequencer--helper --reset-hard <commit> <reflog-msg> \"\n+\t\t\"<verbosity> [<allow-dirty>]\",\n+\t\"git sequencer--helper --fast-forward <commit> <reflog-msg> \"\n+\t\t\"<verbosity> [<allow-dirty>]\",\n \tNULL\n };\n \n@@ -247,7 +249,7 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\tunsigned char sha1[20];\n \t\tchar *commit = ff_commit ? ff_commit : reset_commit;\n \n-\t\tif (argc != 2)\n+\t\tif (argc != 2 && argc != 3)\n \t\t\tusage_with_options(git_sequencer_helper_usage,\n \t\t\t\t\t   options);\n \n@@ -263,6 +265,9 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\t\treturn 1;\n \t\t}\n \n+\t\tif (argc == 3 && *argv[2] && strcmp(argv[2], \"0\"))\n+\t\t\tallow_dirty = 1;\n+\n \t\tif (ff_commit)\n \t\t\treturn do_fast_forward(sha1);\n \t\telse\n-- \n1.6.4.271.ge010d\n"},{"id":"121972","messageId":"20090828044746.4307.55101.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 10/15] rebase -i: use \"git sequencer--helper --fast-forward\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:40Z","receivedAt":"2009-08-28T04:47:40Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"when fast forwarding, as it removes a few more lines of shell\ncode.\n\nNote that in the first hunk of this patch, there was this line:\n\ntest \"a$1\" = a-n && output git reset --soft $current_sha1\n\nbut the test always failed.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n git-rebase--interactive.sh |   11 +++--------\n 1 files changed, 3 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0041994..7651fd6 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -154,11 +154,8 @@ pick_one () {\n \t\tdie \"Could not get the parent of $sha1\"\n \tcurrent_sha1=$(git rev-parse --verify HEAD)\n \tif test \"$no_ff$current_sha1\" = \"$parent_sha1\"; then\n-\t\tgit sequencer--helper --reset-hard $sha1 \\\n+\t\tgit sequencer--helper --fast-forward $sha1 \\\n \t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\"\n-\t\ttest \"a$1\" = a-n && output git reset --soft $current_sha1\n-\t\tsha1=$(git rev-parse --short $sha1)\n-\t\toutput warn Fast forward to $sha1\n \telse\n \t\toutput git cherry-pick \"$@\"\n \tfi\n@@ -238,10 +235,8 @@ pick_one_preserving_merges () {\n \tdone\n \tcase $fast_forward in\n \tt)\n-\t\toutput warn \"Fast forward to $sha1\"\n-\t\tgit sequencer--helper --reset-hard $sha1 \\\n-\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" ||\n-\t\t\tdie \"Cannot fast forward to $sha1\"\n+\t\tgit sequencer--helper --fast-forward $sha1 \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" || exit\n \t\t;;\n \tf)\n \t\tfirst_parent=$(expr \"$new_parents\" : ' \\([^ ]*\\)')\n-- \n1.6.4.271.ge010d\n"},{"id":"121964","messageId":"20090828044746.4307.25608.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 11/15] revert: libify cherry-pick and revert functionnality","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:41Z","receivedAt":"2009-08-28T04:47:41Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThe goal of this commit is to abstract out \"git cherry-pick\" and\n\"git revert\" functionnality into a new pick_commit() function made\nof code from \"builtin-revert.c\".\n\nThe new pick_commit() function is in a new \"pick.c\" file with an\nassociated \"pick.h\".\n\nThis function starts from the current index (not HEAD), and allow\nthe effect of one commit replayed (either forward or backward) to\nthat state, leaving the result in the index. So it makes it\npossible to replay many commits to the index in sequence without\ncommiting in between.\n\nThis commit is made of code from the sequencer GSoC project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nAnd it contains some changes and comments suggested by Junio.\n\nThe original commit in the sequencer project that introduced\nthis change is: 94a568a78d243d7a6c13778bc6b7ac1eb46e48cc\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Makefile         |    2 +\n builtin-revert.c |  272 +++++++++---------------------------------------------\n pick.c           |  218 +++++++++++++++++++++++++++++++++++++++++++\n pick.h           |   13 +++\n 4 files changed, 277 insertions(+), 228 deletions(-)\n create mode 100644 pick.c\n create mode 100644 pick.h\n\ndiff --git a/Makefile b/Makefile\nindex 4aab6bc..372b263 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -432,6 +432,7 @@ LIB_H += pack-refs.h\n LIB_H += pack-revindex.h\n LIB_H += parse-options.h\n LIB_H += patch-ids.h\n+LIB_H += pick.h\n LIB_H += pkt-line.h\n LIB_H += progress.h\n LIB_H += quote.h\n@@ -519,6 +520,7 @@ LIB_OBJS += parse-options.o\n LIB_OBJS += patch-delta.o\n LIB_OBJS += patch-ids.o\n LIB_OBJS += path.o\n+LIB_OBJS += pick.o\n LIB_OBJS += pkt-line.o\n LIB_OBJS += preload-index.o\n LIB_OBJS += pretty.o\ndiff --git a/builtin-revert.c b/builtin-revert.c\nindex 151aa6a..4797ac5 100644\n--- a/builtin-revert.c\n+++ b/builtin-revert.c\n@@ -1,18 +1,14 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n-#include \"object.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n-#include \"wt-status.h\"\n-#include \"run-command.h\"\n #include \"exec_cmd.h\"\n #include \"utf8.h\"\n #include \"parse-options.h\"\n-#include \"cache-tree.h\"\n #include \"diff.h\"\n #include \"revision.h\"\n #include \"rerere.h\"\n-#include \"merge-recursive.h\"\n+#include \"pick.h\"\n \n /*\n  * This implements the builtins revert and cherry-pick.\n@@ -35,25 +31,23 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, no_replay, no_commit, mainline, signoff;\n-static enum { REVERT, CHERRY_PICK } action;\n+static int edit, no_commit, mainline, signoff;\n+static int flags;\n static struct commit *commit;\n \n-static const char *me;\n-\n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n static void parse_args(int argc, const char **argv)\n {\n \tconst char * const * usage_str =\n-\t\taction == REVERT ?  revert_usage : cherry_pick_usage;\n+\t\tflags & PICK_REVERSE ? revert_usage : cherry_pick_usage;\n \tunsigned char sha1[20];\n \tconst char *arg;\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('x', NULL, &no_replay, \"append commit name when cherry-picking\"),\n+\t\tOPT_BIT('x', NULL, &flags, \"append commit name when cherry-picking\", PICK_ADD_NOTE),\n \t\tOPT_BOOLEAN('r', NULL, &noop, \"no-op (backward compatibility)\"),\n \t\tOPT_BOOLEAN('s', \"signoff\", &signoff, \"add Signed-off-by:\"),\n \t\tOPT_INTEGER('m', \"mainline\", &mainline, \"parent number\"),\n@@ -77,42 +71,12 @@ static void parse_args(int argc, const char **argv)\n \t\tdie (\"'%s' does not point to a commit\", arg);\n }\n \n-static char *get_oneline(const char *message)\n-{\n-\tchar *result;\n-\tconst char *p = message, *abbrev, *eol;\n-\tint abbrev_len, oneline_len;\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' || p[1] != '\\n'))\n-\t\tp++;\n-\n-\tif (*p) {\n-\t\tp += 2;\n-\t\tfor (eol = p + 1; *eol && *eol != '\\n'; eol++)\n-\t\t\t; /* do nothing */\n-\t} else\n-\t\teol = p;\n-\tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n-\tabbrev_len = strlen(abbrev);\n-\toneline_len = eol - p;\n-\tresult = xmalloc(abbrev_len + 5 + oneline_len);\n-\tmemcpy(result, abbrev, abbrev_len);\n-\tmemcpy(result + abbrev_len, \"... \", 4);\n-\tmemcpy(result + abbrev_len + 4, p, oneline_len);\n-\tresult[abbrev_len + 4 + oneline_len] = '\\0';\n-\treturn result;\n-}\n-\n 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+\t\treturn NULL;\n \twhile (*p && *p != '\\n') {\n \t\tfor (eol = p + 1; *eol && *eol != '\\n'; eol++)\n \t\t\t; /* do nothing */\n@@ -128,30 +92,6 @@ static char *get_encoding(const char *message)\n \treturn NULL;\n }\n \n-static struct lock_file msg_file;\n-static int msg_fd;\n-\n-static void add_to_msg(const char *string)\n-{\n-\tint len = strlen(string);\n-\tif (write_in_full(msg_fd, string, len) < 0)\n-\t\tdie_errno (\"Could not write to MERGE_MSG\");\n-}\n-\n-static void add_message_to_msg(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\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n-\n-\tp += 2;\n-\tadd_to_msg(p);\n-\treturn;\n-}\n-\n static void set_author_ident_env(const char *message)\n {\n \tconst char *p = message;\n@@ -214,7 +154,7 @@ static char *help_msg(const unsigned char *sha1)\n \t       \"mark the corrected paths with 'git add <paths>' \"\n \t       \"or 'git rm <paths>' and commit the result.\");\n \n-\tif (action == CHERRY_PICK) {\n+\tif (!(flags & PICK_REVERSE)) {\n \t\tsprintf(helpbuf + strlen(helpbuf),\n \t\t\t\"\\nWhen commiting, use the option \"\n \t\t\t\"'-c %s' to retain authorship and message.\",\n@@ -223,187 +163,68 @@ static char *help_msg(const unsigned char *sha1)\n \treturn helpbuf;\n }\n \n-static struct tree *empty_tree(void)\n+static void write_message(struct strbuf *msgbuf, const char *filename)\n {\n-\tstruct tree *tree = xcalloc(1, sizeof(struct tree));\n-\n-\ttree->object.parsed = 1;\n-\ttree->object.type = OBJ_TREE;\n-\tpretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);\n-\treturn tree;\n+\tstruct lock_file msg_file;\n+\tint msg_fd;\n+\tmsg_fd = hold_lock_file_for_update(&msg_file, filename,\n+\t\t\t\t\t   LOCK_DIE_ON_ERROR);\n+\tif (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)\n+\t\tdie_errno(\"Could not write to %s.\", filename);\n+\tstrbuf_release(msgbuf);\n+\tif (commit_lock_file(&msg_file) < 0)\n+\t\tdie(\"Error wrapping up %s\", filename);\n }\n \n static int revert_or_cherry_pick(int argc, const char **argv)\n {\n-\tunsigned char head[20];\n-\tstruct commit *base, *next, *parent;\n-\tint i, index_fd, clean;\n-\tchar *oneline, *reencoded_message = NULL;\n-\tconst char *message, *encoding;\n-\tchar *defmsg = git_pathdup(\"MERGE_MSG\");\n-\tstruct merge_options o;\n-\tstruct tree *result, *next_tree, *base_tree, *head_tree;\n-\tstatic struct lock_file index_lock;\n+\tconst char *me;\n+\tstruct strbuf msgbuf;\n+\tchar *reencoded_message = NULL;\n+\tconst char *encoding;\n+\tint failed;\n \n \tgit_config(git_default_config, NULL);\n-\tme = action == REVERT ? \"revert\" : \"cherry-pick\";\n+\tme = flags & PICK_REVERSE ? \"revert\" : \"cherry-pick\";\n \tsetenv(GIT_REFLOG_ACTION, me, 0);\n \tparse_args(argc, argv);\n \n-\t/* this is copied from the shell script, but it's never triggered... */\n-\tif (action == REVERT && !no_replay)\n-\t\tdie(\"revert is incompatible with replay\");\n-\n \tif (read_cache() < 0)\n \t\tdie(\"git %s: failed to read the index\", me);\n-\tif (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-\t\t * that represents the \"current\" state for merge-recursive\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} else {\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: cannot %s\", me);\n-\t}\n-\tdiscard_cache();\n-\n-\tindex_fd = hold_locked_index(&index_lock, 1);\n+\tif (!no_commit && index_differs_from(\"HEAD\", 0))\n+\t\tdie (\"Dirty index: cannot %s\", me);\n \n-\tif (!commit->parents) {\n-\t\tif (action == REVERT)\n-\t\t\tdie (\"Cannot revert a root commit\");\n-\t\tparent = NULL;\n-\t}\n-\telse if (commit->parents->next) {\n-\t\t/* Reverting or cherry-picking a merge commit */\n-\t\tint cnt;\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-\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\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-\telse\n-\t\tparent = commit->parents->item;\n-\n-\tif (!(message = commit->buffer))\n-\t\tdie (\"Cannot get commit message for %s\",\n+\tif (!commit->buffer)\n+\t\treturn error(\"Cannot get commit message for %s\",\n \t\t\t\tsha1_to_hex(commit->object.sha1));\n-\n-\tif (parent && parse_commit(parent) < 0)\n-\t\tdie(\"%s: cannot parse parent commit %s\",\n-\t\t    me, sha1_to_hex(parent->object.sha1));\n-\n-\t/*\n-\t * \"commit\" is an existing commit.  We would want to apply\n-\t * the difference it introduces since its first parent \"prev\"\n-\t * on top of the current HEAD if we are cherry-pick.  Or the\n-\t * reverse of it if we are revert.\n-\t */\n-\n-\tmsg_fd = hold_lock_file_for_update(&msg_file, defmsg,\n-\t\t\t\t\t   LOCK_DIE_ON_ERROR);\n-\n-\tencoding = get_encoding(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-\tif ((reencoded_message = reencode_string(message,\n+\tif ((reencoded_message = reencode_string(commit->buffer,\n \t\t\t\t\tgit_commit_encoding, encoding)))\n-\t\tmessage = reencoded_message;\n-\n-\toneline = get_oneline(message);\n-\n-\tif (action == REVERT) {\n-\t\tchar *oneline_body = strchr(oneline, ' ');\n+\t\tcommit->buffer = reencoded_message;\n \n-\t\tbase = commit;\n-\t\tnext = parent;\n-\t\tadd_to_msg(\"Revert \\\"\");\n-\t\tadd_to_msg(oneline_body + 1);\n-\t\tadd_to_msg(\"\\\"\\n\\nThis reverts commit \");\n-\t\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n-\n-\t\tif (commit->parents->next) {\n-\t\t\tadd_to_msg(\", reversing\\nchanges made to \");\n-\t\t\tadd_to_msg(sha1_to_hex(parent->object.sha1));\n-\t\t}\n-\t\tadd_to_msg(\".\\n\");\n-\t} else {\n-\t\tbase = parent;\n-\t\tnext = commit;\n-\t\tset_author_ident_env(message);\n-\t\tadd_message_to_msg(message);\n-\t\tif (no_replay) {\n-\t\t\tadd_to_msg(\"(cherry picked from commit \");\n-\t\t\tadd_to_msg(sha1_to_hex(commit->object.sha1));\n-\t\t\tadd_to_msg(\")\\n\");\n-\t\t}\n-\t}\n-\n-\tread_cache();\n-\tinit_merge_options(&o);\n-\to.branch1 = \"HEAD\";\n-\to.branch2 = oneline;\n-\n-\thead_tree = parse_tree_indirect(head);\n-\tnext_tree = next ? next->tree : empty_tree();\n-\tbase_tree = base ? base->tree : empty_tree();\n-\n-\tclean = merge_trees(&o,\n-\t\t\t    head_tree,\n-\t\t\t    next_tree, base_tree, &result);\n-\n-\tif (active_cache_changed &&\n-\t    (write_cache(index_fd, active_cache, active_nr) ||\n-\t     commit_locked_index(&index_lock)))\n-\t\tdie(\"%s: Unable to write new index file\", me);\n-\trollback_lock_file(&index_lock);\n-\n-\tif (!clean) {\n-\t\tadd_to_msg(\"\\nConflicts:\\n\\n\");\n-\t\tfor (i = 0; i < active_nr;) {\n-\t\t\tstruct cache_entry *ce = active_cache[i++];\n-\t\t\tif (ce_stage(ce)) {\n-\t\t\t\tadd_to_msg(\"\\t\");\n-\t\t\t\tadd_to_msg(ce->name);\n-\t\t\t\tadd_to_msg(\"\\n\");\n-\t\t\t\twhile (i < active_nr && !strcmp(ce->name,\n-\t\t\t\t\t\tactive_cache[i]->name))\n-\t\t\t\t\ti++;\n-\t\t\t}\n-\t\t}\n-\t\tif (commit_lock_file(&msg_file) < 0)\n-\t\t\tdie (\"Error wrapping up %s\", defmsg);\n+\tfailed = pick_commit(commit, mainline, flags, &msgbuf);\n+\tif (failed < 0) {\n+\t\texit(1);\n+\t} else if (failed > 0) {\n \t\tfprintf(stderr, \"Automatic %s failed.%s\\n\",\n \t\t\tme, help_msg(commit->object.sha1));\n+\t\twrite_message(&msgbuf, git_path(\"MERGE_MSG\"));\n \t\trerere();\n \t\texit(1);\n \t}\n-\tif (commit_lock_file(&msg_file) < 0)\n-\t\tdie (\"Error wrapping up %s\", defmsg);\n+\tif (!(flags & PICK_REVERSE))\n+\t\tset_author_ident_env(commit->buffer);\n+\tfree(reencoded_message);\n+\n \tfprintf(stderr, \"Finished one %s.\\n\", me);\n \n+\twrite_message(&msgbuf, git_path(\"MERGE_MSG\"));\n+\n \t/*\n-\t *\n \t * If we are cherry-pick, and if the merge did not result in\n \t * hand-editing, we will hit this commit and inherit the original\n \t * author date and name.\n@@ -421,14 +242,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\t\targs[i++] = \"-s\";\n \t\tif (!edit) {\n \t\t\targs[i++] = \"-F\";\n-\t\t\targs[i++] = defmsg;\n+\t\t\targs[i++] = git_path(\"MERGE_MSG\");\n \t\t}\n \t\targs[i] = NULL;\n \t\treturn execv_git_cmd(args);\n \t}\n-\tfree(reencoded_message);\n-\tfree(defmsg);\n-\n \treturn 0;\n }\n \n@@ -436,14 +254,12 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n {\n \tif (isatty(0))\n \t\tedit = 1;\n-\tno_replay = 1;\n-\taction = REVERT;\n+\tflags = PICK_REVERSE | PICK_ADD_NOTE;\n \treturn revert_or_cherry_pick(argc, argv);\n }\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n-\tno_replay = 0;\n-\taction = CHERRY_PICK;\n+\tflags = 0;\n \treturn revert_or_cherry_pick(argc, argv);\n }\ndiff --git a/pick.c b/pick.c\nnew file mode 100644\nindex 0000000..bb04c68\n--- /dev/null\n+++ b/pick.c\n@@ -0,0 +1,218 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"run-command.h\"\n+#include \"cache-tree.h\"\n+#include \"pick.h\"\n+#include \"merge-recursive.h\"\n+\n+static struct commit *commit;\n+\n+static char *get_oneline(const char *message)\n+{\n+\tchar *result;\n+\tconst char *p = message, *abbrev, *eol;\n+\tint abbrev_len, oneline_len;\n+\n+\tif (!p)\n+\t\treturn NULL;\n+\twhile (*p && (*p != '\\n' || p[1] != '\\n'))\n+\t\tp++;\n+\n+\tif (*p) {\n+\t\tp += 2;\n+\t\tfor (eol = p + 1; *eol && *eol != '\\n'; eol++)\n+\t\t\t; /* do nothing */\n+\t} else\n+\t\teol = p;\n+\tabbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);\n+\tabbrev_len = strlen(abbrev);\n+\toneline_len = eol - p;\n+\tresult = xmalloc(abbrev_len + 5 + oneline_len);\n+\tmemcpy(result, abbrev, abbrev_len);\n+\tmemcpy(result + abbrev_len, \"... \", 4);\n+\tmemcpy(result + abbrev_len + 4, p, oneline_len);\n+\tresult[abbrev_len + 4 + oneline_len] = '\\0';\n+\treturn result;\n+}\n+\n+static void add_message_to_msg(struct strbuf *msg, 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(msg, sha1_to_hex(commit->object.sha1));\n+\n+\tp += 2;\n+\tstrbuf_addstr(msg, p);\n+\treturn;\n+}\n+\n+static struct tree *empty_tree(void)\n+{\n+\tstruct tree *tree = xcalloc(1, sizeof(struct tree));\n+\n+\ttree->object.parsed = 1;\n+\ttree->object.type = OBJ_TREE;\n+\tpretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);\n+\treturn tree;\n+}\n+\n+/*\n+ * Pick changes introduced by \"commit\" argument into current working\n+ * tree and index.\n+ *\n+ * It starts from the current index (not HEAD), and allow the effect\n+ * of one commit replayed (either forward or backward) to that state,\n+ * leaving the result in the index.\n+ *\n+ * You do not have to start from a commit, so you can replay many commits\n+ * to the index in sequence without commiting in between to squash multiple\n+ * steps if you wanted to.\n+ *\n+ * Return 0 on success.\n+ * Return negative value on error before picking,\n+ * and a positive value after picking,\n+ * and return 1 if and only if a conflict occurs but no other error.\n+ */\n+int pick_commit(struct commit *pick_commit, int mainline, int flags,\n+\t\tstruct strbuf *msg)\n+{\n+\tunsigned char head[20];\n+\tstruct commit *base, *next, *parent;\n+\tint i, index_fd, clean;\n+\tint ret = 0;\n+\tchar *oneline;\n+\tconst char *message;\n+\tstruct merge_options o;\n+\tstruct tree *result, *next_tree, *base_tree, *head_tree;\n+\tstatic struct lock_file index_lock;\n+\n+\tstrbuf_init(msg, 0);\n+\tcommit = pick_commit;\n+\n+\t/*\n+\t * Let's compute the tree that represents the \"current\" state\n+\t * for merge-recursive to work on.\n+\t */\n+\tif (write_cache_as_tree(head, 0, NULL))\n+\t\treturn error(\"Your index file is unmerged.\");\n+\tdiscard_cache();\n+\n+\tindex_fd = hold_locked_index(&index_lock, 0);\n+\tif (index_fd < 0)\n+\t\treturn error(\"Unable to create locked index: %s\",\n+\t\t\t     strerror(errno));\n+\n+\tif (!commit->parents) {\n+\t\tif (flags & PICK_REVERSE)\n+\t\t\treturn error(\"Cannot revert a root commit\");\n+\t\tparent = NULL;\n+\t}\n+\telse if (commit->parents->next) {\n+\t\t/* Reverting or cherry-picking a merge commit */\n+\t\tint cnt;\n+\t\tstruct commit_list *p;\n+\n+\t\tif (!mainline)\n+\t\t\treturn error(\"Commit %s is a merge but no mainline was given.\",\n+\t\t\t\t     sha1_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\treturn error(\"Commit %s does not have parent %d\",\n+\t\t\t\t     sha1_to_hex(commit->object.sha1),\n+\t\t\t\t     mainline);\n+\t\tparent = p->item;\n+\t} else if (0 < mainline)\n+\t\treturn error(\"Mainline was specified but commit %s is not a merge.\",\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\telse\n+\t\tparent = commit->parents->item;\n+\n+\tif (!(message = commit->buffer))\n+\t\treturn error(\"Cannot get commit message for %s\",\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\n+\tif (parent && parse_commit(parent) < 0)\n+\t\treturn error(\"Cannot parse parent commit %s\",\n+\t\t\t     sha1_to_hex(parent->object.sha1));\n+\n+\toneline = get_oneline(message);\n+\n+\tif (flags & PICK_REVERSE) {\n+\t\tchar *oneline_body = strchr(oneline, ' ');\n+\n+\t\tbase = commit;\n+\t\tnext = parent;\n+\t\tstrbuf_addstr(msg, \"Revert \\\"\");\n+\t\tstrbuf_addstr(msg, oneline_body + 1);\n+\t\tstrbuf_addstr(msg, \"\\\"\\n\\nThis reverts commit \");\n+\t\tstrbuf_addstr(msg, sha1_to_hex(commit->object.sha1));\n+\n+\t\tif (commit->parents->next) {\n+\t\t\tstrbuf_addstr(msg, \", reversing\\nchanges made to \");\n+\t\t\tstrbuf_addstr(msg, sha1_to_hex(parent->object.sha1));\n+\t\t}\n+\t\tstrbuf_addstr(msg, \".\\n\");\n+\t} else {\n+\t\tbase = parent;\n+\t\tnext = commit;\n+\t\tadd_message_to_msg(msg, message);\n+\t\tif (flags & PICK_ADD_NOTE) {\n+\t\t\tstrbuf_addstr(msg, \"(cherry picked from commit \");\n+\t\t\tstrbuf_addstr(msg, sha1_to_hex(commit->object.sha1));\n+\t\t\tstrbuf_addstr(msg, \")\\n\");\n+\t\t}\n+\t}\n+\n+\tread_cache();\n+\tinit_merge_options(&o);\n+\to.branch1 = \"HEAD\";\n+\to.branch2 = oneline;\n+\n+\thead_tree = parse_tree_indirect(head);\n+\tnext_tree = next ? next->tree : empty_tree();\n+\tbase_tree = base ? base->tree : empty_tree();\n+\n+\tclean = merge_trees(&o,\n+\t\t\t    head_tree,\n+\t\t\t    next_tree, base_tree, &result);\n+\n+\tif (active_cache_changed &&\n+\t    (write_cache(index_fd, active_cache, active_nr) ||\n+\t     commit_locked_index(&index_lock))) {\n+\t\terror(\"Unable to write new index file\");\n+\t\treturn 2;\n+\t}\n+\trollback_lock_file(&index_lock);\n+\n+\tif (!clean) {\n+\t\tstrbuf_addstr(msg, \"\\nConflicts:\\n\\n\");\n+\t\tfor (i = 0; i < active_nr;) {\n+\t\t\tstruct cache_entry *ce = active_cache[i++];\n+\t\t\tif (ce_stage(ce)) {\n+\t\t\t\tstrbuf_addstr(msg, \"\\t\");\n+\t\t\t\tstrbuf_addstr(msg, ce->name);\n+\t\t\t\tstrbuf_addstr(msg, \"\\n\");\n+\t\t\t\twhile (i < active_nr && !strcmp(ce->name,\n+\t\t\t\t\t\tactive_cache[i]->name))\n+\t\t\t\t\ti++;\n+\t\t\t}\n+\t\t}\n+\t\tret = 1;\n+\t}\n+\tfree(oneline);\n+\n+\tdiscard_cache();\n+\tif (read_cache() < 0) {\n+\t\terror(\"Cannot read the index\");\n+\t\treturn 2;\n+\t}\n+\n+\treturn ret;\n+}\ndiff --git a/pick.h b/pick.h\nnew file mode 100644\nindex 0000000..7a74ad8\n--- /dev/null\n+++ b/pick.h\n@@ -0,0 +1,13 @@\n+#ifndef PICK_H\n+#define PICK_H\n+\n+#include \"commit.h\"\n+\n+/* Pick flags: */\n+#define PICK_REVERSE   1 /* pick the reverse changes (\"revert\") */\n+#define PICK_ADD_NOTE  2 /* add note about original commit (unless conflict) */\n+/* We don't need a PICK_QUIET. This is done by\n+ *\tsetenv(\"GIT_MERGE_VERBOSITY\", \"0\", 1); */\n+extern int pick_commit(struct commit *commit, int mainline, int flags, struct strbuf *msg);\n+\n+#endif\n-- \n1.6.4.271.ge010d\n"},{"id":"121971","messageId":"20090828044746.4307.53125.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 12/15] pick: libify \"pick_help_msg()\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:42Z","receivedAt":"2009-08-28T04:47:42Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This function gives an help message when pick or revert failed.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-revert.c |   23 +----------------------\n pick.c           |   22 ++++++++++++++++++++++\n pick.h           |    1 +\n 3 files changed, 24 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin-revert.c b/builtin-revert.c\nindex 4797ac5..e5250bd 100644\n--- a/builtin-revert.c\n+++ b/builtin-revert.c\n@@ -142,27 +142,6 @@ static void set_author_ident_env(const char *message)\n \t\t\tsha1_to_hex(commit->object.sha1));\n }\n \n-static char *help_msg(const unsigned char *sha1)\n-{\n-\tstatic char helpbuf[1024];\n-\tchar *msg = getenv(\"GIT_CHERRY_PICK_HELP\");\n-\n-\tif (msg)\n-\t\treturn msg;\n-\n-\tstrcpy(helpbuf, \"  After resolving the conflicts,\\n\"\n-\t       \"mark the corrected paths with 'git add <paths>' \"\n-\t       \"or 'git rm <paths>' and commit the result.\");\n-\n-\tif (!(flags & PICK_REVERSE)) {\n-\t\tsprintf(helpbuf + strlen(helpbuf),\n-\t\t\t\"\\nWhen commiting, use the option \"\n-\t\t\t\"'-c %s' to retain authorship and message.\",\n-\t\t\tfind_unique_abbrev(sha1, DEFAULT_ABBREV));\n-\t}\n-\treturn helpbuf;\n-}\n-\n static void write_message(struct strbuf *msgbuf, const char *filename)\n {\n \tstruct lock_file msg_file;\n@@ -211,7 +190,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t\texit(1);\n \t} else if (failed > 0) {\n \t\tfprintf(stderr, \"Automatic %s failed.%s\\n\",\n-\t\t\tme, help_msg(commit->object.sha1));\n+\t\t\tme, pick_help_msg(commit->object.sha1, flags));\n \t\twrite_message(&msgbuf, git_path(\"MERGE_MSG\"));\n \t\trerere();\n \t\texit(1);\ndiff --git a/pick.c b/pick.c\nindex bb04c68..e1242f6 100644\n--- a/pick.c\n+++ b/pick.c\n@@ -216,3 +216,25 @@ int pick_commit(struct commit *pick_commit, int mainline, int flags,\n \n \treturn ret;\n }\n+\n+char *pick_help_msg(const unsigned char *sha1, int flags)\n+{\n+\tstatic char helpbuf[1024];\n+\tchar *msg = getenv(\"GIT_CHERRY_PICK_HELP\");\n+\n+\tif (msg)\n+\t\treturn msg;\n+\n+\tstrcpy(helpbuf, \"  After resolving the conflicts,\\n\"\n+\t       \"mark the corrected paths with 'git add <paths>' \"\n+\t       \"or 'git rm <paths>' and commit the result.\");\n+\n+\tif (!(flags & PICK_REVERSE)) {\n+\t\tsprintf(helpbuf + strlen(helpbuf),\n+\t\t\t\"\\nWhen commiting, use the option \"\n+\t\t\t\"'-c %s' to retain authorship and message.\",\n+\t\t\tfind_unique_abbrev(sha1, DEFAULT_ABBREV));\n+\t}\n+\treturn helpbuf;\n+}\n+\ndiff --git a/pick.h b/pick.h\nindex 7a74ad8..115541a 100644\n--- a/pick.h\n+++ b/pick.h\n@@ -9,5 +9,6 @@\n /* We don't need a PICK_QUIET. This is done by\n  *\tsetenv(\"GIT_MERGE_VERBOSITY\", \"0\", 1); */\n extern int pick_commit(struct commit *commit, int mainline, int flags, struct strbuf *msg);\n+extern char *pick_help_msg(const unsigned char *sha1, int flags);\n \n #endif\n-- \n1.6.4.271.ge010d\n"},{"id":"121968","messageId":"20090828044746.4307.51257.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 13/15] sequencer: add \"do_commit()\" and related functions working on \"next_commit\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:43Z","receivedAt":"2009-08-28T04:47:43Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThis patch adds \"struct commit_info\", the \"next_commit\" static variable\nand the following functions:\n\n        - do_commit()\n        - set_author_info()\n        - set_message_source()\n        - set_pick_subject()\n        - write_commit_summary_into()\n\nThis makes it possible to prepare and perform a commit (without forking\nand execing \"git commit\"), and this will be used in a following patch to\nperform a cherry-pick.\n\nAll these functions work on the \"struct commit_info next_commit\" global.\nThis variable will eventually be saved between the different calls to\n\"git rebase\" (or \"git sequencer\"). So we cannot easily reuse existing\nfunctions from \"builtin-commit.c\" or \"builtin-commit-tree.c\" and we need\nthese special functions.\n\nThis patch adds some code that comes from the sequencer GSoC project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nCompared to the sequencer project, the only change is that \"mark\"\nrelated (3 lines long) code has been removed from do_commit().\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-sequencer--helper.c |  213 +++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 213 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex 71a7fef..014e4ce 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -5,17 +5,55 @@\n #include \"refs.h\"\n #include \"diff.h\"\n #include \"unpack-trees.h\"\n+#include \"string-list.h\"\n+#include \"pick.h\"\n+#include \"rerere.h\"\n+#include \"dir.h\"\n+#include \"cache-tree.h\"\n+#include \"utf8.h\"\n \n #define SEQ_DIR \"rebase-merge\"\n \n #define PATCH_FILE\tgit_path(SEQ_DIR \"/patch\")\n+#define MERGE_MSG\tgit_path(\"MERGE_MSG\")\n+#define SQUASH_MSG\tgit_path(\"SQUASH_MSG\")\n+\n+/**********************************************************************\n+ * Data structures\n+ */\n+\n+struct user_info {\n+\tconst char *name;\n+\tconst char *mail;\n+\tconst char *time; /* \"<timestamp> <timezone>\" */\n+};\n+\n+struct commit_info {\n+\tstruct user_info author; /* author info */\n+\tstruct user_info committer; /* not used, but for easy extendability */\n+\tconst char *encoding; /* encoding */\n+\tchar *subject; /* basically the first line of the summary */\n+\tstruct strbuf summary; /* the commit message */\n+\tchar *source; /* source of the commit message, either\n+\t\t       * \"message\", \"merge\", \"squash\" or a commit SHA1 */\n+\tchar *patch; /* a patch */\n+\tstruct string_list parents; /* list of parents' hex'ed sha1 ids */\n+};\n+\n+/**********************************************************************\n+ * Global variables\n+ */\n \n static char *reflog;\n \n+static int squash_count = 0;\n+\n static int allow_dirty = 0, verbosity = 1, advice = 1;\n \n static unsigned char head_sha1[20];\n \n+static struct commit_info next_commit;\n+\n static const char * const git_sequencer_helper_usage[] = {\n \t\"git sequencer--helper --make-patch <commit>\",\n \t\"git sequencer--helper --reset-hard <commit> <reflog-msg> \"\n@@ -25,6 +63,10 @@ static const char * const git_sequencer_helper_usage[] = {\n \tNULL\n };\n \n+/**********************************************************************\n+ * Sequencer functions\n+ */\n+\n static int parse_and_init_tree_desc(const unsigned char *sha1,\n \t\t\t\t    struct tree_desc *desc)\n {\n@@ -162,6 +204,157 @@ static void make_patch(struct commit *commit)\n \tfree(args);\n }\n \n+/* Commit current index with information next_commit onto parent_sha1. */\n+static int do_commit(unsigned char *parent_sha1)\n+{\n+\tint failed;\n+\tunsigned char tree_sha1[20];\n+\tunsigned char commit_sha1[20];\n+\tstruct strbuf sbuf;\n+\tconst char *reencoded = NULL;\n+\n+\tif (squash_count) {\n+\t\tsquash_count = 0;\n+\t\tif (file_exists(SQUASH_MSG))\n+\t\t\tunlink(SQUASH_MSG);\n+\t}\n+\n+\tif (!index_differs_from(\"HEAD\", 0) &&\n+\t    !next_commit.parents.nr)\n+\t\treturn error(\"No changes! Do you really want an empty commit?\");\n+\n+\tif (!next_commit.author.name || !next_commit.author.mail)\n+\t\treturn error(\"Internal error: Author information not set properly.\");\n+\n+\tif (write_cache_as_tree(tree_sha1, 0, NULL))\n+\t\treturn 1;\n+\n+\tif (!next_commit.encoding)\n+\t\tnext_commit.encoding = xstrdup(\"utf-8\");\n+\tif (!git_commit_encoding)\n+\t\tgit_commit_encoding = \"utf-8\";\n+\n+\tstrbuf_init(&sbuf, 8192); /* should avoid reallocs for the headers */\n+\tstrbuf_addf(&sbuf, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tif (parent_sha1)\n+\t\tstrbuf_addf(&sbuf, \"parent %s\\n\", sha1_to_hex(parent_sha1));\n+\tif (next_commit.parents.nr) {\n+\t\tint i;\n+\t\tfor (i = 0; i < next_commit.parents.nr; ++i)\n+\t\t\tstrbuf_addf(&sbuf, \"parent %s\\n\",\n+\t\t\t\t\tnext_commit.parents.items[i].string);\n+\t}\n+\tif (!next_commit.author.time) {\n+\t\tchar time[50];\n+\t\tdatestamp(time, sizeof(time));\n+\t\tnext_commit.author.time = xstrdup(time);\n+\t}\n+\n+\tstripspace(&next_commit.summary, 1);\n+\n+\t/* if encodings differ, reencode whole buffer */\n+\tif (strcasecmp(git_commit_encoding, next_commit.encoding)) {\n+\t\tif ((reencoded = reencode_string(next_commit.author.name,\n+\t\t\t\tgit_commit_encoding, next_commit.encoding))) {\n+\t\t\tfree((void *)next_commit.author.name);\n+\t\t\tnext_commit.author.name = reencoded;\n+\t\t}\n+\t\tif ((reencoded = reencode_string(next_commit.summary.buf,\n+\t\t\t\tgit_commit_encoding, next_commit.encoding))) {\n+\t\t\tstrbuf_reset(&next_commit.summary);\n+\t\t\tstrbuf_addstr(&next_commit.summary, reencoded);\n+\t\t}\n+\t}\n+\tstrbuf_addf(&sbuf, \"author %s <%s> %s\\n\", next_commit.author.name,\n+\t\t\tnext_commit.author.mail, next_commit.author.time);\n+\tstrbuf_addf(&sbuf, \"committer %s\\n\", git_committer_info(0));\n+\tif (!is_encoding_utf8(git_commit_encoding))\n+\t\tstrbuf_addf(&sbuf, \"encoding %s\\n\", git_commit_encoding);\n+\tstrbuf_addch(&sbuf, '\\n');\n+\tstrbuf_addbuf(&sbuf, &next_commit.summary);\n+\tif (sbuf.buf[sbuf.len-1] != '\\n')\n+\t\tstrbuf_addch(&sbuf, '\\n');\n+\n+\tfailed = write_sha1_file(sbuf.buf, sbuf.len, commit_type, commit_sha1);\n+\tstrbuf_release(&sbuf);\n+\tif (failed)\n+\t\treturn 1;\n+\n+\tif (verbosity > 1)\n+\t\tprintf(\"Created %scommit %s\\n\",\n+\t\t\tparent_sha1 || next_commit.parents.nr ? \"\" : \"initial \",\n+\t\t\tsha1_to_hex(commit_sha1));\n+\n+\tif (update_ref(reflog, \"HEAD\", commit_sha1, NULL, 0, 0))\n+\t\treturn error(\"Could not update HEAD to %s.\",\n+\t\t\t\t\t\tsha1_to_hex(commit_sha1));\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Fill next_commit.author according to ident.\n+ * Ident may have one of the following forms:\n+ * \t\"name <e-mail> timestamp timezone\\n...\"\n+ * \t\"name <e-mail> timestamp timezone\"\n+ * \t\"name <e-mail>\"\n+ */\n+static void set_author_info(const char *ident)\n+{\n+\tconst char *tmp1 = strstr(ident, \" <\");\n+\tconst char *tmp2;\n+\tchar *data;\n+\tif (!tmp1)\n+\t\treturn;\n+\ttmp2 = strstr(tmp1+2, \">\");\n+\tif (!tmp2)\n+\t\treturn;\n+\tif (tmp2[1] != 0 && tmp2[1] != ' ')\n+\t\treturn;\n+\n+\tdata = xmalloc(strlen(ident)); /* a trivial upper bound */\n+\n+\tsnprintf(data, tmp1-ident+1, \"%s\", ident);\n+\tnext_commit.author.name = xstrdup(data);\n+\tsnprintf(data, tmp2-tmp1-1, \"%s\", tmp1+2);\n+\tnext_commit.author.mail = xstrdup(data);\n+\n+\tif (tmp2[1] == 0) {\n+\t\tfree(data);\n+\t\treturn;\n+\t}\n+\n+\ttmp1 = strpbrk(tmp2+2, \"\\r\\n\");\n+\tif (!tmp1)\n+\t\ttmp1 = tmp2 + strlen(tmp2);\n+\n+\tsnprintf(data, tmp1-tmp2-1, \"%s\", tmp2+2);\n+\tnext_commit.author.time = xstrdup(data);\n+\tfree(data);\n+}\n+\n+static void set_message_source(const char *source)\n+{\n+\tif (next_commit.source)\n+\t\tfree(next_commit.source);\n+\tnext_commit.source = xstrdup(source);\n+}\n+\n+/* Set subject, an information for the case of conflict */\n+static void set_pick_subject(const char *hex, struct commit *commit)\n+{\n+\tconst char *tmp = strstr(commit->buffer, \"\\n\\n\");\n+\tif (tmp) {\n+\t\tconst char *eol;\n+\t\tint len = strlen(hex);\n+\t\ttmp += 2;\n+\t\teol = strchrnul(tmp, '\\n');\n+\t\tnext_commit.subject = xmalloc(eol - tmp + len + 5);\n+\t\tsnprintf(next_commit.subject, eol - tmp + len + 5, \"%s... %s\",\n+\t\t\t\t\t\t\t\thex, tmp);\n+\t}\n+}\n+\n /* Return a commit object of \"arg\" */\n static struct commit *get_commit(const char *arg)\n {\n@@ -198,6 +391,26 @@ static int set_verbosity(int verbose)\n \treturn 0;\n }\n \n+static int write_commit_summary_into(const char *filename)\n+{\n+\tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n+\tint fd = hold_lock_file_for_update(lock, filename, 0);\n+\tif (fd < 0)\n+\t\treturn error(\"Unable to create '%s.lock': %s\", filename,\n+\t\t\t\t\t\t\tstrerror(errno));\n+\tif (write_in_full(fd, next_commit.summary.buf,\n+\t\t\t      next_commit.summary.len) < 0)\n+\t\treturn error(\"Could not write to %s: %s\",\n+\t\t\t\t\t\tfilename, strerror(errno));\n+\tif (commit_lock_file(lock) < 0)\n+\t\treturn error(\"Error wrapping up %s\", filename);\n+\treturn 0;\n+}\n+\n+/**********************************************************************\n+ * Builtin sequencer helper functions\n+ */\n+\n /* v should be \"\" or \"t\" or \"\\d\" */\n static int parse_verbosity(const char *v)\n {\n-- \n1.6.4.271.ge010d\n"},{"id":"121966","messageId":"20090828044746.4307.16842.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 14/15] sequencer: add \"--cherry-pick\" option to \"git sequencer--helper\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:44Z","receivedAt":"2009-08-28T04:47:44Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Stephan Beyer <s-beyer@gmx.net>\n\nThis patch implements a new \"do_cherry_pick()\" function using the\npreviously libified \"pick_commit()\" function and some other functions\n(like \"do_commit()\") previously added to \"builtin-sequencer--helper.c\".\n\nLike in the \"do_commit()\" function, the \"next_commit\" global is\nused to store commit related information, so we cannot easily reuse\nexisting code to perform what \"do_cherry_pick()\" does.\n\nThis patch adds some code that comes from the sequencer GSoC project:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nMost of the code from do_cherry_pick() is taken from the\nsequencer insn_pick_act() function.\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-sequencer--helper.c |   70 +++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 61 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c\nindex 014e4ce..291ba18 100644\n--- a/builtin-sequencer--helper.c\n+++ b/builtin-sequencer--helper.c\n@@ -60,6 +60,8 @@ static const char * const git_sequencer_helper_usage[] = {\n \t\t\"<verbosity> [<allow-dirty>]\",\n \t\"git sequencer--helper --fast-forward <commit> <reflog-msg> \"\n \t\t\"<verbosity> [<allow-dirty>]\",\n+\t\"git sequencer--helper --cherry-pick <commit> <reflog-msg> \"\n+\t\t\"<verbosity> [<do-not-commit>]\",\n \tNULL\n };\n \n@@ -287,7 +289,7 @@ static int do_commit(unsigned char *parent_sha1)\n \n \tif (update_ref(reflog, \"HEAD\", commit_sha1, NULL, 0, 0))\n \t\treturn error(\"Could not update HEAD to %s.\",\n-\t\t\t\t\t\tsha1_to_hex(commit_sha1));\n+\t\t\t     sha1_to_hex(commit_sha1));\n \n \treturn 0;\n }\n@@ -407,6 +409,46 @@ static int write_commit_summary_into(const char *filename)\n \treturn 0;\n }\n \n+static int do_cherry_pick(char *cp_commit, int no_commit)\n+{\n+\tstruct commit *commit;\n+\tint failed;\n+\tconst char *author;\n+\n+\tif (get_sha1(\"HEAD\", head_sha1))\n+\t\treturn error(\"You do not have a valid HEAD.\");\n+\n+\tcommit = get_commit(cp_commit);\n+\tif (!commit)\n+\t\treturn 1;\n+\n+\tset_pick_subject(cp_commit, commit);\n+\n+\tfailed = pick_commit(commit, 0, 0, &next_commit.summary);\n+\n+\tset_message_source(sha1_to_hex(commit->object.sha1));\n+\tauthor = strstr(commit->buffer, \"\\nauthor \");\n+\tif (author)\n+\t\tset_author_info(author + 8);\n+\n+\t/* We do not want extra Conflicts: lines on cherry-pick,\n+\t   so just take the old commit message. */\n+\tif (failed) {\n+\t\tstrbuf_setlen(&next_commit.summary, 0);\n+\t\tstrbuf_addstr(&next_commit.summary,\n+\t\t\t      strstr(commit->buffer, \"\\n\\n\") + 2);\n+\t\trerere();\n+\t\tmake_patch(commit);\n+\t\twrite_commit_summary_into(MERGE_MSG);\n+\t\treturn error(pick_help_msg(commit->object.sha1, 0));\n+\t}\n+\n+\tif (!no_commit && do_commit(head_sha1))\n+\t\treturn error(\"Could not commit.\");\n+\n+\treturn 0;\n+}\n+\n /**********************************************************************\n  * Builtin sequencer helper functions\n  */\n@@ -435,6 +477,7 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \tchar *patch_commit = NULL;\n \tchar *reset_commit = NULL;\n \tchar *ff_commit = NULL;\n+\tchar *cp_commit = NULL;\n \tstruct option options[] = {\n \t\tOPT_STRING(0, \"make-patch\", &patch_commit, \"commit\",\n \t\t\t   \"create a patch from commit\"),\n@@ -442,6 +485,8 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\t\t   \"reset to commit\"),\n \t\tOPT_STRING(0, \"fast-forward\", &ff_commit, \"commit\",\n \t\t\t   \"fast forward to commit\"),\n+\t\tOPT_STRING(0, \"cherry-pick\", &cp_commit, \"commit\",\n+\t\t\t   \"cherry pick commit\"),\n \t\tOPT_END()\n \t};\n \n@@ -458,19 +503,15 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\treturn 0;\n \t}\n \n-\tif (ff_commit || reset_commit) {\n+\tif (cp_commit || ff_commit || reset_commit) {\n \t\tunsigned char sha1[20];\n-\t\tchar *commit = ff_commit ? ff_commit : reset_commit;\n+\t\tchar *commit;\n+\t\tint opt_arg = 0;\n \n \t\tif (argc != 2 && argc != 3)\n \t\t\tusage_with_options(git_sequencer_helper_usage,\n \t\t\t\t\t   options);\n \n-\t\tif (get_sha1(commit, sha1)) {\n-\t\t\terror(\"Could not find '%s'\", commit);\n-\t\t\treturn 1;\n-\t\t}\n-\n \t\treflog = (char *)argv[0];\n \n \t\tif (parse_verbosity(argv[1])) {\n@@ -479,7 +520,18 @@ int cmd_sequencer__helper(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\tif (argc == 3 && *argv[2] && strcmp(argv[2], \"0\"))\n-\t\t\tallow_dirty = 1;\n+\t\t\topt_arg = 1;\n+\n+\t\tif (cp_commit)\n+\t\t\treturn do_cherry_pick(cp_commit, opt_arg);\n+\n+\t\tallow_dirty = opt_arg;\n+\n+\t\tcommit = ff_commit ? ff_commit : reset_commit;\n+\t\tif (get_sha1(commit, sha1)) {\n+\t\t\terror(\"Could not find '%s'\", commit);\n+\t\t\treturn 1;\n+\t\t}\n \n \t\tif (ff_commit)\n \t\t\treturn do_fast_forward(sha1);\n-- \n1.6.4.271.ge010d\n"},{"id":"121965","messageId":"20090828044746.4307.98469.chriscool@tuxfamily.org","threadId":"20768","inReplyTo":"20090828043913.4307.34708.chriscool@tuxfamily.org","subject":"[PATCH v4 15/15] rebase -i: use \"git sequencer--helper --cherry-pick\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2009-08-28T04:47:45Z","receivedAt":"2009-08-28T04:47:45Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"instead of \"git cherry-pick\", as this will make it easier to\nport \"git-rebase--interactive.sh\" to C.\n\nThis is because we will be able to use the \"do_cherry_pick()\" added\nby a previous patch.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n git-rebase--interactive.sh |   11 ++++++++---\n 1 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 7651fd6..349ca50 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -147,7 +147,8 @@ pick_one () {\n \t\tpick_one_preserving_merges \"$@\" && return\n \tif test ! -z \"$REBASE_ROOT\"\n \tthen\n-\t\toutput git cherry-pick \"$@\"\n+\t\tgit sequencer--helper --cherry-pick $sha1 \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" $no_ff\n \t\treturn\n \tfi\n \tparent_sha1=$(git rev-parse --verify $sha1^) ||\n@@ -157,7 +158,8 @@ pick_one () {\n \t\tgit sequencer--helper --fast-forward $sha1 \\\n \t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\"\n \telse\n-\t\toutput git cherry-pick \"$@\"\n+\t\tgit sequencer--helper --cherry-pick $sha1 \\\n+\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" $no_ff\n \tfi\n }\n \n@@ -269,7 +271,10 @@ pick_one_preserving_merges () {\n \t\t\tfi\n \t\t\t;;\n \t\t*)\n-\t\t\toutput git cherry-pick \"$@\" ||\n+\t\t\tno_commit=\n+\t\t\ttest \"a$1\" = \"a-n\" && no_commit=t\n+\t\t\tgit sequencer--helper --cherry-pick $sha1 \\\n+\t\t\t\t\"$GIT_REFLOG_ACTION\" \"$VERBOSE\" $no_commit ||\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\n \t\t\t;;\n \t\tesac\n-- \n1.6.4.271.ge010d\n"},{"id":"121976","messageId":"loom.20090828T080732-795@post.gmane.org","threadId":"20768","inReplyTo":"20090828044746.4307.88742.chriscool@tuxfamily.org","subject":"Re: [PATCH v4 04/15] sequencer: add \"reset_almost_hard()\" and related functions","fromName":"Eric Raible","fromEmail":"raible@gmail.com","sentAt":"2009-08-28T06:08:54Z","receivedAt":"2009-08-28T06:08:54Z","isPatch":true,"sender":{"key":"raible@gmail.com","avatar":null},"body":"Christian Couder <chriscool <at> tuxfamily.org> writes:\n\n> \"reset_almost_hard()\" can be used to do a \"git reset --hard\". It\n> should be faster as it calls \"unpack_trees()\" directly, and it can\n> optionnaly preserve changes in the work tree if the \"allow_dirty\"\n> global is set. Preserving changes in the work tree can be usefull\n> if for example you want to get rid of the last commit but keep\n> your current not yet commited work.\n\ns/optionnaly/optionally/\ns/usefull/useful/\n"}]}