<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/custom-pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0"><channel><title>Kristoffer Balintona — #Jujutsu</title><description>Entries tagged with &quot;Jujutsu&quot;</description><link>https://kristofferbalintona.me/</link><language>en-us</language><image><url>https://kristofferbalintona.me/favicon-rss.png</url><title>Kristoffer Balintona — #Jujutsu</title><link>https://kristofferbalintona.me</link></image><item><title>Jujutsu (jj) VCS workflows and the convenience of its “operation log”</title><link>https://kristofferbalintona.me/posts/202503270835/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202503270835/</guid><description>&lt;p&gt;Over the last month or two I’ve been trying out the relatively new &lt;a href=&quot;https://jj-vcs.github.io/jj/latest/&quot;&gt;jujutsu&lt;/a&gt; version control system (VCS) — and loving it. At first, I discovered it and read their &lt;a href=&quot;https://github.com/jj-vcs/jj&quot;&gt;GitHub README&lt;/a&gt; with curiosity but skepticism. Then I sought a few &lt;a href=&quot;https://www.youtube.com/results?search_query=what+is+jujutsu+vcs&quot;&gt;YouTube videos&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; demonstrating jj in action, and &lt;a href=&quot;https://jj-vcs.github.io/jj/latest/&quot;&gt;a tutorial&lt;/a&gt; for a text-based reference. I became very interested. I initialized a jj repo in one of my small git projects and played around. Since then, I’ve migrated all of my personal repositories to jj, and use jj for practically everything.&lt;/p&gt;
&lt;p&gt;From the time I’ve spent with jj, I’ve felt myself sliding into some general workflows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;jj squash&lt;/code&gt; workflow&lt;br /&gt;
In git, this would be a workflow where you make a commit and continually amend/extend that commit until its intended goal is completed.
&lt;ol&gt;
&lt;li&gt;Make progress toward a desired goal.&lt;/li&gt;
&lt;li&gt;Commit (&lt;code&gt;jj commit&lt;/code&gt;, or &lt;code&gt;jj new&lt;/code&gt; then &lt;code&gt;jj describe -m &quot;...&quot;&lt;/code&gt;) with a message describing this unit of work.&lt;/li&gt;
&lt;li&gt;Continue making changes.&lt;/li&gt;
&lt;li&gt;Squash (perhaps interactively: &lt;code&gt;jj squash -i&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#fn-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;) new changes until the desired goal is accomplished.&lt;/li&gt;
&lt;li&gt;Maybe change the description of the previous commit commit.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Work in the working copy
&lt;ol&gt;
&lt;li&gt;Envision a goal for a new commit. Express that into the description of the working copy commit: &lt;code&gt;jj describe -m &quot;...&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Work until much of that goal is met.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jj new&lt;/code&gt; to work on the next goal. Or &lt;code&gt;jj split -i&lt;/code&gt; if some of the changes in the working copy belong in the next commit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jj edit&lt;/code&gt; to hop between commits and work on each until completion. Perhaps &lt;code&gt;jj new -A ...&lt;/code&gt; one or more times when when you don’t want certain changes in a commit: make changes across however many of those commits, then &lt;code&gt;jj squash&lt;/code&gt; them all into your original commit when you’re happy. (You’re basically creating a new git branch!)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Concurrent commits workflow&lt;br /&gt;
Work on several commits simultaneously, using combinations of &lt;code&gt;jj squash&lt;/code&gt;, &lt;code&gt;jj new&lt;/code&gt;, and &lt;code&gt;jj rebase&lt;/code&gt; to make make reversible changes while having a clean &lt;code&gt;jj log&lt;/code&gt; at the end. In essence, this is point (3.4) above but with room for added complexity.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m not a VCS expert, and my projects are small, but I’ve gravitated to (1) and (2) without feeling any mental strain of keeping track of where this and that change is and what CLI operations avoid x problem or y merging conflict (which, by the way, jj permits! Jujutsu treats conflicts as first-class, so conflicts and their resolutions percolate through ancestors and descendants without problem.)&lt;sup&gt;&lt;a href=&quot;#fn-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Perhaps the most exciting part of using jj is fearlessly making changes and experimenting. This has been an extraordinary boon for my learning about how to use jj in accordance to its VCS concepts. The reason is jj’s operation log (&lt;code&gt;jj op log&lt;/code&gt;) and the ability to &lt;strong&gt;revert back to &lt;em&gt;any&lt;/em&gt; past repository state&lt;/strong&gt; (&lt;code&gt;jj op restore OPERATION_ID&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;jj op restore&lt;/code&gt;, I can merge branches, create conflicts, resolve conflicts, mess up… then go back as if it never happened. I can make sweeping repository changes without fear! In git, I’d be walking on egg shells, worried about the potential to ruin the entire state of my local repository if I’m not careful…&lt;/p&gt;
&lt;p&gt;I’d definitely recommend trying jj out if you haven’t already! Easily turn a git repo into a jj repo with a git backend: &lt;code&gt;jj git init \-\-colocate&lt;/code&gt;.&lt;/p&gt;
&lt;footer&gt; &lt;h2&gt;Footnotes &lt;a href=&quot;#footnotes-heading&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;[1]&lt;/a&gt; &lt;div&gt; &lt;p&gt;I found &lt;a href=&quot;https://www.youtube.com/watch?v=bx_LGilOuE4&quot;&gt;this talk&lt;/a&gt; by the originator of jujutsu, Martin von Zweigbergk, a senior software engineer at Google, especially insightful with respect to the technical merits of jj over git. If jj is meant to potentially eventually handle Google’s gigantic monorepo (86 terabytes of data, ~2 billion lines of code across 9 million source files!), then surely there’s something to it! The talk justifies the existence of jj.&lt;/p&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;  &lt;a href=&quot;#fnref-2&quot;&gt;[2]&lt;/a&gt; &lt;div&gt; &lt;p&gt;Without the &lt;code&gt;-u&lt;/code&gt; flag, &lt;code&gt;jj squash -i&lt;/code&gt; effectively behaves like &lt;code&gt;git commit \-\-amend&lt;/code&gt; when your working copy has a description (e.g., with &lt;code&gt;jj desc -m &quot;...&quot;&lt;/code&gt; or if you &lt;code&gt;jj edit&lt;/code&gt; to a past commit). Without a commit, &lt;code&gt;jj squash -i&lt;/code&gt; is like &lt;code&gt;git commit \-\-amend \-\-no-edit&lt;/code&gt;.&lt;/p&gt;  &lt;a href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;  &lt;a href=&quot;#fnref-3&quot;&gt;[3]&lt;/a&gt; &lt;div&gt; &lt;p&gt;A great resource on the matter of “conflicts as first-class” is &lt;a href=&quot;https://youtu.be/LV0JzI8IcCY?si=n0xrGZfRx6vZGNmr&amp;amp;t=553&quot;&gt;this talk&lt;/a&gt; by the mind behind jj.&lt;/p&gt;  &lt;a href=&quot;#fnref-3&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/footer&gt;</description><pubDate>Thu, 27 Mar 2025 08:35:00 GMT</pubDate><category>VCS</category><category>Tips and Tricks</category><category>Jujutsu</category></item></channel></rss>