{"thread":{"id":"65926","subject":"[PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","startedAt":"2026-07-05T14:15:27Z","lastAt":"2026-07-07T04:27:20Z","messageCount":8,"participants":["Trevor Gross","Junio C Hamano","Matt Hunter","Jeff King","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"547164","messageId":"20260705140931.98262-2-tg@trevorgross.com","threadId":"65926","inReplyTo":null,"subject":"[PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Trevor Gross","fromEmail":"tg@trevorgross.com","sentAt":"2026-07-05T14:09:06Z","receivedAt":"2026-07-05T14:15:27Z","isPatch":true,"body":"It is sometimes useful to do cherry picks via rebases when there is a\nsequence of picks or other git operations to combine. However, there is\nno interactive rebase equivalent to the cherry-pick `-x` flag, which\nadds a line to the commit body indicating the original commit.\n\nUsing `exec git cherry-pick ... -x` does work, but is not as nice\nbecause it interrupts rebase flow; after resolving a conflict, both `git\ncherry-pick --continue` and `git rebase --continue` must be run.\n\nTo improve this, introduce `-x` to the pick, reword, and edit todo\nrebase commands.  This uses the same logic as cherry-pick to add a\n\"(cherry picked from commit ...)\" note to the commit body.\n\nOf note is that rebase will fastforward wherever possible, meaning the\ncheck for TODO_RECORD_ORIGIN doesn't get hit and the message will not\nget amended. This differs from the cherry-pick logic, which will add\n\"cherry picked from ...\" even if a rewrite isn't otherwise necessary.\n\nSigned-off-by: Trevor Gross <tg@trevorgross.com>\n---\n\nLink to PR with the CI runs: https://github.com/git/git/pull/2194\n\n Documentation/git-rebase.adoc | 16 +++++++++++++\n rebase-interactive.c          |  9 +++++---\n sequencer.c                   | 19 ++++++++++++++--\n t/t3404-rebase-interactive.sh | 42 +++++++++++++++++++++++++++++++++++\n 4 files changed, 81 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc\nindex f6c22d1598..d8a8e2c2d6 100644\n--- a/Documentation/git-rebase.adoc\n+++ b/Documentation/git-rebase.adoc\n@@ -978,6 +978,22 @@ pick f4593f9 four\n exec make test\n --------------------\n\n+Similar to `git cherry-pick`, `-x` can be specified to append a \"(cherry\n+picked from commit …​)\" line to the commit body if the the commit base\n+changes. That is, the following todo list:\n+\n+--------------\n+pick 123456 -x\n+edit 654321 -x\n+--------------\n+\n+acts the same as:\n+\n+---------------------------\n+$ git cherry-pick -x 123456\n+$ git cherry-pick -xe 654321\n+---------------------------\n+\n SPLITTING COMMITS\n -----------------\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 809f76a87b..6a86ab5a94 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -47,9 +47,9 @@ void append_todo_help(int command_count,\n \t\t      struct strbuf *buf)\n {\n \tconst char *msg = _(\"\\nCommands:\\n\"\n-\"p, pick <commit> = use commit\\n\"\n-\"r, reword <commit> = use commit, but edit the commit message\\n\"\n-\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"p, pick   [ -x ] <commit> = use commit\\n\"\n+\"r, reword [ -x ] <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit   [ -x ] <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n \"f, fixup [-C | -c] <commit> = like \\\"squash\\\" but keep only the previous\\n\"\n \"                   commit's log message, unless -C is used, in which case\\n\"\n@@ -68,6 +68,9 @@ void append_todo_help(int command_count,\n \"                      to this position in the new commits. The <ref> is\\n\"\n \"                      updated at the end of the rebase\\n\"\n \"\\n\"\n+\"With pick, reword, or edit, -x will append a line that says \\\"(cherry\\n\"\n+\"picked from commit <sha>)\\\", similar to git-cherry-pick.\"\n+\"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \tunsigned edit_todo = !(shortrevisions && shortonto);\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 57855b0066..fde09dd77d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1884,6 +1884,7 @@ enum todo_item_flags {\n \tTODO_EDIT_MERGE_MSG    = (1 << 0),\n \tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n \tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+\tTODO_RECORD_ORIGIN     = (1 << 3),\n };\n\n static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n@@ -2390,7 +2391,7 @@ static int do_pick_commit(struct repository *r,\n \t\tif (find_commit_subject(msg.message, &p))\n \t\t\tstrbuf_addstr(&ctx->message, p);\n\n-\t\tif (opts->record_origin) {\n+\t\tif (opts->record_origin || (item->flags & TODO_RECORD_ORIGIN)) {\n \t\t\tstrbuf_complete_line(&ctx->message);\n \t\t\tif (!has_conforming_footer(&ctx->message, NULL, 0))\n \t\t\t\tstrbuf_addch(&ctx->message, '\\n');\n@@ -2758,6 +2759,14 @@ static int parse_insn_line(struct repository *r, struct replay_opts *opts,\n \t\treturn error(_(\"missing arguments for %s\"),\n \t\t\t     command_to_string(item->command));\n\n+\tif (item->command == TODO_PICK || item->command == TODO_REWORD ||\n+\t    item->command == TODO_EDIT) {\n+\t\tif (skip_prefix(bol, \"-x\", &bol)) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_RECORD_ORIGIN;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_EXEC || item->command == TODO_LABEL ||\n \t    item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {\n \t\tint ret = 0;\n@@ -5524,7 +5533,7 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n-\tstruct todo_item item;\n+\tstruct todo_item item = { 0 };\n\n \titem.command = opts->action == REPLAY_PICK ?\n \t\t\tTODO_PICK : TODO_REVERT;\n@@ -6340,6 +6349,12 @@ static void todo_list_to_strbuf(struct repository *r,\n \t\t\t\t\t  short_commit_name(r, item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n\n+\t\t\tif (item->command == TODO_PICK || item->command == TODO_EDIT ||\n+\t\t\t    item->command == TODO_REWORD) {\n+\t\t\t\tif (item->flags & TODO_RECORD_ORIGIN)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -x\");\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_FIXUP) {\n \t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 58b3bb0c27..3ff86ebaae 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -2337,6 +2337,48 @@ test_expect_success 'non-merge commands reject merge commits' '\n \ttest_cmp expect actual\n '\n\n+\n+test_expect_success 'rebase -i with pick -x' '\n+\tgit checkout A &&\n+\torig_j=\"$(git rev-parse J)\" &&\n+\torig_k=\"$(git rev-parse K)\" &&\n+\torig_l=\"$(git rev-parse L)\" &&\n+\tcat >fake-todo <<-EOF &&\n+\t# No message since this is a fastforward\n+\tpick -x F\n+\t# The rest should get the \"cherry picked from \" message\n+\tpick -x J\n+\treword -x K\n+\tedit -x L\n+\tEOF\n+\t(\n+\t\tset_replace_editor fake-todo &&\n+\t\tgit rebase -i HEAD\n+\t) &&\n+\tgit log --format=\"---%n%s%n%b\" >actual &&\n+\tcat >expect <<-EOF &&\n+\t---\n+\tL\n+\t(cherry picked from commit $orig_l)\n+\n+\t---\n+\tK\n+\t(cherry picked from commit $orig_k)\n+\n+\t---\n+\tJ\n+\t(cherry picked from commit $orig_j)\n+\n+\t---\n+\tF\n+\n+\t---\n+\tA\n+\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n # This must be the last test in this file\n test_expect_success '$EDITOR and friends are unchanged' '\n \ttest_editor_unchanged\n--\n2.50.1 (Apple Git-155)\n"},{"id":"547167","messageId":"xmqqldbpclhh.fsf@gitster.g","threadId":"65926","inReplyTo":"20260705140931.98262-2-tg@trevorgross.com","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-05T18:58:02Z","receivedAt":"2026-07-05T18:58:05Z","isPatch":true,"body":"Trevor Gross <tg@trevorgross.com> writes:\n\nFirst, I have to say that I personally am not a huge fan of these\n\"cherry picked from...\" messages.\n\nEspecially because I was the one who initially introduced them and\nenabled it as the default behaviour, and it turned out that people\nreally hated to see them (and rightfully so, given that the original\ncommit object were often not available to them) so much that they\nthrew raw eggs at me until I made it disabled by default.\n\nOh, the raw egg part is an exaggeration, but it was a traumatic\nexperience for me nevertheless ;-)\n\nAnyway, let's see what we have here.\n\n> Of note is that rebase will fastforward wherever possible, meaning the\n> check for TODO_RECORD_ORIGIN doesn't get hit and the message will not\n> get amended. This differs from the cherry-pick logic, which will add\n> \"cherry picked from ...\" even if a rewrite isn't otherwise necessary.\n\nWhy should it behave differently?  Ease of implementation, or\nare there inherent design reasons behind this difference (if so that\nneeds to be described here).\n\n\n> +Similar to `git cherry-pick`, `-x` can be specified to append a \"(cherry\n> +picked from commit …​)\" line to the commit body if the the commit base\n> +changes. That is, the following todo list:\n\n\"the the\".\n\n> +\n> +--------------\n> +pick 123456 -x\n> +edit 654321 -x\n> +--------------\n\nYou do not mean \"$verb -x 123456\" (where verb in (pick, edit))?\n\nThe help text seems to contradict with the above.\n\n> diff --git a/rebase-interactive.c b/rebase-interactive.c\n> index 809f76a87b..6a86ab5a94 100644\n> --- a/rebase-interactive.c\n> +++ b/rebase-interactive.c\n> @@ -47,9 +47,9 @@ void append_todo_help(int command_count,\n>  \t\t      struct strbuf *buf)\n>  {\n>  \tconst char *msg = _(\"\\nCommands:\\n\"\n> +\"p, pick   [ -x ] <commit> = use commit\\n\"\n> +\"r, reword [ -x ] <commit> = use commit, but edit the commit message\\n\"\n> +\"e, edit   [ -x ] <commit> = use commit, but stop for amending\\n\"\n\nSo presumably the documentation part needs fixing?\n\n> @@ -2758,6 +2759,14 @@ static int parse_insn_line(struct repository *r, struct replay_opts *opts,\n>  \t\treturn error(_(\"missing arguments for %s\"),\n>  \t\t\t     command_to_string(item->command));\n>\n> +\tif (item->command == TODO_PICK || item->command == TODO_REWORD ||\n> +\t    item->command == TODO_EDIT) {\n> +\t\tif (skip_prefix(bol, \"-x\", &bol)) {\n> +\t\t\tbol += strspn(bol, \" \\t\");\n> +\t\t\titem->flags |= TODO_RECORD_ORIGIN;\n\n  \"pick -xabcdef 123456 commit title\"\n\nis parsed just like \"pick -x\" but somewhere downstream it would fail\nto pick up the commit object name and barf, with something like\n\"'abcdef' is not a commit object name\"?  Or worse, do we mistake it\nas picking commit abcdef whose title is \"123456 commit title\"?\n\nIn any case, since a valid <commit> will never begin with '-', we\nshould be able to design/implement a much better error checking here.\n\n> @@ -5524,7 +5533,7 @@ static int single_pick(struct repository *r,\n>  \t\t       struct replay_opts *opts)\n>  {\n>  \tint check_todo;\n> -\tstruct todo_item item;\n> +\tstruct todo_item item = { 0 };\n\nThis may be a good change, but I do not think the proposed commit log\nmessage touched upon it.  It should.  Is it a bug that we somehow were\nlucky that nobody made an access to uninitialized piece of memory here?\n\n> @@ -6340,6 +6349,12 @@ static void todo_list_to_strbuf(struct repository *r,\n>  \t\t\t\t\t  short_commit_name(r, item->commit) :\n>  \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n>\n> +\t\t\tif (item->command == TODO_PICK || item->command == TODO_EDIT ||\n> +\t\t\t    item->command == TODO_REWORD) {\n> +\t\t\t\tif (item->flags & TODO_RECORD_ORIGIN)\n> +\t\t\t\t\tstrbuf_addstr(buf, \" -x\");\n> +\t\t\t}\n\nWhy two nested conditional, instead of\n\n\t\tif ((item->command == ... ||\n\t\t     item->command == ... ||\n\t\t     item->command == ...) && (item->flags & RECORD_ORIGIN))\n\t\t\tadd \" -x\";\n\n?\n"},{"id":"547168","messageId":"xmqqechhcg6h.fsf@gitster.g","threadId":"65926","inReplyTo":"20260705140931.98262-2-tg@trevorgross.com","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-05T20:52:38Z","receivedAt":"2026-07-05T20:52:41Z","isPatch":true,"body":"There is another thing.\n\n> Using `exec git cherry-pick ... -x` does work, ...\n\nDoes it really work?  I seem to recall there is a reason why \"pick\"\ninsn in the rebase todo list and \"exec git cherry-pick\" would not\nwork identically and the distinction is rather deliberate.\n\nRebase copies the notes attached to the original commits to the\ncorresponding rewritten commits.  This is because rebase is a way to\n_move_ an existing (and hopefully not yet published) history on top\nof some other base, with the full intention to destroy, abandon,\nremove, and forget about the original history, and nobody will see\nthe original commits after the rebase is finished.  Copying notes,\ntherefore, is a sensible way to preserve the data, as these new\ncommits fully _replace_ the old ones.\n\nOn the other hand, cherry-pick is about _duplicating_ a parallel\nhistory in a new context that is separate from the original, while\npreserving the original history.  Since the expectation is that the\noriginal history will be kept (and not rewritten---otherwise the\n\"cherry picked from ...\" comment will totally be useless), and the\nnew commits are being created to live in their own new _context_,\nnotes are not carried over.\n\nAs can be seen in the mental model above, \"rebase\" by its nature\nis what you do with the intention not to keep the original. From\nthat point of view, \"pick -x\" is a poor fit in the context, because\nfor the result from \"cherry-pick -x\" to be any useful, the original\ncommit you made the picked commit out of MUST be known to those who\nlearn the fact that this new commit was cherry-picked from that\nother commit.  It goes directly opposite to what \"rebase\" does, in\nthat the point of rebase is to destroy \"that other commit\" and make\nsure nobody will see it after rebase is done.\n\nSo...\n"},{"id":"547169","messageId":"DJQZMN6UIPBY.Z6WBNUP1E3U2@lfurio.us","threadId":"65926","inReplyTo":"xmqqldbpclhh.fsf@gitster.g","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Matt Hunter","fromEmail":"m@lfurio.us","sentAt":"2026-07-05T22:23:52Z","receivedAt":"2026-07-05T22:24:00Z","isPatch":true,"body":"On Sun Jul 5, 2026 at 2:58 PM EDT, Junio C Hamano wrote:\n> Trevor Gross <tg@trevorgross.com> writes:\n>> @@ -5524,7 +5533,7 @@ static int single_pick(struct repository *r,\n>>  \t\t       struct replay_opts *opts)\n>>  {\n>>  \tint check_todo;\n>> -\tstruct todo_item item;\n>> +\tstruct todo_item item = { 0 };\n>\n> This may be a good change, but I do not think the proposed commit log\n> message touched upon it.  It should.  Is it a bug that we somehow were\n> lucky that nobody made an access to uninitialized piece of memory here?\n\nOn a first glance, do_pick_commit() was only referencing the 'command'\nand 'commit' fields of struct todo_item.  Trevor added a reference to\nitem->flags which created the need to initialize it here.\n\nHowever, on a second glance, there _is_ a pre-existing reference to\nitem->flags in do_pick_commit() as well, at line 2410 on master\n(e9019fcafe00):\n\n    if (command == TODO_REWORD)\n        reword = 1;\n    else if (is_fixup(command)) {\n        if (update_squash_messages(r, command, commit,\n                       opts, item->flags)) {\n            res = -1;\n            goto leave;\n        }\n\nIt doesn't look like this code is actually reachable from single_pick()\nas written, since it is guarded by is_fixup(command) and single_pick()\ndoesn't set such a command.\n"},{"id":"547173","messageId":"20260706002415.GC2301945@coredump.intra.peff.net","threadId":"65926","inReplyTo":"20260705140931.98262-2-tg@trevorgross.com","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-07-06T00:24:15Z","receivedAt":"2026-07-06T00:24:16Z","isPatch":true,"body":"On Sun, Jul 05, 2026 at 02:09:06PM +0000, Trevor Gross wrote:\n\n> It is sometimes useful to do cherry picks via rebases when there is a\n> sequence of picks or other git operations to combine. However, there is\n> no interactive rebase equivalent to the cherry-pick `-x` flag, which\n> adds a line to the commit body indicating the original commit.\n> \n> Using `exec git cherry-pick ... -x` does work, but is not as nice\n> because it interrupts rebase flow; after resolving a conflict, both `git\n> cherry-pick --continue` and `git rebase --continue` must be run.\n\nTo me this feels like you're approaching the problem backwards. Mostly\nbecause rebase and cherry-pick are _kind of_ the same operation.\n\nUsually a rebase is about rewriting the commits on a new base so that\nyou can throw away the old ones. And that's why git-rebase generally\nrewrites the branch you're on, and replaces those old commits. So adding\na \"cherry-picked from...\" annotation doesn't make sense there; nobody\nwould have those old commits!\n\nAnd so while cherry-pick is doing roughly the same thing under the hood,\nit has different defaults: you specify a read-only source from which to\npick the commits (and \"-x\" may or may not make sense).\n\nSo I can see why you might use git-rebase to do what is essentially a\ncherry-pick, porting options from cherry-pick to rebase feels weird. Why\ncan't we fix the problems in cherry-pick that make you want to use\nrebase instead?\n\nOnce upon a time they had very different backends, but these days\nthey're both using the sequencer subsystem under the hood. And it sounds\nlike you just want to do interactive sequencer type things. If there was\nan interactive cherry-pick option, would that be enough? I wonder how\nfar we are from that.\n\nLet's do a little experiment that stops the cherry-pick in the middle,\nlike this:\n\n  # start with a repo with any file\n  git init\n  echo base >file\n  git add file\n  git commit -m file\n\n  # one branch makes a few commits\n  git checkout -b branch-a main\n  for i in a1 a2 a3; do\n\techo $i >file\n\tgit commit -am $i\n  done\n\n  # another one does the same\n  git checkout -b branch-b main\n  for i in b1 b2 b3; do\n\techo $i >file\n\tgit commit -am $i\n  done\n\n  # and now we try to cherry-pick all of branch-a, which will\n  # fail with conflicts\n  git cherry-pick main..branch-a\n\nAnd now let's look in the sequencer directory:\n\n  $ cat .git/sequencer/todo\n  pick 206bede a1\n  pick 638aff4 a2\n  pick ec375c4 a3\n\nSo what I'm wondering specifically: have we done 99% of the work to have\ninteractive cherry-pick, and we just need to add a \"-i\" option to let\nthe user edit that todo file before we start executing it?\n\nTo be clear, I don't know the answer. It's been ages since I've looked\nat sequencer code, so there might be more gotchas. That's just my gut\nfeeling from a high level after reading your message.\n\n> To improve this, introduce `-x` to the pick, reword, and edit todo\n> rebase commands.  This uses the same logic as cherry-pick to add a\n> \"(cherry picked from commit ...)\" note to the commit body.\n\nThere is one thing that differs here from how cherry-pick works. Even\nthough cherry-pick is using the sequencer under the hood, it does not\nallow individual \"pick -x\" commands, but instead records it as an option\nfor the whole operation. So if you add \"-x\" to the conflicting\ncherry-pick above, you can see:\n\n  $ cat .git/sequencer/opts\n  [options]\n\trecord-origin = true\n\nThat's less flexible, since you can't have per-pick \"-x\" behavior. If\nthat's important to you, I think it might be reasonable to support the\n\"-x\" option for those sequencer commands, and have \"cherry-pick -x\" just\nadd it automatically to each line (rather than record the global\noption).\n\n> Of note is that rebase will fastforward wherever possible, meaning the\n> check for TODO_RECORD_ORIGIN doesn't get hit and the message will not\n> get amended. This differs from the cherry-pick logic, which will add\n> \"cherry picked from ...\" even if a rewrite isn't otherwise necessary.\n\nThis sounds like another case where cherry-pick and rebase have subtly\ndifferent behaviors, even though the core functionality is still \"pick\nthese commits\". So being able to stick to the cherry-pick command for\ncherry-picking may be preferable.\n\n-Peff\n"},{"id":"547209","messageId":"5d238e0d-18ba-429a-a9a4-a3988b00e1e1@gmail.com","threadId":"65926","inReplyTo":"20260706002415.GC2301945@coredump.intra.peff.net","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-07-06T10:08:18Z","receivedAt":"2026-07-06T10:08:22Z","isPatch":true,"body":"On 06/07/2026 01:24, Jeff King wrote:\n> On Sun, Jul 05, 2026 at 02:09:06PM +0000, Trevor Gross wrote:\n> \n>> It is sometimes useful to do cherry picks via rebases when there is a\n>> sequence of picks or other git operations to combine. However, there is\n>> no interactive rebase equivalent to the cherry-pick `-x` flag, which\n>> adds a line to the commit body indicating the original commit.\n>>\n>> Using `exec git cherry-pick ... -x` does work, but is not as nice\n>> because it interrupts rebase flow; after resolving a conflict, both `git\n>> cherry-pick --continue` and `git rebase --continue` must be run.\n> \n> To me this feels like you're approaching the problem backwards. Mostly\n> because rebase and cherry-pick are _kind of_ the same operation.\n> \n> Usually a rebase is about rewriting the commits on a new base so that\n> you can throw away the old ones. And that's why git-rebase generally\n> rewrites the branch you're on, and replaces those old commits. So adding\n> a \"cherry-picked from...\" annotation doesn't make sense there; nobody\n> would have those old commits!\n\nExactly\n\n> And so while cherry-pick is doing roughly the same thing under the hood,\n> it has different defaults: you specify a read-only source from which to\n> pick the commits (and \"-x\" may or may not make sense).\n> \n> So I can see why you might use git-rebase to do what is essentially a\n> cherry-pick, porting options from cherry-pick to rebase feels weird. Why\n> can't we fix the problems in cherry-pick that make you want to use\n> rebase instead?\n\nI think that would be a better solution. Trevor - what is missing from \n\"git cherry-pick\" that means you end up using \"git rebase\" instead?\n\n> So what I'm wondering specifically: have we done 99% of the work to have\n> interactive cherry-pick, and we just need to add a \"-i\" option to let\n> the user edit that todo file before we start executing it?\n> \n> To be clear, I don't know the answer. It's been ages since I've looked\n> at sequencer code, so there might be more gotchas. That's just my gut\n> feeling from a high level after reading your message.\n\nI don't think it would be much work. The code that edits the todo list \nis rebase specific because it deals with rebase.missingCommitsCheck but \nit shouldn't be too difficult to generalize it. I do wonder though if it \nmakes sense to support all of the usual commands when cherry-picking \nespecially with `-x`. In particular I'm not sure about adding support \nfor `edit -x`, or for `pick -x` followed by `fixup` - what does the \ntrailer mean when the commit has been edited or fixed up? (though if \nyou're back-porting bug fixes I guess some degree of editing is inevitable)\n\nOn a slight tangent I've sometimes wanted to be able to do\n\n\tgit cherry-pick --exec 'make test' some commits\n\n>> To improve this, introduce `-x` to the pick, reword, and edit todo\n>> rebase commands.  This uses the same logic as cherry-pick to add a\n>> \"(cherry picked from commit ...)\" note to the commit body.\n> \n> There is one thing that differs here from how cherry-pick works. Even\n> though cherry-pick is using the sequencer under the hood, it does not\n> allow individual \"pick -x\" commands, but instead records it as an option\n> for the whole operation. So if you add \"-x\" to the conflicting\n> cherry-pick above, you can see:\n> \n>    $ cat .git/sequencer/opts\n>    [options]\n> \trecord-origin = true\n> \n> That's less flexible, since you can't have per-pick \"-x\" behavior. If\n> that's important to you, I think it might be reasonable to support the\n> \"-x\" option for those sequencer commands, and have \"cherry-pick -x\" just\n> add it automatically to each line (rather than record the global\n> option).\n\nYes, if we're adding a per-commit flag to record the origin it would be \nmuch nicer just to set that flag when we build the todo list rather than \nhaving to do\n\n\tif (opt->record_origin || (item->flags &  TODO_RECORD_ORIGIN))\n\nto see whether we need to add the trailer.\n\n>> Of note is that rebase will fastforward wherever possible, meaning the\n>> check for TODO_RECORD_ORIGIN doesn't get hit and the message will not\n>> get amended. This differs from the cherry-pick logic, which will add\n>> \"cherry picked from ...\" even if a rewrite isn't otherwise necessary.\n> \n> This sounds like another case where cherry-pick and rebase have subtly\n> different behaviors, even though the core functionality is still \"pick\n> these commits\". So being able to stick to the cherry-pick command for\n> cherry-picking may be preferable.\n\nI think that is a consequence of the way this patch is implemented - it \nadds the new per-commit flag but does not change the conditions for \npreventing a fast-forward in do_pick_commit() or skip_unnecessary_picks().\n\nThanks\n\nPhillip\n\n"},{"id":"547265","messageId":"xmqqcxwzamtm.fsf@gitster.g","threadId":"65926","inReplyTo":"5d238e0d-18ba-429a-a9a4-a3988b00e1e1@gmail.com","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-06T20:24:21Z","receivedAt":"2026-07-06T20:24:24Z","isPatch":true,"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> Usually a rebase is about rewriting the commits on a new base so that\n>> you can throw away the old ones. And that's why git-rebase generally\n>> rewrites the branch you're on, and replaces those old commits. So adding\n>> a \"cherry-picked from...\" annotation doesn't make sense there; nobody\n>> would have those old commits!\n>\n> Exactly\n\n;-)  \n\nWhew.  Briefly I wondered if I were the only one who felt 'rebase'\nand 'cherry-pick' serve two different purposes and need to behave\ndifferently, e.g., with respect to how notes on old commits are\ndealt with.\n\n> On a slight tangent I've sometimes wanted to be able to do\n>\n> \tgit cherry-pick --exec 'make test' some commits\n\nYes, I agree that is something quite handy.\n\nThanks.\n"},{"id":"547282","messageId":"20260707042712.GA677056@coredump.intra.peff.net","threadId":"65926","inReplyTo":"5d238e0d-18ba-429a-a9a4-a3988b00e1e1@gmail.com","subject":"Re: [PATCH] rebase -i: introduce `pick -x` to add \"cherry picked from commit ...\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-07-07T04:27:12Z","receivedAt":"2026-07-07T04:27:20Z","isPatch":true,"body":"On Mon, Jul 06, 2026 at 11:08:18AM +0100, Phillip Wood wrote:\n\n> > To be clear, I don't know the answer. It's been ages since I've looked\n> > at sequencer code, so there might be more gotchas. That's just my gut\n> > feeling from a high level after reading your message.\n> \n> I don't think it would be much work. The code that edits the todo list is\n> rebase specific because it deals with rebase.missingCommitsCheck but it\n> shouldn't be too difficult to generalize it. I do wonder though if it makes\n> sense to support all of the usual commands when cherry-picking especially\n> with `-x`. In particular I'm not sure about adding support for `edit -x`, or\n> for `pick -x` followed by `fixup` - what does the trailer mean when the\n> commit has been edited or fixed up? (though if you're back-porting bug fixes\n> I guess some degree of editing is inevitable)\n\nI'd probably err on the side of assuming the user knows what they're\ndoing, and will mention any edits in the commit message as appropriate.\nMaybe that's being too optimistic. :)\n\n> On a slight tangent I've sometimes wanted to be able to do\n> \n> \tgit cherry-pick --exec 'make test' some commits\n\nYeah, though in that case I'd usually cherry-pick and then just do an\nin-place \"rebase -x 'make test'\". You could really do _almost_ any\ncherry-pick sequencer operation like that, which is perhaps why we\nhaven't see a huge number of requests for it.\n\nThis \"-x\" thing is special because it's inherently about looking at the\noriginal commit id, as opposed to fiddling with our rebased version. But\nI guess you could \"cherry-pick -x\" and then rebase (doing whatever\nrearranging and markup you wanted) the result.\n\n-Peff\n"}]}