{"thread":{"id":"22540","subject":"[PATCH 0/9] add --ff option to cherry-pick","startedAt":"2010-02-05T23:11:02Z","lastAt":"2010-02-28T22:22:54Z","messageCount":20,"participants":["Christian Couder","Junio C Hamano","Paolo Bonzini"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"133744","messageId":"20100205231028.3689.12228.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":null,"subject":"[PATCH 0/9] add --ff option to cherry-pick","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:02Z","receivedAt":"2010-02-05T23:11:02Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Changes since the previous series are the following:\n\n- added some tests in a new patch\n- added some documentation in a new patch\n- added a patch to use the new \"reset\" function in builtin-merge.c\n- made --ff incompatible with --edit -x and --signoff too, thanks to Paolo\n- improved the first patch with suggestions from Stephen Boyd, thanks\n- made a \"struct lock_file\" static to initialize it in the first patch\n- improved commit messages\n\nChristian Couder (8):\n  reset: refactor updating heads into a static function\n  reset: refactor reseting in its own function\n  reset: make reset function non static and declare it in \"reset.h\"\n  revert: add --ff option to allow fast forward when cherry-picking\n  cherry-pick: add tests for new --ff option\n  Documentation: describe new cherry-pick --ff option\n  rebase -i: use new --ff cherry-pick option\n  merge: use new \"reset\" function instead of running \"git read-tree\"\n\nStephan Beyer (1):\n  revert: libify cherry-pick and revert functionnality\n\n Documentation/git-cherry-pick.txt |    6 +-\n Makefile                          |    2 +\n builtin-merge.c                   |   31 ++---\n builtin-reset.c                   |  175 ++++++++++++----------\n builtin-revert.c                  |  303 +++++++++----------------------------\n git-rebase--interactive.sh        |   15 +--\n pick.c                            |  218 ++++++++++++++++++++++++++\n pick.h                            |   13 ++\n reset.h                           |   10 ++\n t/t3506-cherry-pick-ff.sh         |   38 +++++\n 10 files changed, 471 insertions(+), 340 deletions(-)\n create mode 100644 pick.c\n create mode 100644 pick.h\n create mode 100644 reset.h\n create mode 100755 t/t3506-cherry-pick-ff.sh\n"},{"id":"133747","messageId":"20100205231112.3689.23742.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 1/9] revert: libify cherry-pick and revert functionnality","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:03Z","receivedAt":"2010-02-05T23:11:03Z","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 d624530..71901c8 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -458,6 +458,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@@ -550,6 +551,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 8ac86f0..7488d4c 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,26 +31,24 @@ 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 static int allow_rerere_auto;\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@@ -79,42 +73,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@@ -130,30 +94,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@@ -216,7 +156,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@@ -225,14 +165,17 @@ 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+\tstatic struct 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 NORETURN void die_dirty_index(const char *me)\n@@ -250,175 +193,53 @@ static NORETURN void die_dirty_index(const char *me)\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(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(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-\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+\t\tcommit->buffer = reencoded_message;\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(allow_rerere_auto);\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@@ -436,14 +257,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@@ -451,14 +269,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..1e1628a\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, ' ') + 1;\n+\n+\t\tbase = commit;\n+\t\tnext = parent;\n+\t\tstrbuf_addstr(msg, \"Revert \\\"\");\n+\t\tstrbuf_addstr(msg, oneline_body);\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_addch(msg, '\\t');\n+\t\t\t\tstrbuf_addstr(msg, ce->name);\n+\t\t\t\tstrbuf_addch(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.6.1.557.g77031\n"},{"id":"133751","messageId":"20100205231112.3689.95767.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 2/9] reset: refactor updating heads into a static function","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:04Z","receivedAt":"2010-02-05T23:11:04Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-reset.c |   43 +++++++++++++++++++++++++++----------------\n 1 files changed, 27 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 0f5022e..3569695 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -211,15 +211,38 @@ static void prepend_reflog_action(const char *action, char *buf, size_t size)\n \t\twarning(\"Reflog action message too long: %.*s...\", 50, buf);\n }\n \n+/*\n+ * Any resets update HEAD to the head being switched to,\n+ * saving the previous head in ORIG_HEAD before.\n+ */\n+static int update_heads(unsigned char *sha1)\n+{\n+\tunsigned char sha1_orig[20], *orig = NULL,\n+\t\tsha1_old_orig[20], *old_orig = NULL;\n+\tchar msg[1024];\n+\n+\tif (!get_sha1(\"ORIG_HEAD\", sha1_old_orig))\n+\t\told_orig = sha1_old_orig;\n+\tif (!get_sha1(\"HEAD\", sha1_orig)) {\n+\t\torig = sha1_orig;\n+\t\tprepend_reflog_action(\"updating ORIG_HEAD\", msg, sizeof(msg));\n+\t\tupdate_ref(msg, \"ORIG_HEAD\", orig, old_orig, 0, MSG_ON_ERR);\n+\t}\n+\telse if (old_orig)\n+\t\tdelete_ref(\"ORIG_HEAD\", old_orig, 0);\n+\tprepend_reflog_action(\"updating HEAD\", msg, sizeof(msg));\n+\n+\treturn update_ref(msg, \"HEAD\", sha1, orig, 0, MSG_ON_ERR);\n+}\n+\n int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n \tint i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;\n \tint patch_mode = 0;\n \tconst char *rev = \"HEAD\";\n-\tunsigned char sha1[20], *orig = NULL, sha1_orig[20],\n-\t\t\t\t*old_orig = NULL, sha1_old_orig[20];\n+\tunsigned char sha1[20];\n \tstruct commit *commit;\n-\tchar *reflog_action, msg[1024];\n+\tchar *reflog_action;\n \tconst struct option options[] = {\n \t\tOPT__QUIET(&quiet),\n \t\tOPT_SET_INT(0, \"mixed\", &reset_type,\n@@ -321,19 +344,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \telse if (reset_index_file(sha1, reset_type, quiet))\n \t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \n-\t/* Any resets update HEAD to the head being switched to,\n-\t * saving the previous head in ORIG_HEAD before. */\n-\tif (!get_sha1(\"ORIG_HEAD\", sha1_old_orig))\n-\t\told_orig = sha1_old_orig;\n-\tif (!get_sha1(\"HEAD\", sha1_orig)) {\n-\t\torig = sha1_orig;\n-\t\tprepend_reflog_action(\"updating ORIG_HEAD\", msg, sizeof(msg));\n-\t\tupdate_ref(msg, \"ORIG_HEAD\", orig, old_orig, 0, MSG_ON_ERR);\n-\t}\n-\telse if (old_orig)\n-\t\tdelete_ref(\"ORIG_HEAD\", old_orig, 0);\n-\tprepend_reflog_action(\"updating HEAD\", msg, sizeof(msg));\n-\tupdate_ref_status = update_ref(msg, \"HEAD\", sha1, orig, 0, MSG_ON_ERR);\n+\tupdate_ref_status = update_heads(sha1);\n \n \tswitch (reset_type) {\n \tcase HARD:\n-- \n1.6.6.1.557.g77031\n"},{"id":"133752","messageId":"20100205231112.3689.94900.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 3/9] reset: refactor reseting in its own function","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:05Z","receivedAt":"2010-02-05T23:11:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This splits the reseting logic away from the argument parsing.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-reset.c |  138 +++++++++++++++++++++++++++++-------------------------\n 1 files changed, 74 insertions(+), 64 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 3569695..bf97931 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -235,68 +235,13 @@ static int update_heads(unsigned char *sha1)\n \treturn update_ref(msg, \"HEAD\", sha1, orig, 0, MSG_ON_ERR);\n }\n \n-int cmd_reset(int argc, const char **argv, const char *prefix)\n+static int reset(const char *rev, const char *prefix,\n+\t\t int reset_type, int quiet, int patch_mode,\n+\t\t int argc, const char **argv)\n {\n-\tint i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;\n-\tint patch_mode = 0;\n-\tconst char *rev = \"HEAD\";\n-\tunsigned char sha1[20];\n \tstruct commit *commit;\n-\tchar *reflog_action;\n-\tconst struct option options[] = {\n-\t\tOPT__QUIET(&quiet),\n-\t\tOPT_SET_INT(0, \"mixed\", &reset_type,\n-\t\t\t\t\t\t\"reset HEAD and index\", MIXED),\n-\t\tOPT_SET_INT(0, \"soft\", &reset_type, \"reset only HEAD\", SOFT),\n-\t\tOPT_SET_INT(0, \"hard\", &reset_type,\n-\t\t\t\t\"reset HEAD, index and working tree\", HARD),\n-\t\tOPT_SET_INT(0, \"merge\", &reset_type,\n-\t\t\t\t\"reset HEAD, index and working tree\", MERGE),\n-\t\tOPT_BOOLEAN('p', \"patch\", &patch_mode, \"select hunks interactively\"),\n-\t\tOPT_END()\n-\t};\n-\n-\tgit_config(git_default_config, NULL);\n-\n-\targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n-\t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n-\treflog_action = args_to_str(argv);\n-\tsetenv(\"GIT_REFLOG_ACTION\", reflog_action, 0);\n-\n-\t/*\n-\t * Possible arguments are:\n-\t *\n-\t * git reset [-opts] <rev> <paths>...\n-\t * git reset [-opts] <rev> -- <paths>...\n-\t * git reset [-opts] -- <paths>...\n-\t * git reset [-opts] <paths>...\n-\t *\n-\t * At this point, argv[i] points immediately after [-opts].\n-\t */\n-\n-\tif (i < argc) {\n-\t\tif (!strcmp(argv[i], \"--\")) {\n-\t\t\ti++; /* reset to HEAD, possibly with paths */\n-\t\t} else if (i + 1 < argc && !strcmp(argv[i+1], \"--\")) {\n-\t\t\trev = argv[i];\n-\t\t\ti += 2;\n-\t\t}\n-\t\t/*\n-\t\t * Otherwise, argv[i] could be either <rev> or <paths> and\n-\t\t * has to be unambiguous.\n-\t\t */\n-\t\telse if (!get_sha1(argv[i], sha1)) {\n-\t\t\t/*\n-\t\t\t * Ok, argv[i] looks like a rev; it should not\n-\t\t\t * be a filename.\n-\t\t\t */\n-\t\t\tverify_non_filename(prefix, argv[i]);\n-\t\t\trev = argv[i++];\n-\t\t} else {\n-\t\t\t/* Otherwise we treat this as a filename */\n-\t\t\tverify_filename(prefix, argv[i]);\n-\t\t}\n-\t}\n+\tunsigned char sha1[20];\n+\tint update_ref_status;\n \n \tif (get_sha1(rev, sha1))\n \t\tdie(\"Failed to resolve '%s' as a valid ref.\", rev);\n@@ -309,19 +254,19 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (patch_mode) {\n \t\tif (reset_type != NONE)\n \t\t\tdie(\"--patch is incompatible with --{hard,mixed,soft}\");\n-\t\treturn interactive_reset(rev, argv + i, prefix);\n+\t\treturn interactive_reset(rev, argv, prefix);\n \t}\n \n \t/* git reset tree [--] paths... can be used to\n \t * load chosen paths from the tree into the index without\n \t * affecting the working tree nor HEAD. */\n-\tif (i < argc) {\n+\tif (argc > 0) {\n \t\tif (reset_type == MIXED)\n \t\t\twarning(\"--mixed option is deprecated with paths.\");\n \t\telse if (reset_type != NONE)\n \t\t\tdie(\"Cannot do %s reset with paths.\",\n \t\t\t\t\treset_type_names[reset_type]);\n-\t\treturn read_from_tree(prefix, argv + i, sha1,\n+\t\treturn read_from_tree(prefix, argv, sha1,\n \t\t\t\tquiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);\n \t}\n \tif (reset_type == NONE)\n@@ -361,7 +306,72 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \n \tremove_branch_state();\n \n+\treturn update_ref_status;\n+}\n+\n+int cmd_reset(int argc, const char **argv, const char *prefix)\n+{\n+\tint i = 0, reset_type = NONE, quiet = 0;\n+\tint patch_mode = 0;\n+\tconst char *rev = \"HEAD\";\n+\tunsigned char sha1[20];\n+\tchar *reflog_action;\n+\tconst struct option options[] = {\n+\t\tOPT__QUIET(&quiet),\n+\t\tOPT_SET_INT(0, \"mixed\", &reset_type,\n+\t\t\t\t\t\t\"reset HEAD and index\", MIXED),\n+\t\tOPT_SET_INT(0, \"soft\", &reset_type, \"reset only HEAD\", SOFT),\n+\t\tOPT_SET_INT(0, \"hard\", &reset_type,\n+\t\t\t\t\"reset HEAD, index and working tree\", HARD),\n+\t\tOPT_SET_INT(0, \"merge\", &reset_type,\n+\t\t\t\t\"reset HEAD, index and working tree\", MERGE),\n+\t\tOPT_BOOLEAN('p', \"patch\", &patch_mode, \"select hunks interactively\"),\n+\t\tOPT_END()\n+\t};\n+\n+\tgit_config(git_default_config, NULL);\n+\n+\targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n+\t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n+\treflog_action = args_to_str(argv);\n+\tsetenv(\"GIT_REFLOG_ACTION\", reflog_action, 0);\n \tfree(reflog_action);\n \n-\treturn update_ref_status;\n+\t/*\n+\t * Possible arguments are:\n+\t *\n+\t * git reset [-opts] <rev> <paths>...\n+\t * git reset [-opts] <rev> -- <paths>...\n+\t * git reset [-opts] -- <paths>...\n+\t * git reset [-opts] <paths>...\n+\t *\n+\t * At this point, argv[i] points immediately after [-opts].\n+\t */\n+\n+\tif (i < argc) {\n+\t\tif (!strcmp(argv[i], \"--\")) {\n+\t\t\ti++; /* reset to HEAD, possibly with paths */\n+\t\t} else if (i + 1 < argc && !strcmp(argv[i+1], \"--\")) {\n+\t\t\trev = argv[i];\n+\t\t\ti += 2;\n+\t\t}\n+\t\t/*\n+\t\t * Otherwise, argv[i] could be either <rev> or <paths> and\n+\t\t * has to be unambiguous.\n+\t\t */\n+\t\telse if (!get_sha1(argv[i], sha1)) {\n+\t\t\t/*\n+\t\t\t * Ok, argv[i] looks like a rev; it should not\n+\t\t\t * be a filename.\n+\t\t\t */\n+\t\t\tverify_non_filename(prefix, argv[i]);\n+\t\t\trev = argv[i++];\n+\t\t} else {\n+\t\t\t/* Otherwise we treat this as a filename */\n+\t\t\tverify_filename(prefix, argv[i]);\n+\t\t}\n+\t}\n+\n+\treturn reset(rev, prefix, reset_type, quiet, patch_mode,\n+\t\t     argc - i, argv + i);\n }\n-- \n1.6.6.1.557.g77031\n"},{"id":"133745","messageId":"20100205231112.3689.64300.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 4/9] reset: make reset function non static and declare it in \"reset.h\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:06Z","receivedAt":"2010-02-05T23:11:06Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-reset.c |    8 ++++----\n reset.h         |   10 ++++++++++\n 2 files changed, 14 insertions(+), 4 deletions(-)\n create mode 100644 reset.h\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex bf97931..b004f9a 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 \"reset.h\"\n \n static const char * const git_reset_usage[] = {\n \t\"git reset [--mixed | --soft | --hard | --merge] [-q] [<commit>]\",\n@@ -27,7 +28,6 @@ static const char * const git_reset_usage[] = {\n \tNULL\n };\n \n-enum reset_type { MIXED, SOFT, HARD, MERGE, NONE };\n static const char *reset_type_names[] = { \"mixed\", \"soft\", \"hard\", \"merge\", NULL };\n \n static char *args_to_str(const char **argv)\n@@ -235,9 +235,9 @@ static int update_heads(unsigned char *sha1)\n \treturn update_ref(msg, \"HEAD\", sha1, orig, 0, MSG_ON_ERR);\n }\n \n-static int reset(const char *rev, const char *prefix,\n-\t\t int reset_type, int quiet, int patch_mode,\n-\t\t int argc, const char **argv)\n+int reset(const char *rev, const char *prefix,\n+\t  int reset_type, int quiet, int patch_mode,\n+\t  int argc, const char **argv)\n {\n \tstruct commit *commit;\n \tunsigned char sha1[20];\ndiff --git a/reset.h b/reset.h\nnew file mode 100644\nindex 0000000..c8497e4\n--- /dev/null\n+++ b/reset.h\n@@ -0,0 +1,10 @@\n+#ifndef RESET_H\n+#define RESET_H\n+\n+enum reset_type { MIXED, SOFT, HARD, MERGE, NONE };\n+\n+int reset(const char *rev, const char *prefix,\n+\t  int reset_type, int quiet, int patch_mode,\n+\t  int argc, const char **argv);\n+\n+#endif\n-- \n1.6.6.1.557.g77031\n"},{"id":"133746","messageId":"20100205231112.3689.67634.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:07Z","receivedAt":"2010-02-05T23:11:07Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"As \"git merge\" fast forwards if possible, it seems sensible to\nhave such a feature for \"git cherry-pick\" too, especially as it\ncould be used in git-rebase--interactive.sh.\n\nMaybe this option could be made the default in the long run, with\nanother --no-ff option to disable this default behavior, but that\ncould make some scripts backward incompatible and/or that would\nrequire testing if some GIT_AUTHOR_* environment variables are\nset. So we don't do that for now.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-revert.c |   35 +++++++++++++++++++++++++++++++----\n 1 files changed, 31 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-revert.c b/builtin-revert.c\nindex 7488d4c..b78926f 100644\n--- a/builtin-revert.c\n+++ b/builtin-revert.c\n@@ -9,6 +9,7 @@\n #include \"revision.h\"\n #include \"rerere.h\"\n #include \"pick.h\"\n+#include \"reset.h\"\n \n /*\n  * This implements the builtins revert and cherry-pick.\n@@ -31,13 +32,19 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, no_commit, mainline, signoff;\n+static int edit, no_commit, mainline, signoff, ff_ok;\n static int flags;\n static struct commit *commit;\n static int allow_rerere_auto;\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n+static void die_if_ff_incompatible(int opt_set, const char *opt_name)\n+{\n+\tif (opt_set)\n+\t\tdie (\"options --ff and %s are incompatible\", opt_name);\n+}\n+\n static void parse_args(int argc, const char **argv)\n {\n \tconst char * const * usage_str =\n@@ -51,6 +58,7 @@ static void parse_args(int argc, const char **argv)\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_BOOLEAN(0, \"ff\", &ff_ok, \"allow fast forward\"),\n \t\tOPT_INTEGER('m', \"mainline\", &mainline, \"parent number\"),\n \t\tOPT_RERERE_AUTOUPDATE(&allow_rerere_auto),\n \t\tOPT_END(),\n@@ -71,6 +79,12 @@ static void parse_args(int argc, const char **argv)\n \t}\n \tif (commit->object.type != OBJ_COMMIT)\n \t\tdie (\"'%s' does not point to a commit\", arg);\n+\tif (ff_ok) {\n+\t\tdie_if_ff_incompatible(edit, \"--edit\");\n+\t\tdie_if_ff_incompatible(flags & PICK_ADD_NOTE, \"-x\");\n+\t\tdie_if_ff_incompatible(no_commit, \"--no-commit\");\n+\t\tdie_if_ff_incompatible(signoff, \"--signoff\");\n+\t}\n }\n \n static char *get_encoding(const char *message)\n@@ -191,7 +205,7 @@ static NORETURN void die_dirty_index(const char *me)\n \t}\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, const char *prefix)\n {\n \tconst char *me;\n \tstruct strbuf msgbuf;\n@@ -209,6 +223,19 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \tif (!no_commit && index_differs_from(\"HEAD\", 0))\n \t\tdie_dirty_index(me);\n \n+\tif (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {\n+\t\tunsigned char head_sha1[20];\n+\t\tif (get_sha1(\"HEAD\", head_sha1))\n+\t\t\tdie(\"You do not have a valid HEAD.\");\n+\t\tif (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {\n+\t\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n+\t\t\tint res = reset(hex, prefix, HARD, 0, 0, 0, NULL);\n+\t\t\tif (!res)\n+\t\t\t\tfprintf(stderr, \"Fast-forward to %s\\n\", hex);\n+\t\t\treturn res;\n+\t\t}\n+\t}\n+\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@@ -270,11 +297,11 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \tif (isatty(0))\n \t\tedit = 1;\n \tflags = PICK_REVERSE | PICK_ADD_NOTE;\n-\treturn revert_or_cherry_pick(argc, argv);\n+\treturn revert_or_cherry_pick(argc, argv, prefix);\n }\n \n int cmd_cherry_pick(int argc, const char **argv, const char *prefix)\n {\n \tflags = 0;\n-\treturn revert_or_cherry_pick(argc, argv);\n+\treturn revert_or_cherry_pick(argc, argv, prefix);\n }\n-- \n1.6.6.1.557.g77031\n"},{"id":"133748","messageId":"20100205231112.3689.86986.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 6/9] cherry-pick: add tests for new --ff option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:08Z","receivedAt":"2010-02-05T23:11:08Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t3506-cherry-pick-ff.sh |   38 ++++++++++++++++++++++++++++++++++++++\n 1 files changed, 38 insertions(+), 0 deletions(-)\n create mode 100755 t/t3506-cherry-pick-ff.sh\n\ndiff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh\nnew file mode 100755\nindex 0000000..21c0729\n--- /dev/null\n+++ b/t/t3506-cherry-pick-ff.sh\n@@ -0,0 +1,38 @@\n+#!/bin/sh\n+\n+test_description='test cherry-picking with --ff option'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\techo first > file1 &&\n+\tgit add file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"first\" &&\n+\tgit tag first &&\n+\n+\tgit checkout -b other &&\n+\techo second >> file1 &&\n+\tgit add file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"second\" &&\n+\tgit tag second\n+'\n+\n+test_expect_success 'cherry-pick using --ff fast forwards' '\n+\tgit checkout master &&\n+\tgit reset --hard first &&\n+\ttest_tick &&\n+\tgit cherry-pick --ff second &&\n+\ttest \"$(git rev-parse --verify HEAD)\" = \"$(git rev-parse --verify second)\"\n+'\n+\n+test_expect_success 'cherry-pick not using --ff does not fast forwards' '\n+\tgit checkout master &&\n+\tgit reset --hard first &&\n+\ttest_tick &&\n+\tgit cherry-pick second &&\n+\ttest \"$(git rev-parse --verify HEAD)\" != \"$(git rev-parse --verify second)\"\n+'\n+\n+test_done\n-- \n1.6.6.1.557.g77031\n"},{"id":"133749","messageId":"20100205231112.3689.48965.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 7/9] Documentation: describe new cherry-pick --ff option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:09Z","receivedAt":"2010-02-05T23:11:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-cherry-pick.txt |    6 +++++-\n 1 files changed, 5 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 78f4714..d71607a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit\n \n SYNOPSIS\n --------\n-'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] <commit>\n+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>\n \n DESCRIPTION\n -----------\n@@ -70,6 +70,10 @@ effect to your index in a row.\n --signoff::\n \tAdd Signed-off-by line at the end of the commit message.\n \n+--ff::\n+\tIf the current HEAD is the same as the parent of the\n+\tcherry-pick'ed commit, then a fast forward to this commit will\n+\tbe performed.\n \n Author\n ------\n-- \n1.6.6.1.557.g77031\n"},{"id":"133750","messageId":"20100205231112.3689.91599.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 8/9] rebase -i: use new --ff cherry-pick option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:10Z","receivedAt":"2010-02-05T23:11:10Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This simplifies rebase -i a little bit.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n git-rebase--interactive.sh |   15 +++------------\n 1 files changed, 3 insertions(+), 12 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c2f6089..6b224a6 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -222,8 +222,8 @@ do_with_author () {\n }\n \n pick_one () {\n-\tno_ff=\n-\tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n+\tff=--ff\n+\tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$REWRITTEN\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n@@ -232,16 +232,7 @@ pick_one () {\n \t\toutput git cherry-pick \"$@\"\n \t\treturn\n \tfi\n-\tparent_sha1=$(git rev-parse --verify $sha1^) ||\n-\t\tdie \"Could not get the parent of $sha1\"\n-\tcurrent_sha1=$(git rev-parse --verify HEAD)\n-\tif test -z \"$no_ff\" && test \"$current_sha1\" = \"$parent_sha1\"\n-\tthen\n-\t\toutput git reset --hard $sha1\n-\t\toutput warn Fast-forward to $(git rev-parse --short $sha1)\n-\telse\n-\t\toutput git cherry-pick \"$@\"\n-\tfi\n+\toutput git cherry-pick $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n-- \n1.6.6.1.557.g77031\n"},{"id":"133753","messageId":"20100205231112.3689.34673.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"[PATCH 9/9] merge: use new \"reset\" function instead of running \"git read-tree\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-05T23:11:11Z","receivedAt":"2010-02-05T23:11:11Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This simplifies \"git merge\" code and make it more efficient in some\ncases.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-merge.c |   31 +++++++++++--------------------\n 1 files changed, 11 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex 3aaec7b..de2343a 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -25,6 +25,7 @@\n #include \"help.h\"\n #include \"merge-recursive.h\"\n #include \"resolve-undo.h\"\n+#include \"reset.h\"\n \n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -231,24 +232,14 @@ static void save_state(void)\n \t\tdie(\"not a valid object: %s\", buffer.buf);\n }\n \n-static void reset_hard(unsigned const char *sha1, int verbose)\n+static void reset_hard(const char *prefix, unsigned const char *sha1, int verbose)\n {\n-\tint i = 0;\n-\tconst char *args[6];\n-\n-\targs[i++] = \"read-tree\";\n-\tif (verbose)\n-\t\targs[i++] = \"-v\";\n-\targs[i++] = \"--reset\";\n-\targs[i++] = \"-u\";\n-\targs[i++] = sha1_to_hex(sha1);\n-\targs[i] = NULL;\n-\n-\tif (run_command_v_opt(args, RUN_GIT_CMD))\n-\t\tdie(\"read-tree failed\");\n+\tint res = reset(sha1_to_hex(sha1), prefix, HARD, !verbose, 0, 0, NULL);\n+\tif (res)\n+\t\tdie(\"hard reset failed\");\n }\n \n-static void restore_state(void)\n+static void restore_state(const char *prefix)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *args[] = { \"stash\", \"apply\", NULL, NULL };\n@@ -256,7 +247,7 @@ static void restore_state(void)\n \tif (is_null_sha1(stash))\n \t\treturn;\n \n-\treset_hard(head, 1);\n+\treset_hard(prefix, head, 1);\n \n \targs[2] = sha1_to_hex(stash);\n \n@@ -970,7 +961,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"%s - not something we can merge\", argv[0]);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n \t\t\t\tDIE_ON_ERR);\n-\t\treset_hard(remote_head->sha1, 0);\n+\t\treset_hard(prefix, remote_head->sha1, 0);\n \t\treturn 0;\n \t} else {\n \t\tstruct strbuf msg = STRBUF_INIT;\n@@ -1167,7 +1158,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tint ret;\n \t\tif (i) {\n \t\t\tprintf(\"Rewinding the tree to pristine...\\n\");\n-\t\t\trestore_state();\n+\t\t\trestore_state(prefix);\n \t\t}\n \t\tif (use_strategies_nr != 1)\n \t\t\tprintf(\"Trying merge strategy %s...\\n\",\n@@ -1228,7 +1219,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t * it up.\n \t */\n \tif (!best_strategy) {\n-\t\trestore_state();\n+\t\trestore_state(prefix);\n \t\tif (use_strategies_nr > 1)\n \t\t\tfprintf(stderr,\n \t\t\t\t\"No merge strategy handled the merge.\\n\");\n@@ -1240,7 +1231,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t; /* We already have its result in the working tree. */\n \telse {\n \t\tprintf(\"Rewinding the tree to pristine...\\n\");\n-\t\trestore_state();\n+\t\trestore_state(prefix);\n \t\tprintf(\"Using the %s to prepare resolving by hand.\\n\",\n \t\t\tbest_strategy);\n \t\ttry_merge_strategy(best_strategy, common, head_arg);\n-- \n1.6.6.1.557.g77031\n"},{"id":"133759","messageId":"7vtytvnt5h.fsf@alter.siamese.dyndns.org","threadId":"22540","inReplyTo":"20100205231028.3689.12228.chriscool@tuxfamily.org","subject":"Re: [PATCH 0/9] add --ff option to cherry-pick","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-02-05T23:45:46Z","receivedAt":"2010-02-05T23:45:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> Changes since the previous series are the following:\n\nCould you please briefly describe what good does \"adding -ff option to\ncherry-pick\" do in the first place?\n\nIOW, help reviewers to convince themselves that it is worth allocating a\nblock of time to read through a 9 patch series.  That is what the cover\nletter is for.\n\nThanks.\n"},{"id":"133762","messageId":"7vpr4jnsm9.fsf@alter.siamese.dyndns.org","threadId":"22540","inReplyTo":"20100205231112.3689.67634.chriscool@tuxfamily.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-02-05T23:57:18Z","receivedAt":"2010-02-05T23:57:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> As \"git merge\" fast forwards if possible, it seems sensible to\n> have such a feature for \"git cherry-pick\" too, especially as it\n> could be used in git-rebase--interactive.sh.\n\n\n> +\tif (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {\n> +\t\tunsigned char head_sha1[20];\n> +\t\tif (get_sha1(\"HEAD\", head_sha1))\n> +\t\t\tdie(\"You do not have a valid HEAD.\");\n> +\t\tif (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {\n> +\t\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n\nWith this check, you are saying:\n\n\tIf we are cherry-picking commit $C, and if the current HEAD is\n        the first parent of $C, then just reset to $C instead of running a\n        cherry-pick.\n\nI didn't check if you have access to commit->parents->item->object.sha1 at\nthis point in the codepath, though (e.g. have you parsed \"commit\" yet?).\n\nIf the goal is to make untouched 'pick' in rebase-i to fast forward\nwithout actually running cherry-picking, perhaps it is much cleaner to do\nthis kind of comparison in the caller of cherry-pick (i.e. rebase-i and\nanything that runs cherry-pick)?\n\nThe whole series is titled as if \"cherry-pick --ff\" is the primary goal,\nbut I am puzzled why earlier patches in the series were necessary for this\nchange.\n"},{"id":"133763","messageId":"7vbpg3nsbd.fsf@alter.siamese.dyndns.org","threadId":"22540","inReplyTo":"20100205231112.3689.34673.chriscool@tuxfamily.org","subject":"Re: [PATCH 9/9] merge: use new \"reset\" function instead of running \"git read-tree\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-02-06T00:03:50Z","receivedAt":"2010-02-06T00:03:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> This simplifies \"git merge\" code and make it more efficient in some\n> cases.\n\nI vaguely recall somebody (perhaps it was you) tried to do something like\nthis before to drive unpack_trees() inside the main process, broke the\nprogram rather badly, and then we ended up keeping read-tree invocation\nexternal to the process.  Am I misremembering things?\n\nIf not, could you describe how is this round different from the old one?\n"},{"id":"133765","messageId":"7vzl3nkydj.fsf@alter.siamese.dyndns.org","threadId":"22540","inReplyTo":"7vpr4jnsm9.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-02-06T00:21:12Z","receivedAt":"2010-02-06T00:21:12Z","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> Christian Couder <chriscool@tuxfamily.org> writes:\n>\n>> As \"git merge\" fast forwards if possible, it seems sensible to\n>> have such a feature for \"git cherry-pick\" too, especially as it\n>> could be used in git-rebase--interactive.sh.\n\nOne more thing, in the same part of the code:\n\n>> +\tif (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {\n>> +\t\tunsigned char head_sha1[20];\n>> +\t\tif (get_sha1(\"HEAD\", head_sha1))\n>> +\t\t\tdie(\"You do not have a valid HEAD.\");\n>> +\t\tif (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {\n>> +\t\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n\nIs there a need to check commit->parents->next?\n\nShould this code work the same way if the commit being cherry-picked is a\nmerge?  Should \"-m <parent-num>\" option affect this codepath in any way?\n"},{"id":"133788","messageId":"4B6D38FB.9000307@gnu.org","threadId":"22540","inReplyTo":"20100205231112.3689.67634.chriscool@tuxfamily.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2010-02-06T09:40:11Z","receivedAt":"2010-02-06T09:40:11Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"On 02/06/2010 12:11 AM, Christian Couder wrote:\n> As \"git merge\" fast forwards if possible, it seems sensible to\n> have such a feature for \"git cherry-pick\" too, especially as it\n> could be used in git-rebase--interactive.sh.\n>\n> Maybe this option could be made the default in the long run, with\n> another --no-ff option to disable this default behavior, but that\n> could make some scripts backward incompatible and/or that would\n> require testing if some GIT_AUTHOR_* environment variables are\n> set. So we don't do that for now.\n\nI would still like to have a no-op --no-ff so that scripts that do rely \non that can be future proofed (or also, scripts that do \"git cherry-pick \n$blah -e COMMIT\" could use --no-ff to avoid errors in case $blah \ncontains --ff).\n\nPaolo\n"},{"id":"133806","messageId":"201002061627.23084.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"7vtytvnt5h.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/9] add --ff option to cherry-pick","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-06T15:27:22Z","receivedAt":"2010-02-06T15:27:22Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On samedi 06 février 2010, Junio C Hamano wrote:\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > Changes since the previous series are the following:\n>\n> Could you please briefly describe what good does \"adding -ff option to\n> cherry-pick\" do in the first place?\n\nOk I will do that.\n\nThanks,\nChristian.\n"},{"id":"133807","messageId":"201002061629.05640.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"4B6D38FB.9000307@gnu.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-06T15:29:05Z","receivedAt":"2010-02-06T15:29:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On samedi 06 février 2010, Paolo Bonzini wrote:\n> On 02/06/2010 12:11 AM, Christian Couder wrote:\n> > As \"git merge\" fast forwards if possible, it seems sensible to\n> > have such a feature for \"git cherry-pick\" too, especially as it\n> > could be used in git-rebase--interactive.sh.\n> >\n> > Maybe this option could be made the default in the long run, with\n> > another --no-ff option to disable this default behavior, but that\n> > could make some scripts backward incompatible and/or that would\n> > require testing if some GIT_AUTHOR_* environment variables are\n> > set. So we don't do that for now.\n>\n> I would still like to have a no-op --no-ff so that scripts that do rely\n> on that can be future proofed (or also, scripts that do \"git cherry-pick\n> $blah -e COMMIT\" could use --no-ff to avoid errors in case $blah\n> contains --ff).\n\nOk, I will add a --no-ff option but I think it should be incompatible \nwith --ff rather than overide it.\n\nThanks,\nChristian.\n"},{"id":"133808","messageId":"201002061634.02126.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"7vbpg3nsbd.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 9/9] merge: use new \"reset\" function instead of running \"git read-tree\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-06T15:34:01Z","receivedAt":"2010-02-06T15:34:01Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On samedi 06 février 2010, Junio C Hamano wrote:\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > This simplifies \"git merge\" code and make it more efficient in some\n> > cases.\n>\n> I vaguely recall somebody (perhaps it was you) tried to do something like\n> this before to drive unpack_trees() inside the main process, broke the\n> program rather badly, and then we ended up keeping read-tree invocation\n> external to the process.  Am I misremembering things?\n\nI don't think it was me and I don't recall that, but I don't follow all the \nthreads on the mailing list.\n\nI will search the archive, but any pointer would be very appreciated.\n\nThanks anyway,\nChristian.\n\n> If not, could you describe how is this round different from the old one?\n"},{"id":"133809","messageId":"hkk2jl$ghl$1@ger.gmane.org","threadId":"22540","inReplyTo":"201002061629.05640.chriscool@tuxfamily.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2010-02-06T15:41:43Z","receivedAt":"2010-02-06T15:41:43Z","isPatch":true,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"On 02/06/2010 04:29 PM, Christian Couder wrote:\n> On samedi 06 février 2010, Paolo Bonzini wrote:\n>> On 02/06/2010 12:11 AM, Christian Couder wrote:\n>>> As \"git merge\" fast forwards if possible, it seems sensible to\n>>> have such a feature for \"git cherry-pick\" too, especially as it\n>>> could be used in git-rebase--interactive.sh.\n>>>\n>>> Maybe this option could be made the default in the long run, with\n>>> another --no-ff option to disable this default behavior, but that\n>>> could make some scripts backward incompatible and/or that would\n>>> require testing if some GIT_AUTHOR_* environment variables are\n>>> set. So we don't do that for now.\n>>\n>> I would still like to have a no-op --no-ff so that scripts that do rely\n>> on that can be future proofed (or also, scripts that do \"git cherry-pick\n>> $blah -e COMMIT\" could use --no-ff to avoid errors in case $blah\n>> contains --ff).\n>\n> Ok, I will add a --no-ff option but I think it should be incompatible\n> with --ff rather than overide it.\n\nWhatever it does it should be the same as git merge.\n\nPaolo\n"},{"id":"135909","messageId":"201002282322.54856.chriscool@tuxfamily.org","threadId":"22540","inReplyTo":"7vpr4jnsm9.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-02-28T22:22:54Z","receivedAt":"2010-02-28T22:22:54Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Saturday 06 February 2010 00:57:18 Junio C Hamano wrote:\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > As \"git merge\" fast forwards if possible, it seems sensible to\n> > have such a feature for \"git cherry-pick\" too, especially as it\n> > could be used in git-rebase--interactive.sh.\n> >\n> >\n> > +\tif (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {\n> > +\t\tunsigned char head_sha1[20];\n> > +\t\tif (get_sha1(\"HEAD\", head_sha1))\n> > +\t\t\tdie(\"You do not have a valid HEAD.\");\n> > +\t\tif (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {\n> > +\t\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n> \n> With this check, you are saying:\n> \n> \tIf we are cherry-picking commit $C, and if the current HEAD is\n>         the first parent of $C, then just reset to $C instead of running a\n>         cherry-pick.\n> \n> I didn't check if you have access to commit->parents->item->object.sha1 at\n> this point in the codepath, though (e.g. have you parsed \"commit\" yet?).\n\nYes it is parsed by the call to lookup_commit_reference() in parse_args().\n\n> If the goal is to make untouched 'pick' in rebase-i to fast forward\n> without actually running cherry-picking, perhaps it is much cleaner to do\n> this kind of comparison in the caller of cherry-pick (i.e. rebase-i and\n> anything that runs cherry-pick)?\n\nAt least Daniel Barkalow and Paolo Bonzini have stated before that they would \nfind natural that git cherry-pick itself can fast forward.\n\nThe argument in the commit message is that as \"git merge\" can and does fast \nforward by default it seems strange that \"git cherry-pick\" cannot fast \nforward. It's not just because rebase-i tries to fast forward, as I think it \nis just simpler to fast forward if possible when using cherry-pick by hand.\n\n> The whole series is titled as if \"cherry-pick --ff\" is the primary goal,\n> but I am puzzled why earlier patches in the series were necessary for this\n> change.\n\nEarlier patches are just refactoring and making the needed functions extern to \nmake the implementation of cherry-pick --ff possible and clean.\n\n> One more thing, in the same part of the code:\n> >> +\tif (!(flags & PICK_REVERSE) && ff_ok && commit->parents) {\n> >> +\t\tunsigned char head_sha1[20];\n> >> +\t\tif (get_sha1(\"HEAD\", head_sha1))\n> >> +\t\t\tdie(\"You do not have a valid HEAD.\");\n> >> +\t\tif (!hashcmp(commit->parents->item->object.sha1, head_sha1)) {\n> >> +\t\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n> \n> Is there a need to check commit->parents->next?\n> \n> Should this code work the same way if the commit being cherry-picked is a\n> merge?  Should \"-m <parent-num>\" option affect this codepath in any way?\n\nYeah I had not even checked what happens with merge commits and/or \"-m \n<parent-num>\". The next version of the patch series takes care of that.\n\nThanks,\nChristian.\n"}]}