Rebasing with Git
If I could use the magic wand for the 4th time, I would improve
how git rebase works.
I do love workflows based on rebase and, coming from CVS and
Subversion, I still think rebase is one of the killer features of
Git. But I cannot help thinking git rebase is broken.
That's a bold claim. Let me unpack it.
Conflicts
Rebase is fantastic until it's not. Think about it. Git is designed to be very safe and conservative:
- It treats your filesystem as sacred. Unless you explicitly tell it
to
git addfiles, it diligently keeps its hands off them. It won't touch your files unless you say so. - Internally, it is strictly append-only. It never deletes info. No matter the operation you perform, it's never destructive; there's always a way to revert what you did.
This behavior instills serenity. You can work relaxed; your code is in trusted hands. You can happily jump back and forth in your history, move files left and right: Git is always there, solid and stable, to support your needs.
Danger Mode
Until you rebase and there's a conflict. Then Git enters danger mode. It basically stops working, as if it's in panic, and offers you only 2 ways to exit:
- Either you
git rebase --abort. - Or you solve the conflicts, now!, and in the exact order it tells you.
You cannot do anything else. It does not even know, let alone tell you, how many conflicts you'll face. It just stopped at the first conflicted commit and handed it over to you.
While in this panic mode, Git does not work. You cannot jump back and forth in your history anymore. If you think that visiting another commit would help you fix the code, forget it: Git won't let you. You cannot cherry-pick, you cannot bisect. What if you have an urgency (like a hotfix to release) while you are struggling with a difficult conflict resolution? Can you pause the rebase, work, and recover your work later? Nope.
Your precious project does not work anymore, and Git quit supporting you exactly when you needed its help the most.
I know it's less dramatic than this; there are always ways to recover. No wonder many people avoid rebasing and stick with the more comforting merge.
Can we de-escalate this?
If I could ask for the moon, I would like a tool that:
- Tells me at once all the conflicts a rebase will encounter.
- Does not stop working just because of conflicts.
- Lets me keep working on important stuff, postponing the conflict resolution.
- Lets me solve conflicts both by editing files and also via whatever feature may help.
Jujutsu is that tool. You will see in the next pages: conflicts are first-class citizens and can be manipulated in far more convenient ways than just editing a file in an emergency. No stress, no drama. Jujutsu keeps working during conflicts, with all its features available.
And you will use them! Because it opens some interesting scenarios that are hardly conceivable with Git. Have you ever considered solving conflicts by editing a commit other than the ones being rebased? Or by performing another rebase (a rebase within a rebase!).
It's much simpler than it sounds. You'll see in a few pages.
In practice
Here's an experiment you can try. Next time you need to rebase a
branch, make a copy of your repo (better safe than sorry, as long as
you are a jj-newbie), jj git init it then try:
jj rebase -s <FROM> -o <TO>
where:
<FROM>where to cut.<TO>where to paste.
For example, say you want to move the branch 3-4-5-6 on top of 11:
jj log
○ 11 <---- paste
○ 10
○ 9
│ ○ 8
│ ○ 7
├─╯
│ ○ 6
│ ○ 5
│ ○ 4
│ ○ 3 <---- cut
├─╯
○ 2
○ 1
Then:
jj rebase -s 3 -o 11
will get you to:
○ 6
○ 5
○ 4
○ 3
○ 11 <---- paste
○ 10
○ 9
│ ○ 8
│ ○ 7
├─╯
○ 2
○ 1
With the same ease you can select other cut/paste points, even in the middle of the history tree:
○ 11
○ 10 <---- paste
○ 9
│ ○ 8
│ ○ 7
├─╯
│ ○ 6
│ ○ 5
│ ○ 4 <---- cut
│ ○ 3
├─╯
○ 2
○ 1
jj rebase -s 4 -o 10
○ 11
│ ○ 6
│ ○ 5
│ ○ 4
├─╯
○ 10 <---- paste
○ 9
│ ○ 8
│ ○ 7
├─╯
│ ○ 3
├─╯
○ 2
○ 1
And if there are conflicts? jj log will tell you where.
○ 11
│ × 6 <---- conflict
│ × 5 <---- conflict
│ ○ 4
├─╯
○ 10
○ 9
│ ○ 8
│ ○ 7
├─╯
│ ○ 3
├─╯
○ 2
○ 1
Then you can fix the conflicts where they are:
jj edit 5
It's likely that fixing the conflict in 5 will propagate the
resolution to 6. Otherwise, you can continue with:
jj edit 6
In any case, you can count on jj undo.
In practice though, you will probably encounter confusing scenarios and need a few more tools.
So, my recommendation: play with jj log, jj rebase and jj undo
in a safe copy of a real repository but, please, don't stop reading
here; there are a few other things you will love to learn!