Subject: Re: [PATCH RFC 11/11] builtin/history: implement "split" subcommand

From: Jean-Noël AVILA <[email-masked]>
Date: Sat, 23 Aug 2025 18:37:23 +0200

On Tuesday, 19 August 2025 12:56:07 CEST Patrick Steinhardt wrote:
> It is quite a common use case that one wants to split up one commit into
> multiple commits by moving parts of the changes of the original commit
> out of it into a separate commit. This is quite an involved operation
> though:
> 
>   1. Identify the commit in question that is to be dropped.
> 
>   2. Perform an interactive rebase on top of that commit's parent.
> 
>   3. Modify the instruction sheet to "edit" the commit that is to be
>      split up.
> 
>   4. Drop the commit via "git reset HEAD~".
> 
>   5. Stage changes that should go into the first commit and commit it.
> 
>   6. Stage changes that should go into the second commit and commit it.
> 
>   7. Finalize the rebase.
> 
> This is quite complex, and overall I would claim that most people who
> are not experts in Git would struggle with this flow.
> 
> Introduce a new "split" subcommand for git-history(1) to make this way
> easier. All the user needs to do is to say `git history split $COMMIT`.
> From hereon, Git asks the user which parts of the commit shall be moved
> out into a separate commit and, once done, asks the user for the commit
> message. Git then creates that split-out commit and applies the original
> commit on top of it.
> 
> Signed-off-by: Patrick Steinhardt <[email-masked]>
> ---
>  Documentation/git-history.adoc |  59 ++++++++
>  builtin/history.c              | 245 +++++++++++++++++++++++++++++++++
>  t/meson.build                  |   1 +
>  t/t3452-history-split.sh       | 304 ++++++++++++++++++++++++++++++++++++++
+++
>  4 files changed, 609 insertions(+)
> 
> diff --git a/Documentation/git-history.adoc b/Documentation/git-history.adoc
> index 6e8b4e1326..f0f1f2a093 100644
> --- a/Documentation/git-history.adoc
> +++ b/Documentation/git-history.adoc
> @@ -10,6 +10,7 @@ SYNOPSIS
>  [synopsis]
>  git history drop [<options>] <revision>
>  git history reorder [<options>] <revision> --(before|after)=<revision>
> +git history split [<options>] <revision> [--] [<pathspec>...]

I just realized that there are no other <options> available for the first two 
commands! So maybe simplify the synopsis for the time being.

The --message is specific to split, so maybe also cite is specifically here.
I 
> 
>  DESCRIPTION
>  -----------
> @@ -47,6 +48,26 @@ reorder <revision> (--before=<revision>|--
after=<revision>)::
>  	commit. The commits must be related to one another and must be
>  	reachable from the current `HEAD` commit.
> 
> +split <revision> [--message=<message>] [--] [<pathspec>...]::

missing backticks. Also the order of options and <commit> are different from 
the general synopsis. Is this order allowed?

> +	Interactively split up the commit into two commits by choosing

You can use the placeholder in this sentence: "Interactively split up 
<commit>..."

> +	hunks introduced by it that will be moved into the new split-out
> +	commit. These hunks will then be written into a new commit that
> +	becomes the parent of the previous commit. The original commit
> +	stays intact, except that its parent will be the newly split-out
> +	commit.
> ++
> +The commit message of the new commit will be asked for by launching the
> +configured editor. Authorship of the commit will be the same as for the
> +original commit.
> ++

I guess this only happens if --message is not passed?

> +If passed, _<pathspec>_ can be used to limit which changes shall be split 
out
> +of the original commit. Files not matching any of the pathspecs will remain
> +part of the original commit. For more details about the _<pathspec>_ 
syntax,
> +see the 'pathspec' entry.

You may have meant: 
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].

> ++
> +It is invalid to select either all or no hunks, as that would lead to
> +one of the commits becoming empty.
> +
>  EXAMPLES
>  --------
> 
> @@ -88,6 +109,44 @@ f44a46e third
>  bf7438d first
>  ----------
> 
> +* Split a commit.
> ++
> +----------
> +$ git log --stat --oneline
> +3f81232 (HEAD -> main) original
> + bar | 1 +
> + foo | 1 +
> + 2 files changed, 2 insertions(+)
> +
> +$ git history split HEAD --message="split-out commit"
> +diff --git a/bar b/bar
> +new file mode 100644
> +index 0000000..5716ca5
> +--- /dev/null
> ++++ b/bar
> +@@ -0,0 +1 @@
> ++bar
> +(1/1) Stage addition [y,n,q,a,d,e,p,?]? y
> +
> +diff --git a/foo b/foo
> +new file mode 100644
> +index 0000000..257cc56
> +--- /dev/null
> ++++ b/foo
> +@@ -0,0 +1 @@
> ++foo
> +(1/1) Stage addition [y,n,q,a,d,e,p,?]? n
> +
> +$ git log --stat --oneline
> +7cebe64 (HEAD -> main) original
> + foo | 1 +
> + 1 file changed, 1 insertion(+)
> +d1582f3 split-out commit
> + bar | 1 +
> + 1 file changed, 1 insertion(+)
> +----------
> +
> +
>  CONFIGURATION
>  -------------