Defeating Git Rigour Fatigue with Jujutsu

ikesau1 pts0 comments

defeating git rigour fatigue with jujutsu | ikesau.codefeating git rigour fatigue with jujutsu<br>computers<br>This post assumes a basic level of familiarity with the<br>jujutsu version control system. If you haven't used jujutsu, you'll still get the gist of the idea, but I<br>recommend reading<br>Steve's Jujutsu tutorial<br>after.When developing a large feature, writing Good Commits is hard.<br>And by Good Commits, I mean something like:<br>define types<br>add DB functions<br>server CRUD<br>client API<br>client UI<br>This allows reviewers to step through your pull request in small bites, with<br>each set of changes scoped to a single aspect of the feature.<br>So, naturally, here's what I do instead:<br>define types<br>add DB functions<br>WIP test code<br>server CRUD<br>client API and UI<br>fix DB function<br>fix UI bug<br>refactor CRUD<br>fix another UI bug<br>Latter commits overwrite work that was done in earlier commits and the story<br>breaks.⚖️<br>Jujutsu makes it easier to hop around commits and iterate quickly on<br>compartmentalized changesets, but it's still effortful and I get averse.🤖<br>jj absorb helps somewhat, as does<br>jj squash -i, but they both have their downsides:<br>absorb assigns the changes based on whichever<br>previous commit most recently touched those files, which sometimes doesn't<br>actually correspond to which commit should own these particular<br>changes.<br>squash can get you stuck in merge conflict hell<br>if your boundaries aren't extremely clean.<br>So here's a solution to this problem of "git rigour fatigue" that I've come<br>up with.<br>For this example, let's represent commits visually. Imagine<br>red represents<br>changes to the type definitions,<br>blue to the UI<br>and so on:

Mayhem. Our first commit is a mix of<br>red and<br>blue. We touch<br>red in multiple<br>places!<br>To fix this, let's create our ideal commit history first, using<br>jj new -B messy-first -m 'red'

Then we can do the rest. (I switch to<br>jj new -A red -m 'blue' at this point)

Then we squash all the commits with actual changes in them into one with<br>jj squash --from messy-first..messy-last --into messy-first

Then we use<br>jj squash -i --from --into red<br>and pick out the red changes, putting them into the red box:

And so on:

Eventually everything's in the right place and the "everything commit" is<br>empty.

For large features, I find this workflow far easier than having to maintain<br>strict git rigour for the lifecycle of the feature's development. It's<br>easier to make improvised commits with temp debugging state in them and tidy<br>it all up in one sweep at the end.<br>preemptions:<br>I don't have a good name for this technique. "Doing Commits Like A Big<br>Pile Of Laundry", perhaps?<br>This is different from (and, imo, superior to)<br>jj split:With split, if I miss a hunk that should have<br>been in red,<br>I have to split again and squash.<br>This technique more easily allows sorting the easiest hunks at the<br>beginning without worrying about how it will effect the commit<br>sequencing.

This reason why doing it all at the end is (often) better than using<br>jj squash -i as you go is because the final state<br>of the everything commit is guaranteed to not have any conflicts. Creating<br>a new "fix red and green" commit and interactively squashing that into<br>your red and green commits might break your blue commit if it happens to<br>touch one of the affected files.<br>A downside to this technique is that there's no guarantee that every<br>commit will compile, which might be a dealbreaker.

commits commit jujutsu squash changes rigour

Related Articles