On Tue, Aug 19, 2025 at 3:57 AM Patrick Steinhardt <ps@xxxxxx> wrote: > > Hi, > > over recent months I've been playing around with Jujutsu quite > frequently. While I still prefer using Git, there's been a couple > features in it that I really like and that I'd like to have in Git, as > well. > > A copule of these features relate to history editing. Most importantly, > I really dig the following commands: > > - jj-abandon(1) to drop a specific commit from your history. It also rebases all descendants on top of the parent(s) of the abandoned commit(s). Branches pointing to the rebased commits are also repointed. So is the working copy if it points to a rebased commit (the closest equivalent in Git would be HEAD). Do you plan to make all the `git history` commands behave that way too? > > - jj-absorb(1) to take some changes and automatically apply them to > commits in your history that last modified the respective hunks. > > - jj-split(1) to split a commit into two. > > - jj-new(1) to insert a new commit after or before a specific other > commit. > > Not all of these commands can be ported directly into Git. jj-new(1) for > example doesn't really make a ton of sense for us, I'd claim. But some > of these commands _do_ make sense. > > I thus had a look at implementing some of these commands in Git itself, > where the result is this patch series. Specifically, the following > commands are introduced by this patch series: > > - `git history drop` to drop a specific commit. This is basically the > same as jj-abandon(1). > > - `git history reorder` to reorder a specific commit before or after > another commit. This is inspired by jj-new(1). It seems more similar to `jj rebase -r X -A/-B Y`, which rips X out of the graph and inserts it after/before Y. Just FYI; I'm not asking for any changes. > > - `git history split` takes a commit and splits it into two. This is > basically the same as jj-split(1). FYI, the default behavior of `jj split` is to split the commit into parent and child, but there's also `-A/-B X` to take the selected changes and insert them after/before X, or `-d X` to put them on top of X. > > If this is something we want to have I think it'd be just a starting > point. There's other commands that I think are quite common and that > might make sense to introduce eventually: > > - An equivalent to jj-absorb(1) would be awesome to have. > > - `git history reword` to change only the commit message of a specific > commit. FYI, `jj describe` can also change the commit message of multiple commits at once (e.g. `jj describe main..@` to edit your current chain of commits). It concatenates each description with some separators between in that case so you can update them all at once in your $EDITOR. I'm letting you know these things in case it impacts planning for the CLI arguments. > > - `git history squash` to squash together multiple commits into one. > > In the end, I'd like us to learn from what people like about Jujutsu and > apply those learnings to Git. We won't be able to apply all learnings > from Jujutsu, as the workflow is quite different there due to the lack > of the index. But other things we certainly can apply to Git directly. Perhaps the simplest thing to copy is revsets (which we copied from Mercurial). See https://jj-vcs.github.io/jj/latest/revsets/. It's not at all simple to implement, but I think it should be relatively simple from a UX point of view because it can probably be done in a mostly backwards compatible way. > > Note: This patch series currently builds on the cherry-pick infra. > As such, when one hits a merge conflict one needs to `git cherry-pick > --continue`, which is quite suboptimal. I didn't want to overpolish this > series before getting some feedback, but it is something I'll fix in > subsequent versions. Furthermore, the command for now bails out in the > case where there's any merge commits in the history that is being > rewritten. This is another restriction that can be lifted in the future. > > Thanks! > > Patrick > > --- > Patrick Steinhardt (11): > sequencer: optionally skip printing commit summary > sequencer: add option to rewind HEAD after picking commits > cache-tree: allow writing in-memory index as tree > builtin: add new "history" command > builtin/history: implement "drop" subcommand > builtin/history: implement "reorder" subcommand > add-patch: split out header from "add-interactive.h" > add-patch: split out `struct interactive_options` > add-patch: remove dependency on "add-interactive" subsystem > add-patch: add support for in-memory index patching > builtin/history: implement "split" subcommand > > .gitignore | 1 + > Documentation/git-history.adoc | 159 ++++++++++ > Documentation/meson.build | 1 + > Makefile | 1 + > add-interactive.c | 151 +++------ > add-interactive.h | 43 +-- > add-patch.c | 271 ++++++++++++++-- > add-patch.h | 61 ++++ > builtin.h | 1 + > builtin/add.c | 22 +- > builtin/checkout.c | 7 +- > builtin/commit.c | 16 +- > builtin/history.c | 691 +++++++++++++++++++++++++++++++++++++++++ > builtin/reset.c | 16 +- > builtin/stash.c | 46 +-- > cache-tree.c | 5 +- > cache-tree.h | 3 +- > commit.h | 2 +- > git.c | 1 + > meson.build | 1 + > sequencer.c | 36 ++- > sequencer.h | 4 + > t/meson.build | 5 +- > t/t3450-history-drop.sh | 127 ++++++++ > t/t3451-history-reorder.sh | 218 +++++++++++++ > t/t3452-history-split.sh | 304 ++++++++++++++++++ > 26 files changed, 1947 insertions(+), 246 deletions(-) > > > --- > base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0 > change-id: 20250819-b4-pks-history-builtin-83398f9a05f0 > >