git/list[1] front-page[2] threads[3] people[4] search[5] about
 

RFC: new git-splice subcommand for non-interactive branch splicing

From
Adam Spiers <git@adamspiers.org>
Date
May 27, 2016, 14:08 UTC
Message-ID
<20160527140811.GB11256@pacific.linksys.moosehall>
Hi all,

I finally got around to implementing a new git subcommand which I've wanted for quite a while. I've called it git-splice.

Description -----------

git-splice(1) non-interactively splices the current branch by removing a range of commits from within it and/or cherry-picking a range of commits into it. It's essentially just a glorified wrapper around cherry-pick and rebase -i.

Usage -----

Examples:
    # Remove commit A from the current branch
    git splice A^!
    # Remove commits A..B from the current branch
    git splice A..B
    # Remove commits A..B from the current branch, and cherry-pick
    # commits C..D at the same point
    git splice A..B C..D
    # Cherry-pick commits C..D, splicing them in just after commit A
    git splice A C..D
    # Remove first commit mentioning 'foo', and insert all commits
    # in the 'elsewhere' branch which mention 'bar'
    git splice --grep=foo -n1 HEAD -- --grep=bar HEAD..elsewhere
    # Abort a splice which failed during cherry-pick or rebase
    git splice --abort
    # Resume a splice after manually fixing conflicts caused by
    # cherry-pick or rebase
    git splice --continue

N.B. Obviously this command rewrites history! As with git rebase, you should be aware of all the implications of history rewriting before using it.

Code ----

Currently this is in alpha state:
  https://github.com/git/git/compare/master...aspiers:splice

and I reserve the right to rewrite the history of that branch in the near future ;-)

I realise that the code does not yet conform to the coding standards of the git project. For example, it relies on non-POSIX bash features, like arrays. I would be happy to fix this if there is a chance git-splice might be accepted for inclusion within the git distribution. (Presumably contrib/ is another possibility.) Also, I haven't yet written a proper man page for it.

Motivation ----------

I wrote git-splice as the next step in the journey towards being able to implement a tool which automatically (or at least semi-automatically) splits a linear sequence of commits into a commit graph where ancestry exactly mirrors commit "dependency".[0] In other words, in this commit graph, a commit B would have commit A as an ancestor if and *only* if commit B cannot cleanly apply without A already being present in the branch. As a corollary, if commit F depends on D and E, but D and E are mutually independent, F would need to depend on a merge commit which contains D and E.

Such a tool could be useful for a few reasons. Firstly, large patch series are much harder to review than single commits or small patch series, but typical development workflows often lead to large patch series.

For example, if I work privately on a new feature for some hours / days / weeks, I will typically amass a bunch of commits which are not all directly related to the new feature: there are often refactorings, fixes for bugs discovered during development of the new feature, etc.

I doubt I'm the only git user not disciplined enough to maintain neat branch organization for the whole of a long period of hacking! i.e. religiously maintaining one branch per bugfix, one branch per refactoring, and one branch for the new feature.[1] Typically, tidying up the branches comes a bit later, when I want to start feeding stuff upstream for review.

Therefore being able to reduce the effort involved with breaking a large patch series into smaller related chunks seems potentially very useful.

As well as making reviews smaller easier, this allows both the reviews and any corresponding CI to proceed in a more parallelized fashion.

Some review systems can implicitly discourage reviews of large patch series, by treating each commit as a review in its own right and/or not providing sophisticated support for patch series. Gerrit is one example; gitlab and GitHub are counter-examples.

I'm sure there are other use cases which I didn't think of yet.

Next steps, and the future --------------------------

Obviously, I'd welcome thoughts on whether it would make sense to include this in the git distribution.

In the longer term however, I'd like to write two more subcommands:
  - git-transplant(1) which wraps around git-splice(1) and enables
    easy non-interactive transplanting of a range of commits from
    one branch to another.  This should be pretty straightforward
    to implement.
  - git-explode(1) which wraps around git-transplant(1) and
    git-deps(1), and automatically breaks a linear sequence of commits
    into multiple smaller sequences, forming a commit graph where
    ancestry mirrors commit dependency, as mentioned above.  I expect
    this to be more difficult, and would probably write it in Python.
    Ideally, this tool would also be able to integrate with other
    workflow management tools[1] in order to effectively create /
    manage topic branches and track dependencies between them.

Eventually, the utopia I'm dreaming about would become a reality and look something like this:

    git checkout -b new-feature
    while in_long_frenzied_period_of_hacking; do
        # don't worry too much about branch maintenance here, just hack
        git add ...
        git commit ...
    done
    # Break lots of commits from new-feature into new topic branches:
    git explode
    # List topic branches
    git work list
    # Manually complete tidy-up of those branches
    git push ...
    git send-email ...
Feedback on any of this is very welcome!

Thanks, Adam

[0] https://github.com/aspiers/git-deps/#user-content-use-case-2-splitting-a-patch-series
    This type of dependency could be described as textual or syntactic or
    lexical, and is automatically detected by git-deps:
        https://github.com/aspiers/git-deps/
    which I wrote a couple of years ago and previously announced on this list:
        http://thread.gmane.org/gmane.comp.version-control.git/262000/focus=262606
    Of course, this is a somewhat naive approach in that it has no
    awareness of semantic dependencies, e.g. commit A changing file X
    in a way which only makes sense if commit B changing file Y is
    already present.  However in my experience it's still a useful
    start in the right direction, saving a lot of time by detecting
    the "obvious" dependencies, and often revealing dependencies which
    I would have otherwise missed.
[1] There are tools which can help with this, e.g. topgit, git-flow,
    and gitwork, which IMHO is particularly interesting.
Next: Johannes Schindelin
Message 1 of 6 in “RFC: new git-splice subcommand for non-interactive branch splicing”
  1. Adam SpiersMay 27, 2016
  2. Johannes SchindelinMay 27, 2016
  3. Adam SpiersMay 27, 2016
  4. Johannes SchindelinMay 28, 2016
  5. Adam SpiersMay 28, 2016
  6. RFC: new git-transplant subcommand for non-interactively moving commits between branchesAdam Spiers, May 30, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.