Skip to content

pr-2180/ozemin/stash-rename-v2

tagged this 27 Jul 10:54
From: =?UTF-8?q?Emin=20=C3=96zata?= <eminozata@proton.me>

Stash entries accumulate with the default "WIP on <branch>" message
when they are created in a hurry, and there is no way to relabel the
ones worth keeping afterwards.  The only option is dropping an entry
and re-storing it by hand, which moves it to the top of the stash
list and gets fiddly for deeper entries.

Add 'git stash reword <message> [<stash>]', which defaults to the
latest entry like the other subcommands do.  The name follows the
verb git already uses for changing only a message, as in the reword
command of 'git rebase -i' and in 'git history reword'.  It reads
the whole reflog and writes it back in a single transaction, with
the new message on the target and every other entry left as it was.
Position, contents, timestamps and the reflog chain all stay put.

Before touching anything, the command inspects the target entry and
the ones above it, and refuses to start if any of them does not look
like a stash commit; that can only happen when refs/stash was
written to by hand.  The rewrite clears the reflog before writing
the new one, so if the transaction fails afterwards, the command
reports the object id of each collected entry and re-stores it
best-effort.  Whatever it fails to re-store can be recovered with
'git stash store'.

This was proposed before: in 2010, as a "git reflog update" command
that edited reflog entries in place [1].  When it came up again in
2013 [2], Junio rejected it on the grounds that reflogs are
append-only recovery logs, and that whoever really cares about a
stash message can pop and re-stash [3].  Michael Haggerty pointed
out in that thread that refs/stash does not fit the description:
its reflog is the primary data store for stash entries, and 'git
stash drop' rewrites it all the time [4].  So this patch rewrites
refs/stash directly, the way 'git stash drop' already does, through
ref_transaction_update_reflog(), which 'git remote rename' and 'git
refs migrate' already use to rewrite existing reflogs.

Name the target by index (stash@{1}); the command rejects
time-based selectors, because it needs the entry's position in the
reflog.  Writing the reflog back at once keeps the cost linear in
its length whatever that position is, and spares the reftable
backend from emitting and compacting a table per entry, which is
what dropping and re-storing the entries one by one would cost.

[1] https://lore.kernel.org/git/20100620093142.GF24805@occam.hewgill.net/
[2] https://lore.kernel.org/git/loom.20130104T192132-16@post.gmane.org/
[3] https://lore.kernel.org/git/7vbod4tynt.fsf@alter.siamese.dyndns.org/
[4] https://lore.kernel.org/git/50ED2C78.1030300@alum.mit.edu/

Signed-off-by: Emin Özata <eminozata@proton.me>

Submitted-As: https://lore.kernel.org/git/pull.2180.v2.git.1785149687514.gitgitgadget@gmail.com
In-Reply-To: https://lore.kernel.org/git/pull.2180.git.1784190706028.gitgitgadget@gmail.com
Assets 2
Loading