{"thread":{"id":"22900","subject":"[PATCH v3 3/9] reset: make reset function non static and declare it in \"reset.h\"","startedAt":"2010-03-03T20:11:35Z","lastAt":"2010-03-03T20:11:44Z","messageCount":10,"participants":["Christian Couder"],"isPatch":true,"patchVersion":3,"patchTotal":9},"messages":[{"id":"136124","messageId":"20100303201046.23506.32653.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":null,"subject":"[PATCH v3 0/9] add --ff option to cherry-pick","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:35Z","receivedAt":"2010-03-03T20:11:35Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"The goal of this patch series is to make it possible for \"git cherry-pick\"\nto fast forward instead of creating a new commit if the cherry picked commit\nhas the same parent as the one we are cherry-picking on.\n\nThe change since the previous series is that there is less refactoring\nof builtin/revert.c before introducing the --ff option, so less code churn.\nThis also means that this series should be easier to merge.\n\nChristian Couder (9):\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: refactor checking parent in a check_parent() function\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  cherry-pick: add a no-op --no-ff option to future proof scripts\n  rebase -i: use new --ff cherry-pick option\n\n Documentation/git-cherry-pick.txt |   10 ++-\n builtin/reset.c                   |  178 ++++++++++++++++++++-----------------\n builtin/revert.c                  |   91 ++++++++++++-------\n git-rebase--interactive.sh        |   15 +---\n reset.h                           |   10 ++\n t/t3506-cherry-pick-ff.sh         |  106 ++++++++++++++++++++++\n 6 files changed, 282 insertions(+), 128 deletions(-)\n create mode 100644 reset.h\n create mode 100755 t/t3506-cherry-pick-ff.sh\n"},{"id":"136121","messageId":"20100303201146.23506.60435.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 1/9] reset: refactor updating heads into a static function","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:36Z","receivedAt":"2010-03-03T20:11:36Z","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 |   42 ++++++++++++++++++++++++++----------------\n 1 files changed, 26 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 2c3a69a..7af1cb1 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -229,7 +229,30 @@ static void die_if_unmerged_cache(int reset_type)\n \tif (is_merge() || read_cache() < 0 || unmerged_cache())\n \t\tdie(\"Cannot do a %s reset in the middle of a merge.\",\n \t\t    reset_type_names[reset_type]);\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@@ -237,10 +260,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\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@@ -350,19 +372,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \t}\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.7.0.315.gbc198\n"},{"id":"136125","messageId":"20100303201146.23506.18146.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 2/9] reset: refactor reseting in its own function","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:37Z","receivedAt":"2010-03-03T20:11:37Z","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 |  140 +++++++++++++++++++++++++++++--------------------------\n 1 files changed, 74 insertions(+), 66 deletions(-)\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 7af1cb1..b2239d2 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -255,70 +255,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_SET_INT(0, \"keep\", &reset_type,\n-\t\t\t\t\"reset HEAD but keep local changes\", KEEP),\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@@ -331,19 +274,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@@ -389,7 +332,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.7.0.315.gbc198\n"},{"id":"136120","messageId":"20100303201146.23506.45925.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 3/9] reset: make reset function non static and declare it in \"reset.h\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:38Z","receivedAt":"2010-03-03T20:11:38Z","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 b2239d2..f1d7a5a 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 | --keep] [-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, KEEP, NONE };\n static const char *reset_type_names[] = {\n \t\"mixed\", \"soft\", \"hard\", \"merge\", \"keep\", NULL\n };\n@@ -255,9 +255,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..05d2205\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, KEEP, 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.7.0.315.gbc198\n"},{"id":"136122","messageId":"20100303201146.23506.21157.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 4/9] revert: refactor checking parent in a check_parent() function","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:39Z","receivedAt":"2010-03-03T20:11:39Z","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/revert.c |   62 ++++++++++++++++++++++++++++++-----------------------\n 1 files changed, 35 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex eff5268..a611960 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -244,6 +244,40 @@ static NORETURN void die_dirty_index(const char *me)\n \t}\n }\n \n+static struct commit * check_parent(struct commit *commit, int mainline)\n+{\n+\tif (!commit->parents) {\n+\t\tif (action == REVERT)\n+\t\t\tdie (\"Cannot revert a root commit\");\n+\t\treturn NULL;\n+\t}\n+\n+\tif (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\treturn p->item;\n+\t}\n+\n+\tif (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+\n+\treturn commit->parents->item;\n+}\n+\n static int revert_or_cherry_pick(int argc, const char **argv)\n {\n \tunsigned char head[20];\n@@ -286,33 +320,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \n \tindex_fd = hold_locked_index(&index_lock, 1);\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+\tparent = check_parent(commit, mainline);\n \n \tif (!(message = commit->buffer))\n \t\tdie (\"Cannot get commit message for %s\",\n-- \n1.7.0.315.gbc198\n"},{"id":"136129","messageId":"20100303201146.23506.55469.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 5/9] revert: add --ff option to allow fast forward when cherry-picking","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:40Z","receivedAt":"2010-03-03T20:11:40Z","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 |   32 ++++++++++++++++++++++----------\n 1 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex a611960..4799073 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -13,6 +13,7 @@\n #include \"revision.h\"\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n+#include \"reset.h\"\n \n /*\n  * This implements the builtins revert and cherry-pick.\n@@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, no_replay, no_commit, mainline, signoff;\n+static int edit, no_replay, no_commit, mainline, signoff, ff_ok;\n static enum { REVERT, CHERRY_PICK } action;\n static struct commit *commit;\n static const char *commit_name;\n@@ -57,6 +58,7 @@ static void parse_args(int argc, const char **argv)\n \t\tOPT_BOOLEAN('x', NULL, &no_replay, \"append commit name when cherry-picking\"),\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@@ -278,7 +280,7 @@ static struct commit * check_parent(struct commit *commit, int mainline)\n \treturn commit->parents->item;\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 \tunsigned char head[20];\n \tstruct commit *base, *next, *parent;\n@@ -318,18 +320,28 @@ static int revert_or_cherry_pick(int argc, const char **argv)\n \t}\n \tdiscard_cache();\n \n-\tindex_fd = hold_locked_index(&index_lock, 1);\n-\n \tparent = check_parent(commit, mainline);\n \n-\tif (!(message = commit->buffer))\n-\t\tdie (\"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+\tif (action == CHERRY_PICK && ff_ok &&\n+\t    parent && !hashcmp(parent->object.sha1, head) &&\n+\t    !edit && !no_commit && !no_replay && !signoff) {\n+\t\tchar *hex = sha1_to_hex(commit->object.sha1);\n+\t\tint res = reset(hex, prefix, HARD, 0, 0, 0, NULL);\n+\t\tif (!res)\n+\t\t\tfprintf(stderr, \"Fast-forward to %s\\n\", hex);\n+\t\treturn res;\n+\t}\n+\n+\tif (!(message = commit->buffer))\n+\t\tdie (\"Cannot get commit message for %s\",\n+\t\t     sha1_to_hex(commit->object.sha1));\n+\n+\tindex_fd = hold_locked_index(&index_lock, 1);\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@@ -457,12 +469,12 @@ int cmd_revert(int argc, const char **argv, const char *prefix)\n \t\tedit = 1;\n \tno_replay = 1;\n \taction = REVERT;\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 \tno_replay = 0;\n \taction = CHERRY_PICK;\n-\treturn revert_or_cherry_pick(argc, argv);\n+\treturn revert_or_cherry_pick(argc, argv, prefix);\n }\n-- \n1.7.0.315.gbc198\n"},{"id":"136128","messageId":"20100303201146.23506.57441.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 6/9] cherry-pick: add tests for new --ff option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:41Z","receivedAt":"2010-03-03T20:11:41Z","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 |   98 +++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 98 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..e17ae71\n--- /dev/null\n+++ b/t/t3506-cherry-pick-ff.sh\n@@ -0,0 +1,98 @@\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+#\n+# We setup the following graph:\n+#\n+#\t      B---C\n+#\t     /   /\n+#\tfirst---A\n+#\n+# (This has been taken from t3502-cherry-pick-merge.sh)\n+#\n+test_expect_success 'merge setup' '\n+\tgit checkout master &&\n+\tgit reset --hard first &&\n+\techo new line >A &&\n+\tgit add A &&\n+\ttest_tick &&\n+\tgit commit -m \"add line to A\" A &&\n+\tgit tag A &&\n+\tgit checkout -b side first &&\n+\techo new line >B &&\n+\tgit add B &&\n+\ttest_tick &&\n+\tgit commit -m \"add line to B\" B &&\n+\tgit tag B &&\n+\tgit checkout master &&\n+\tgit merge side &&\n+\tgit tag C &&\n+\tgit checkout -b new A\n+'\n+\n+test_expect_success 'cherry-pick a non-merge with --ff and -m should fail' '\n+\tgit reset --hard A -- &&\n+\ttest_must_fail git cherry-pick --ff -m 1 B &&\n+\tgit diff --exit-code A --\n+'\n+\n+test_expect_success 'cherry pick a merge with --ff but without -m should fail' '\n+\tgit reset --hard A -- &&\n+\ttest_must_fail git cherry-pick --ff C &&\n+\tgit diff --exit-code A --\n+'\n+\n+test_expect_success 'cherry pick with --ff a merge (1)' '\n+\tgit reset --hard A -- &&\n+\tgit cherry-pick --ff -m 1 C &&\n+\tgit diff --exit-code C &&\n+\ttest \"$(git rev-parse --verify HEAD)\" = \"$(git rev-parse --verify C)\"\n+'\n+\n+test_expect_success 'cherry pick with --ff a merge (2)' '\n+\tgit reset --hard B -- &&\n+\tgit cherry-pick --ff -m 2 C &&\n+\tgit diff --exit-code C &&\n+\ttest \"$(git rev-parse --verify HEAD)\" = \"$(git rev-parse --verify C)\"\n+'\n+\n+test_expect_success 'cherry pick a merge relative to nonexistent parent with --ff should fail' '\n+\tgit reset --hard B -- &&\n+\ttest_must_fail git cherry-pick --ff -m 3 C\n+'\n+\n+test_done\n-- \n1.7.0.315.gbc198\n"},{"id":"136127","messageId":"20100303201146.23506.32147.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 7/9] Documentation: describe new cherry-pick --ff option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:42Z","receivedAt":"2010-03-03T20:11:42Z","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.7.0.315.gbc198\n"},{"id":"136123","messageId":"20100303201146.23506.11793.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 8/9] cherry-pick: add a no-op --no-ff option to future proof scripts","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:43Z","receivedAt":"2010-03-03T20:11:43Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"A --ff option to allow \"git cherry-pick\" to fast forward if\npossible was added in a previous patch, and this behavior may\nbecome the default one in the future.\n\nSo to future proof scripts that may rely on the current behavior\nit is safer to add a --no-ff option to make sure that the current\nbehavior will be used.\n\nRequested-by: Paolo Bonzini <bonzini@gnu.org>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-cherry-pick.txt |    6 +++++-\n builtin/revert.c                  |    5 +++--\n t/t3506-cherry-pick-ff.sh         |    8 ++++++++\n 3 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex d71607a..dfc8243 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] [--ff] <commit>\n+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--[no-]ff] <commit>\n \n DESCRIPTION\n -----------\n@@ -75,6 +75,10 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--no-ff::\n+\tDoes nothing right now, but in the future this may disallow\n+\tfast forward if it becomes the default behavior.\n+\n Author\n ------\n Written by Junio C Hamano <gitster@pobox.com>\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 4799073..111853b 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -36,7 +36,7 @@ static const char * const cherry_pick_usage[] = {\n \tNULL\n };\n \n-static int edit, no_replay, no_commit, mainline, signoff, ff_ok;\n+static int edit, no_replay, no_commit, mainline, signoff, ff_ok, no_ff;\n static enum { REVERT, CHERRY_PICK } action;\n static struct commit *commit;\n static const char *commit_name;\n@@ -59,6 +59,7 @@ static void parse_args(int argc, const char **argv)\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_BOOLEAN(0, \"no-ff\", &no_ff, \"disallow fast forward\"),\n \t\tOPT_INTEGER('m', \"mainline\", &mainline, \"parent number\"),\n \t\tOPT_RERERE_AUTOUPDATE(&allow_rerere_auto),\n \t\tOPT_END(),\n@@ -326,7 +327,7 @@ static int revert_or_cherry_pick(int argc, const char **argv, const char *prefix\n \t\tdie(\"%s: cannot parse parent commit %s\",\n \t\t    me, sha1_to_hex(parent->object.sha1));\n \n-\tif (action == CHERRY_PICK && ff_ok &&\n+\tif (action == CHERRY_PICK && ff_ok && !no_ff &&\n \t    parent && !hashcmp(parent->object.sha1, head) &&\n \t    !edit && !no_commit && !no_replay && !signoff) {\n \t\tchar *hex = sha1_to_hex(commit->object.sha1);\ndiff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh\nindex e17ae71..2d7e532 100755\n--- a/t/t3506-cherry-pick-ff.sh\n+++ b/t/t3506-cherry-pick-ff.sh\n@@ -35,6 +35,14 @@ test_expect_success 'cherry-pick not using --ff does not fast forwards' '\n \ttest \"$(git rev-parse --verify HEAD)\" != \"$(git rev-parse --verify second)\"\n '\n \n+test_expect_success 'cherry-pick using --no-ff does not fast forwards' '\n+\tgit checkout master &&\n+\tgit reset --hard first &&\n+\ttest_tick &&\n+\tgit cherry-pick --no-ff second &&\n+\ttest \"$(git rev-parse --verify HEAD)\" != \"$(git rev-parse --verify second)\"\n+'\n+\n #\n # We setup the following graph:\n #\n-- \n1.7.0.315.gbc198\n"},{"id":"136126","messageId":"20100303201146.23506.89089.chriscool@tuxfamily.org","threadId":"22900","inReplyTo":"20100303201046.23506.32653.chriscool@tuxfamily.org","subject":"[PATCH v3 9/9] rebase -i: use new --ff cherry-pick option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-03-03T20:11:44Z","receivedAt":"2010-03-03T20:11:44Z","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 415ae72..a57f043 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -230,8 +230,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@@ -240,16 +240,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.7.0.315.gbc198\n"}]}