On 07/09/2025 07:46, Elijah Newren wrote:
On Thu, Sep 4, 2025 at 11:43 PM 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.
Fantastic, thanks for working on this
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.
- 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.
Cool, I had been thinking of adding some jj-like functionality as
well, to git-replay in my case, though I was more interested in fixing
up the infrastructure to handle replaying merges sanely first.
Interesting, one of the questions I have about this series is whether it
makes sense to use the sequencer or extend git-replay. I do like the
idea and name "history" though. I've been using a wrapper around
git-rebase that I call "git-rewrite" that lets me amend, reword, or drop
commits and rewrite all the branches that contain the modified commit
for quite a while now. I find amending the commit directly rather than
using fixup commits and then squashing much more convenient and it
avoids the problem of the fixup having conflicts when you try and squash
it (though not the conflicts caused by amending the commit of course).
One feature I particularly like, which we might want to add to "git
history" in the future, is being able to specify a filename, line pair
instead of a commit name. The script then uses "git diff" to map the
line number to the file in HEAD and "git blame" to find the relevant
commit. This makes it easy to start a rewrite directly from my editor
when I see something that needs fixing up.
If we do want to use the sequencer then I think we need to decide
exactly what behavior we want from the new command with regard to
running hooks and copying commit headers and implement that behavior
rather than just accepting the status quo which is largely a historical
accident. I would suggest that for commits that we're not modifing we
should not be running any hooks. For commits that are reworded we should
be running the "commit-msg" hook and possibly "prepare-commit-msg" as
well but no others. Where we're amending the commit content or splitting
a commit then we should be running the "pre-commit" hook as well.
Currently "git-replay" copies any extra commit headers when it creates a
new commit whereas "git-rebase" does not. There is some discussion at
[1] where people were pushing back against copying extra headers by default.
I think it would make sense in the long run to update all the branches
that contain the modified commit. To do that we can use the sequencer's
"update-ref" command. To that end I think we should add a new entry
point to the sequencer that takes a todo list rather than a list of
commits to pick. That would also allow us to implement the "split"
command in the sequencer and reuse the infrastructure that already
exists for rewording commits. The way this series is currently
implemented makes it hard to extend in the future because it is based
around cherry-picking commits rather than creating a todo list for the
sequencer to execute.
Thanks
Phillip
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).
- `git history split` takes a commit and splits it into two. This is
basically the same as jj-split(1).
>>>> 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.
- `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.
So, this brings up a question. Should we have git-rebase &
git-cherry-pick & git-replay & git-history, or should we consolidate?
I had envisioned having git-replay consolidate both cherry-pick and
rebase functionality into one (then got pulled away by combination of
work reassgniment & multiple life crises hitting at once taking my
focus away for quite some time). But now we're going in the other
direction. And further along that other direction is another extreme
-- just having these be top-level commands, e.g. "git reorder", "git
split", etc.
In a separate conversation we had (and I hope I'm paraphrasing
correctly; if not please correct me), you mentioned you wanted
git-history to be the home of history rewriting, and viewed git-replay
as just a server side thing (whereas I created git-replay specifically
as a user-focusing thing and then Christian changed it into a
server-side thing since that part was complete and enough for his
purposes). But if git history is the home of history editing, how far
does that go? Do we have a "git history reset"? "git history
commit"? "git history fast-export/fast-import" "git history
filter-repo"? Or is it just the home for certain kinds of history
rewriting operations? If so, which ones?
That all said, I'm a big fan of the idea of incorporating more of jj
capabilities, and you clearly marked the command as experimental
(thanks!), which leave us room to adjust later if we don't like this
path. So I don't want to serve as a roadblock, I just think it's a
useful conversation to have...