{"thread":{"id":"60875","subject":"[PATCH] prune: mark rebase autostash and orig-head as reachable","startedAt":"2024-02-08T17:00:39Z","lastAt":"2024-05-14T19:37:43Z","messageCount":8,"participants":["Phillip Wood via GitGitGadget","Eric Sunshine","Junio C Hamano","Phillip Wood","Phil Hord"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"488237","messageId":"pull.1656.git.1707411636382.gitgitgadget@gmail.com","threadId":"60875","inReplyTo":null,"subject":"[PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2024-02-08T17:00:36Z","receivedAt":"2024-02-08T17:00:39Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nRebase records the oid of HEAD before rebasing and the commit created by\n\"--autostash\" in files in the rebase state directory. This means that\nthe autostash commit is never reachable from any ref or reflog and when\nrebasing a detached HEAD the original HEAD can become unreachable if the\nuser expires HEAD's the reflog while the rebase is running. Fix this by\nreading the relevant files when marking reachable commits.\n\nNote that it is possible for the commit recorded in\n.git/rebase-merge/amend to be unreachable but pruning that object does\nnot affect the operation of \"git rebase --continue\" as we're only\ninterested in the object id, not in the object itself.\n\nReported-by: Orgad Shaneh <orgads@gmail.com>\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n    prune: mark rebase autostash and orig-head as reachable\n    \n    Thanks for reporting this Orgad, it reminded me that I've been meaning\n    to clean up this patch for a while.\n    \n    I've got a patch on top of this that marks selected pseudorefs such as\n    ORIG_HEAD and AUTO_MERGE as reachable but I've held off sending that as\n    I think it would be better to rebase it on kn/for-all-refs once that has\n    stabilized as that will hopefully allows us to mark all pseudorefs as\n    reachable rather than using a hard-coded list.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1656%2Fphillipwood%2Fprune-protect-rebase-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1656/phillipwood/prune-protect-rebase-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1656\n\n reachable.c                 | 51 +++++++++++++++++++++++++++++++++++++\n t/t3407-rebase-abort.sh     | 17 ++++++++++++-\n t/t3420-rebase-autostash.sh | 10 ++++++++\n 3 files changed, 77 insertions(+), 1 deletion(-)\n\ndiff --git a/reachable.c b/reachable.c\nindex f29b06a5d05..fef29422d4a 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -17,6 +17,7 @@\n #include \"pack-mtimes.h\"\n #include \"config.h\"\n #include \"run-command.h\"\n+#include \"sequencer.h\"\n \n struct connectivity_progress {\n \tstruct progress *progress;\n@@ -30,6 +31,53 @@ static void update_progress(struct connectivity_progress *cp)\n \t\tdisplay_progress(cp->progress, cp->count);\n }\n \n+static int add_one_file(const char *path, struct rev_info *revs)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct object_id oid;\n+\tstruct object *object;\n+\n+\tif (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 0;\n+\t}\n+\tstrbuf_trim(&buf);\n+\tif (!get_oid_hex(buf.buf, &oid)) {\n+\t\tobject = parse_object_or_die(&oid, buf.buf);\n+\t\tadd_pending_object(revs, object, \"\");\n+\t}\n+\treturn 0;\n+}\n+\n+/* Mark objects recored in rebase state files as reachable. */\n+static int add_rebase_files(struct rev_info *revs)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tsize_t len;\n+\tconst char *path[] = {\n+\t\t\"rebase-apply/autostash\",\n+\t\t\"rebase-apply/orig-head\",\n+\t\t\"rebase-merge/autostash\",\n+\t\t\"rebase-merge/orig-head\",\n+\t};\n+\tstruct worktree **worktrees = get_worktrees();\n+\n+\tfor (struct worktree **wt = worktrees; *wt; wt++) {\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addstr(&buf, get_worktree_git_dir(*wt));\n+\t\tstrbuf_complete(&buf, '/');\n+\t\tlen = buf.len;\n+\t\tfor (size_t i = 0; i < ARRAY_SIZE(path); i++) {\n+\t\t\tstrbuf_setlen(&buf, len);\n+\t\t\tstrbuf_addstr(&buf, path[i]);\n+\t\t\tadd_one_file(buf.buf, revs);\n+\t\t}\n+\t}\n+\tstrbuf_release(&buf);\n+\tfree_worktrees(worktrees);\n+\treturn 0;\n+}\n+\n static int add_one_ref(const char *path, const struct object_id *oid,\n \t\t       int flag, void *cb_data)\n {\n@@ -322,6 +370,9 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \thead_ref(add_one_ref, revs);\n \tother_head_refs(add_one_ref, revs);\n \n+\t/* rebase autostash and orig-head */\n+\tadd_rebase_files(revs);\n+\n \t/* Add all reflog info */\n \tif (mark_reflog)\n \t\tadd_reflogs_to_pending(revs, 0);\ndiff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh\nindex ebbaed147a6..9f49c4228b6 100755\n--- a/t/t3407-rebase-abort.sh\n+++ b/t/t3407-rebase-abort.sh\n@@ -40,9 +40,24 @@ testrebase() {\n \t\ttest_path_is_missing \"$state_dir\"\n \t'\n \n+\ttest_expect_success \"pre rebase$type head is marked as reachable\" '\n+\t\t# Clean up the state from the previous one\n+\t\tgit checkout -f --detach pre-rebase &&\n+\t\ttest_tick &&\n+\t\tgit commit --amend --only -m \"reworded\" &&\n+\t\torig_head=$(git rev-parse HEAD) &&\n+\t\ttest_must_fail git rebase$type main &&\n+\t\t# Stop ORIG_HEAD marking $state_dir/orig-head as reachable\n+\t\tgit update-ref -d ORIG_HEAD &&\n+\t\tgit reflog expire --expire=\"$GIT_COMMITTER_DATE\" --all &&\n+\t\tgit prune --expire=now &&\n+\t\tgit rebase --abort &&\n+\t\ttest_cmp_rev $orig_head HEAD\n+\t'\n+\n \ttest_expect_success \"rebase$type --abort after --skip\" '\n \t\t# Clean up the state from the previous one\n-\t\tgit reset --hard pre-rebase &&\n+\t\tgit checkout -B to-rebase pre-rebase &&\n \t\ttest_must_fail git rebase$type main &&\n \t\ttest_path_is_dir \"$state_dir\" &&\n \t\ttest_must_fail git rebase --skip &&\ndiff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh\nindex 693934ee8be..1a820f14815 100755\n--- a/t/t3420-rebase-autostash.sh\n+++ b/t/t3420-rebase-autostash.sh\n@@ -333,4 +333,14 @@ test_expect_success 'never change active branch' '\n \ttest_cmp_rev not-the-feature-branch unrelated-onto-branch\n '\n \n+test_expect_success 'autostash commit is marked as reachable' '\n+\techo changed >file0 &&\n+\tgit rebase --autostash --exec \"git prune --expire=now\" \\\n+\t\tfeature-branch^ feature-branch &&\n+\t# git rebase succeeds if the stash cannot be applied so we need to check\n+\t# the contents of file0\n+\techo changed >expect &&\n+\ttest_cmp expect file0\n+'\n+\n test_done\n\nbase-commit: 2a540e432fe5dff3cfa9d3bf7ca56db2ad12ebb9\n-- \ngitgitgadget\n"},{"id":"488242","messageId":"CAPig+cRASFkTD6=YumZJKv7XJjr1asxKB-mAyBFox8tuwmNnFw@mail.gmail.com","threadId":"60875","inReplyTo":"pull.1656.git.1707411636382.gitgitgadget@gmail.com","subject":"Re: [PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-02-08T17:25:06Z","receivedAt":"2024-02-08T17:25:18Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Feb 8, 2024 at 12:00 PM Phillip Wood via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> Rebase records the oid of HEAD before rebasing and the commit created by\n> \"--autostash\" in files in the rebase state directory. This means that\n> the autostash commit is never reachable from any ref or reflog and when\n> rebasing a detached HEAD the original HEAD can become unreachable if the\n> user expires HEAD's the reflog while the rebase is running. Fix this by\n> reading the relevant files when marking reachable commits.\n>\n> Note that it is possible for the commit recorded in\n> .git/rebase-merge/amend to be unreachable but pruning that object does\n> not affect the operation of \"git rebase --continue\" as we're only\n> interested in the object id, not in the object itself.\n>\n> Reported-by: Orgad Shaneh <orgads@gmail.com>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n> diff --git a/reachable.c b/reachable.c\n> @@ -30,6 +31,53 @@ static void update_progress(struct connectivity_progress *cp)\n> +static int add_one_file(const char *path, struct rev_info *revs)\n> +{\n> +       struct strbuf buf = STRBUF_INIT;\n> +\n> +       if (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {\n> +               strbuf_release(&buf);\n> +               return 0;\n> +       }\n> +       strbuf_trim(&buf);\n> +       if (!get_oid_hex(buf.buf, &oid)) {\n> +               object = parse_object_or_die(&oid, buf.buf);\n> +               add_pending_object(revs, object, \"\");\n> +       }\n> +       return 0;\n> +}\n\nIs this leaking the strbuf? Should the function instead end with:\n\n    strbuf_release(&buf);\n    return 0;\n\nAlso, what is the significance of the return value of this function?\nAll code paths seem to be returning 0 unconditionally, and the caller\nignores the return value.\n\n> +/* Mark objects recored in rebase state files as reachable. */\n\ns/recored/recorded/\n"},{"id":"488247","messageId":"xmqqmssan841.fsf@gitster.g","threadId":"60875","inReplyTo":"pull.1656.git.1707411636382.gitgitgadget@gmail.com","subject":"Re: [PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-02-08T18:06:38Z","receivedAt":"2024-02-08T18:06:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Phillip Wood via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> Rebase records the oid of HEAD before rebasing and the commit created by\n> \"--autostash\" in files in the rebase state directory. This means that\n> the autostash commit is never reachable from any ref or reflog and when\n> rebasing a detached HEAD the original HEAD can become unreachable if the\n> user expires HEAD's the reflog while the rebase is running. Fix this by\n> reading the relevant files when marking reachable commits.\n\nI do not like this kind of special casing in general, but because\nthese are our tools' droppings, I am OK to grandfather them in, as\nlong as we promise ourselves that we will not add more of these\nad-hoc \"text files\" that record object names, loss of which affects\ncorrectness.  They should, like \"git bisect\", be using proper\nreferences to protect these objects instead, of course.\n\nI agree with you that we might want to add pseudorefs as a starting\npoints of reachability traversal, but I suspect it would add\nunnecessary complexity we would rather not want to deal with.\n\nFor example, not GC'ing what is pointed at by lines in FETCH_HEAD is\nOK.  Excluding those objects that are only reachable from an object\nmentioned by a pseudoref, when a new \"git fetch\" is negotiating with\na remote what objects need to be sent here, might be disastrous, as\nthe pseudoref that said \"this object is here and you can safely\nconsider everything reachable from it is\" will be short-lived and\ncan go away anytime, and an auto-gc kicking in at a wrong time ...\n\nThanks.\n"},{"id":"488286","messageId":"6ed59006-9572-460e-996b-63a1321b3db5@gmail.com","threadId":"60875","inReplyTo":"CAPig+cRASFkTD6=YumZJKv7XJjr1asxKB-mAyBFox8tuwmNnFw@mail.gmail.com","subject":"Re: [PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2024-02-09T11:08:33Z","receivedAt":"2024-02-09T11:08:36Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Eric\n\nOn 08/02/2024 17:25, Eric Sunshine wrote:\n> On Thu, Feb 8, 2024 at 12:00 PM Phillip Wood via GitGitGadget\n\n>> +static int add_one_file(const char *path, struct rev_info *revs)\n>> +{\n>> +       struct strbuf buf = STRBUF_INIT;\n>> +\n>> +       if (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {\n>> +               strbuf_release(&buf);\n>> +               return 0;\n>> +       }\n>> +       strbuf_trim(&buf);\n>> +       if (!get_oid_hex(buf.buf, &oid)) {\n>> +               object = parse_object_or_die(&oid, buf.buf);\n>> +               add_pending_object(revs, object, \"\");\n>> +       }\n>> +       return 0;\n>> +}\n> \n> Is this leaking the strbuf? Should the function instead end with:\n> \n>      strbuf_release(&buf);\n>      return 0;\n\nYes, well spotted\n\n> Also, what is the significance of the return value of this function?\n> All code paths seem to be returning 0 unconditionally, and the caller\n> ignores the return value.\n\nGood point, I think in an earlier draft it returned an error at one \npoint, I'll change the return types.\n\n>> +/* Mark objects recored in rebase state files as reachable. */\n> \n> s/recored/recorded/\n\nSharp eyes as ever, thanks for looking at this I'll re-roll\n\nPhillip\n"},{"id":"488291","messageId":"6d2e3c87-4ab8-419a-8350-b95cf03b00c7@gmail.com","threadId":"60875","inReplyTo":"xmqqmssan841.fsf@gitster.g","subject":"Re: [PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2024-02-09T14:15:25Z","receivedAt":"2024-02-09T14:15:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Junio\n\nOn 08/02/2024 18:06, Junio C Hamano wrote:\n> \"Phillip Wood via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n> \n>> Rebase records the oid of HEAD before rebasing and the commit created by\n>> \"--autostash\" in files in the rebase state directory. This means that\n>> the autostash commit is never reachable from any ref or reflog and when\n>> rebasing a detached HEAD the original HEAD can become unreachable if the\n>> user expires HEAD's the reflog while the rebase is running. Fix this by\n>> reading the relevant files when marking reachable commits.\n> \n> I do not like this kind of special casing in general, but because\n> these are our tools' droppings, I am OK to grandfather them in, as\n> long as we promise ourselves that we will not add more of these\n> ad-hoc \"text files\" that record object names, loss of which affects\n> correctness.  They should, like \"git bisect\", be using proper\n> references to protect these objects instead, of course.\n\nWe should definitely do that for future commands\n\n> I agree with you that we might want to add pseudorefs as a starting\n> points of reachability traversal, but I suspect it would add\n> unnecessary complexity we would rather not want to deal with.\n> \n> For example, not GC'ing what is pointed at by lines in FETCH_HEAD is\n> OK.  Excluding those objects that are only reachable from an object\n> mentioned by a pseudoref, when a new \"git fetch\" is negotiating with\n> a remote what objects need to be sent here, might be disastrous, as\n> the pseudoref that said \"this object is here and you can safely\n> consider everything reachable from it is\" will be short-lived and\n> can go away anytime, and an auto-gc kicking in at a wrong time ...\n\nI can see that including pseudorefs when \"git fetch\" is negotiating \ncould be problematic but does it use mark_reachable_objects()? Maybe I'm \nmissing something as I've only done a quick grep but it only seems to be \ncalled from builtin/prune.c and builtin/repack.c and prior to 4421474e06 \n(Move traversal of reachable objects into a separate library., \n2007-01-06) it seems to have been a static method in builtin-prune.c\n\nBest Wishes\n\nPhillip\n\n"},{"id":"488297","messageId":"pull.1656.v2.git.1707495579886.gitgitgadget@gmail.com","threadId":"60875","inReplyTo":"pull.1656.git.1707411636382.gitgitgadget@gmail.com","subject":"[PATCH v2] prune: mark rebase autostash and orig-head as reachable","fromName":"Phillip Wood via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2024-02-09T16:19:39Z","receivedAt":"2024-02-09T16:19:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nRebase records the oid of HEAD before rebasing and the commit created by\n\"--autostash\" in files in the rebase state directory. This means that\nthe autostash commit is never reachable from any ref or reflog and when\nrebasing a detached HEAD the original HEAD can become unreachable if the\nuser expires HEAD's the reflog while the rebase is running. Fix this by\nreading the relevant files when marking reachable commits.\n\nNote that it is possible for the commit recorded in\n.git/rebase-merge/amend to be unreachable but pruning that object does\nnot affect the operation of \"git rebase --continue\" as we're only\ninterested in the object id, not in the object itself.\n\nReported-by: Orgad Shaneh <orgads@gmail.com>\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n    prune: mark rebase autostash and orig-head as reachable\n    \n    Thanks for the comments on v1. I've fixed the memory leak and changed\n    the return types as suggested by Eric.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1656%2Fphillipwood%2Fprune-protect-rebase-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1656/phillipwood/prune-protect-rebase-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1656\n\nRange-diff vs v1:\n\n 1:  ce75996f1a3 ! 1:  7256197a26f prune: mark rebase autostash and orig-head as reachable\n     @@ reachable.c: static void update_progress(struct connectivity_progress *cp)\n       \t\tdisplay_progress(cp->progress, cp->count);\n       }\n       \n     -+static int add_one_file(const char *path, struct rev_info *revs)\n     ++static void add_one_file(const char *path, struct rev_info *revs)\n      +{\n      +\tstruct strbuf buf = STRBUF_INIT;\n      +\tstruct object_id oid;\n     @@ reachable.c: static void update_progress(struct connectivity_progress *cp)\n      +\n      +\tif (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {\n      +\t\tstrbuf_release(&buf);\n     -+\t\treturn 0;\n     ++\t\treturn;\n      +\t}\n      +\tstrbuf_trim(&buf);\n      +\tif (!get_oid_hex(buf.buf, &oid)) {\n      +\t\tobject = parse_object_or_die(&oid, buf.buf);\n      +\t\tadd_pending_object(revs, object, \"\");\n      +\t}\n     -+\treturn 0;\n     ++\tstrbuf_release(&buf);\n      +}\n      +\n     -+/* Mark objects recored in rebase state files as reachable. */\n     -+static int add_rebase_files(struct rev_info *revs)\n     ++/* Mark objects recorded in rebase state files as reachable. */\n     ++static void add_rebase_files(struct rev_info *revs)\n      +{\n      +\tstruct strbuf buf = STRBUF_INIT;\n      +\tsize_t len;\n     @@ reachable.c: static void update_progress(struct connectivity_progress *cp)\n      +\t}\n      +\tstrbuf_release(&buf);\n      +\tfree_worktrees(worktrees);\n     -+\treturn 0;\n      +}\n      +\n       static int add_one_ref(const char *path, const struct object_id *oid,\n\n\n reachable.c                 | 50 +++++++++++++++++++++++++++++++++++++\n t/t3407-rebase-abort.sh     | 17 ++++++++++++-\n t/t3420-rebase-autostash.sh | 10 ++++++++\n 3 files changed, 76 insertions(+), 1 deletion(-)\n\ndiff --git a/reachable.c b/reachable.c\nindex f29b06a5d05..3b85add243b 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -17,6 +17,7 @@\n #include \"pack-mtimes.h\"\n #include \"config.h\"\n #include \"run-command.h\"\n+#include \"sequencer.h\"\n \n struct connectivity_progress {\n \tstruct progress *progress;\n@@ -30,6 +31,52 @@ static void update_progress(struct connectivity_progress *cp)\n \t\tdisplay_progress(cp->progress, cp->count);\n }\n \n+static void add_one_file(const char *path, struct rev_info *revs)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct object_id oid;\n+\tstruct object *object;\n+\n+\tif (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn;\n+\t}\n+\tstrbuf_trim(&buf);\n+\tif (!get_oid_hex(buf.buf, &oid)) {\n+\t\tobject = parse_object_or_die(&oid, buf.buf);\n+\t\tadd_pending_object(revs, object, \"\");\n+\t}\n+\tstrbuf_release(&buf);\n+}\n+\n+/* Mark objects recorded in rebase state files as reachable. */\n+static void add_rebase_files(struct rev_info *revs)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tsize_t len;\n+\tconst char *path[] = {\n+\t\t\"rebase-apply/autostash\",\n+\t\t\"rebase-apply/orig-head\",\n+\t\t\"rebase-merge/autostash\",\n+\t\t\"rebase-merge/orig-head\",\n+\t};\n+\tstruct worktree **worktrees = get_worktrees();\n+\n+\tfor (struct worktree **wt = worktrees; *wt; wt++) {\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addstr(&buf, get_worktree_git_dir(*wt));\n+\t\tstrbuf_complete(&buf, '/');\n+\t\tlen = buf.len;\n+\t\tfor (size_t i = 0; i < ARRAY_SIZE(path); i++) {\n+\t\t\tstrbuf_setlen(&buf, len);\n+\t\t\tstrbuf_addstr(&buf, path[i]);\n+\t\t\tadd_one_file(buf.buf, revs);\n+\t\t}\n+\t}\n+\tstrbuf_release(&buf);\n+\tfree_worktrees(worktrees);\n+}\n+\n static int add_one_ref(const char *path, const struct object_id *oid,\n \t\t       int flag, void *cb_data)\n {\n@@ -322,6 +369,9 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \thead_ref(add_one_ref, revs);\n \tother_head_refs(add_one_ref, revs);\n \n+\t/* rebase autostash and orig-head */\n+\tadd_rebase_files(revs);\n+\n \t/* Add all reflog info */\n \tif (mark_reflog)\n \t\tadd_reflogs_to_pending(revs, 0);\ndiff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh\nindex ebbaed147a6..9f49c4228b6 100755\n--- a/t/t3407-rebase-abort.sh\n+++ b/t/t3407-rebase-abort.sh\n@@ -40,9 +40,24 @@ testrebase() {\n \t\ttest_path_is_missing \"$state_dir\"\n \t'\n \n+\ttest_expect_success \"pre rebase$type head is marked as reachable\" '\n+\t\t# Clean up the state from the previous one\n+\t\tgit checkout -f --detach pre-rebase &&\n+\t\ttest_tick &&\n+\t\tgit commit --amend --only -m \"reworded\" &&\n+\t\torig_head=$(git rev-parse HEAD) &&\n+\t\ttest_must_fail git rebase$type main &&\n+\t\t# Stop ORIG_HEAD marking $state_dir/orig-head as reachable\n+\t\tgit update-ref -d ORIG_HEAD &&\n+\t\tgit reflog expire --expire=\"$GIT_COMMITTER_DATE\" --all &&\n+\t\tgit prune --expire=now &&\n+\t\tgit rebase --abort &&\n+\t\ttest_cmp_rev $orig_head HEAD\n+\t'\n+\n \ttest_expect_success \"rebase$type --abort after --skip\" '\n \t\t# Clean up the state from the previous one\n-\t\tgit reset --hard pre-rebase &&\n+\t\tgit checkout -B to-rebase pre-rebase &&\n \t\ttest_must_fail git rebase$type main &&\n \t\ttest_path_is_dir \"$state_dir\" &&\n \t\ttest_must_fail git rebase --skip &&\ndiff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh\nindex 693934ee8be..1a820f14815 100755\n--- a/t/t3420-rebase-autostash.sh\n+++ b/t/t3420-rebase-autostash.sh\n@@ -333,4 +333,14 @@ test_expect_success 'never change active branch' '\n \ttest_cmp_rev not-the-feature-branch unrelated-onto-branch\n '\n \n+test_expect_success 'autostash commit is marked as reachable' '\n+\techo changed >file0 &&\n+\tgit rebase --autostash --exec \"git prune --expire=now\" \\\n+\t\tfeature-branch^ feature-branch &&\n+\t# git rebase succeeds if the stash cannot be applied so we need to check\n+\t# the contents of file0\n+\techo changed >expect &&\n+\ttest_cmp expect file0\n+'\n+\n test_done\n\nbase-commit: 2a540e432fe5dff3cfa9d3bf7ca56db2ad12ebb9\n-- \ngitgitgadget\n"},{"id":"488311","messageId":"xmqqjzndfr9d.fsf@gitster.g","threadId":"60875","inReplyTo":"pull.1656.v2.git.1707495579886.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] prune: mark rebase autostash and orig-head as reachable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-02-09T18:04:46Z","receivedAt":"2024-02-09T18:04:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Phillip Wood via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +static void add_rebase_files(struct rev_info *revs)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tsize_t len;\n> +\tconst char *path[] = {\n> +\t\t\"rebase-apply/autostash\",\n> +\t\t\"rebase-apply/orig-head\",\n> +\t\t\"rebase-merge/autostash\",\n> +\t\t\"rebase-merge/orig-head\",\n> +\t};\n\nYuck.\n\nHaving this table here makes the sequencer subsystem even less\nmaintainable than it already is.  I wonder if we can at least\nsomehow share some of these?  #leftoverbits.\n\nThanks.\n\n"},{"id":"494735","messageId":"CABURp0oNyOcrDySmMtbnGrFLuWWUybeo7-osS4NqPNBD3wKdaA@mail.gmail.com","threadId":"60875","inReplyTo":"xmqqmssan841.fsf@gitster.g","subject":"Re: [PATCH] prune: mark rebase autostash and orig-head as reachable","fromName":"Phil Hord","fromEmail":"phil.hord@gmail.com","sentAt":"2024-05-14T19:37:28Z","receivedAt":"2024-05-14T19:37:43Z","isPatch":true,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"On Thu, Feb 8, 2024 at 10:08 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"Phillip Wood via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n> > Rebase records the oid of HEAD before rebasing and the commit created by\n> > \"--autostash\" in files in the rebase state directory. This means that\n...\n> I do not like this kind of special casing in general, but because\n> these are our tools' droppings, I am OK to grandfather them in, as\n> long as we promise ourselves that we will not add more of these\n> ad-hoc \"text files\" that record object names, loss of which affects\n> correctness.  They should, like \"git bisect\", be using proper\n> references to protect these objects instead, of course.\n\nI have long wanted to have a special ref named \"AUTOSTASH\" since it\nsupports my workflow of applying workdir changes to previous commits\nduring a rebase.  For example, I often do this:\n\n     $ git rebase -i\n     Created autostash: c0ffeebea0\n     ...\n     <stopped to edit some commit in my history>\n     $ git stash apply c0ffeebea0\n     $ git commit --amend && git rebase --continue\n\nBut it requires me to find the text output after \"Created autostash:\"\nfrom the original rebase command which may have scrolled a lot by now.\nIt would be easier to say:\n     $ git stash apply AUTOSTASH\n\nI see that MERGE_AUTOSTASH has been added lately. And I am inferring\nthat there's a desire to remove (eventually) these file-based info\ntrackers such as \"rebase-apply/autostash\". Is there any reason not to\nraise the rebase/autostash notation to a proper ref now?  Should it be\nnamed REBASE_AUTOSTASH if I add this?\n\nEven if we don't remove the file-based notation immediately\n\"rebase-apply/autostash\", I would like to add a ref that duplicates\nthe information for my workflow. Maybe we can deprecate the file\nitself and remove it in some future version.\n"}]}