Subject: Re: [PATCH v5 06/12] builtin/history: implement "reword" subcommand

From: Junio C Hamano <[email-masked]>
Date: Tue, 21 Oct 2025 14:34:31 -0700

Patrick Steinhardt <[email-masked]> writes:

> Implement a new "reword" subcommand for git-history(1). This subcommand
> is essentially the same as if a user performed an interactive rebase
> with a single commit changed to use the "reword" verb.

Oy.  I've always wanted something like this in "rebase -i" myself.

It is a bit sad that I have to learn a new command to do something
obvious and trivial like this, but that's life ;-)

Maybe "git history" becomes powerful enough and can replace my
every-day use of "rebase -i".

> @@ -9,6 +9,7 @@ SYNOPSIS
>  --------
>  [synopsis]
>  git history [<options>]
> +git history reword [<options>] <commit>

It is curious that a command-less form is still listed here,
especially since this command "requires" a subcommand.  I would have
expected that there will be a single line here after implementing a
single subcommand.

> +`reword <commit> [--message=<message>]`::

That should be `reword [--message=<message>] <commit>` no?

> +	Rewrite the commit message of the specified commit. All the other
> +	details of this commit remain unchanged. If no commit message is
> +	provided, then this command will spawn an editor with the current
> +	message of that commit.

As long as it takes more than one -m and concatenates them just like
"git commit -m <message1> -m <message2>" does, I would not complain
too much that a command line option to give message encourages sloppy
log messages.

> +		if (!onto) {
> +			onto = commit;
> +			result.clean = 1;
> +			result.tree = repo_get_commit_tree(repo, commit);
> +		} else {
> +			onto = replay_pick_regular_commit(repo, commit, replayed_commits,
> +							  onto, &merge_opts, &result);
> +			if (!onto)
> +				break;
> +		}

Hmph, I would have expected that the overall flow of this command
would be

 * find the commits above and including the <commit> in question,
   making sure there is no merge.

 * read metadata of <commit> like the parent (as we do not allow
   merges), tree, author ident & time.

 * create a new commit object that has the same metadata as <commit>
   on top of the parent of <commit>, but with the updated message
   and new committer ident & time.

 * initialize a variable Current to point at the rewritten <commit>

 * loop for each commit C in <commit>..HEAD range in reverse order
   (we know we have a single strand of pearls):

   - read metadata of C

   - create a new commit object C' that has the same metadata and
     message as C on top of the Current commit, with new committer
     ident & time.

   - make Current point at the resulting C'

 * Point the Current with HEAD.

without having to touch any "pick" machinery.  Why do we need to go
down to the merge machinery for a mere "reword" operation?