<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>thisalex.com</title>
    <subtitle>Website of Alex Zakhlestin</subtitle>
    <link rel="self" type="application/atom+xml" href="https://thisalex.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://thisalex.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-01-27T00:00:00+00:00</updated>
    <id>https://thisalex.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Taming Claude Code</title>
        <published>2026-01-27T00:00:00+00:00</published>
        <updated>2026-01-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://thisalex.com/posts/claude-taming/"/>
        <id>https://thisalex.com/posts/claude-taming/</id>
        
        <content type="html" xml:base="https://thisalex.com/posts/claude-taming/">&lt;p&gt;&lt;em&gt;I was recently giving masterclasses for colleagues and friends about Claude Code and realized it makes sense to share some tips I show there.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;note-container&quot;&gt;
  
    &lt;div class=&quot;note-header&quot;&gt;
      
        &lt;div class=&quot;note-icon&quot;&gt;
        &lt;p&gt;WARNING&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
      
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;note-content&quot;&gt;
      &lt;p&gt;⚠️ Target audience: Senior Developers. Coding agent is not a suitable tool for beginners.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
  
&lt;&#x2F;div&gt;
&lt;p&gt;&quot;Computers are good at following instructions, but not at reading your mind.&quot; © Donald Knuth&lt;&#x2F;p&gt;
&lt;p&gt;Many different speakers would tell you that you have to become a manager to work with coding agents. It frightens a lot of programmers. The good news is: That is a lie! Such an approach might work if all you need is a crude prototype, but it would probably fail dramatically if you persist. A much better strategy is to take the role of a &lt;strong&gt;systems analyst&lt;&#x2F;strong&gt; or &lt;strong&gt;software architect&lt;&#x2F;strong&gt;. Coding agents do not have expertise to choose a good solution. They choose the most common solution for the context they have. And our goal is to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Provide the agent with more relevant context&lt;&#x2F;li&gt;
&lt;li&gt;Guide the agent toward a better solution&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Doing this interactively for each of the tasks is extremely tiresome, so it is a good idea to reuse as much as possible. And Claude Code has some very good tools for such reuse.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;skills&quot;&gt;Skills&lt;&#x2F;h2&gt;
&lt;p&gt;Think about every practice you try to enforce on your projects. You should probably make a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;skills&quot;&gt;Skill&lt;&#x2F;a&gt; for it. A Skill is a very efficient approach for transferring knowledge into your agentic alter-ego. It is a markdown document accompanied by additional files which can include both additional documentation and pre-built tools for specific tasks. The main markdown file has a short description text which will always be present in the context. The agent is instructed to check its current objective with this description and it will deep-dive if there is a match. You can encode your VCS&#x2F;branching preferences in one skill (&lt;em&gt;my local skill encodes my personal rules for using &lt;a href=&quot;&#x2F;tags&#x2F;jujutsu&quot;&gt;jj&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;) and an approach to writing code-comments in another skill. My toolset has skills for the way I want python-tools to be created (and Claude writes a lot of temporary python tools!) and how reactivity should be done in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dioxuslabs.com&#x2F;&quot;&gt;Dioxus&lt;&#x2F;a&gt; apps. I have several dozen of them and add more constantly.&lt;&#x2F;p&gt;
&lt;p&gt;And while some skills are shareable, the majority of them depends on your personal tastes and preferences and just wouldn&#x27;t make a lot of sense for anyone else. And that is a good thing. Don&#x27;t rush to look for curated lists and marketplaces of skills. Create your own.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;claude-code-can-configure-itself&quot;&gt;Claude Code can configure itself&lt;&#x2F;h2&gt;
&lt;p&gt;And when I say &quot;create your own&quot;, I don&#x27;t mean to literally write them by hand. Jump to the meta-level: tell Claude Code to do it for you.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Take a look at the recent Claude Code docs for writing skills and create a skill for …. Ask me questions about how I want it to work.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&quot;Ask me questions&quot; is a very important part. You don&#x27;t want Claude to make decisions on your behalf. You want it to get details from you. As long as you know what to ask beforehand — write it at once, but oftentimes you can&#x27;t quite find the correct words — that&#x27;s OK. Claude is a fine interviewer. And you can do many iterations of questions gradually increasing the amount of detail. In some extreme cases I even suggest you start the process by making &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;how-claude-code-works#explore-before-implementing&quot;&gt;a plan&lt;&#x2F;a&gt; for a detailed interview: Ask Claude to do some research and prepare a file with 20 questions and designated places for your answers. It will require some effort, but the result would be worth it.&lt;&#x2F;p&gt;
&lt;p&gt;Same thing applies to generic instructions:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mention &#x2F;a, &#x2F;b, and &#x2F;c skills in your global CLAUDE.md. I want these to be very visible to agents.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;knowledge-base&quot;&gt;Knowledge Base&lt;&#x2F;h2&gt;
&lt;p&gt;I suggest everyone find a way to take notes about things you find interesting. It can be as simple as a collection of text&#x2F;markdown files or as complicated as an automated pipeline which summarizes the articles which you find useful. The important part is to teach Agents how to find information there (yes, that&#x27;s one more skill I suggest you create). Being able to reference something local without resorting to web-search capabilities is extremely useful:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want you to apply the approach from that article by Martin Fowler I read last week&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;A habit of information hoarding finally pays off 🤪&lt;&#x2F;p&gt;
&lt;div class=&quot;note-container&quot;&gt;
  
    &lt;div class=&quot;note-header&quot;&gt;
      
        &lt;div class=&quot;note-icon&quot;&gt;
        &lt;p&gt;anticipation&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
      
    &lt;&#x2F;div&gt;
    &lt;div class=&quot;note-content&quot;&gt;
      &lt;p&gt;&lt;em&gt;p.s. You probably noticed that I didn&#x27;t say anything about project-level CLAUDE.md files — that was intentional. I find them to be less useful than most people consider them to be. I guess I should write a separate article about that.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
  
&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;links-elsewhere&quot;&gt;Links Elsewhere&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hachyderm.io&#x2F;@thisalex&#x2F;115969620588584958&quot;&gt;Comment at Mastodon&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;pulse&#x2F;taming-claude-code-aleksei-zakhlestin-trrce&quot;&gt;Discuss at LinkedIn&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;xpujwk&quot;&gt;Discussion at lobste.rs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Recording terminal animations with ASCIInema</title>
        <published>2025-04-26T00:00:00+00:00</published>
        <updated>2025-04-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://thisalex.com/posts/asciinema/"/>
        <id>https://thisalex.com/posts/asciinema/</id>
        
        <content type="html" xml:base="https://thisalex.com/posts/asciinema/">&lt;p&gt;&lt;em&gt;In the &lt;a href=&quot;https:&#x2F;&#x2F;thisalex.com&#x2F;posts&#x2F;2025-04-20&#x2F;&quot;&gt;previous article&lt;&#x2F;a&gt; I was using terminal animations to illustrate examples of using the &#x27;jj&#x27; command line tool. The need to figure out how to do that delayed the article. But now I know how to do it and I can share this knowledge.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;preamble&quot;&gt;Preamble&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;ASCIInema is not the only tool for recording terminal sessions, but it is the one which worked for me reliably.&lt;&#x2F;li&gt;
&lt;li&gt;I use Fish shell on macOS, but my solution should not be difficult to adapt to other shells.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;recording&quot;&gt;Recording&lt;&#x2F;h2&gt;
&lt;p&gt;Official &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.asciinema.org&#x2F;getting-started&#x2F;&quot;&gt;&quot;Getting Started&quot; page&lt;&#x2F;a&gt; of ASCIInema has all the details about installing on different systems. In my case, I used Homebrew to install it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#1F2328, #E6EDF3); background-color: light-dark(#FFFFFF, #0D1117);&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; install&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; asciinema&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, I added the following functions to my &lt;code&gt;~&#x2F;.config&#x2F;fish&#x2F;config.fish&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#1F2328, #E6EDF3); background-color: light-dark(#FFFFFF, #0D1117);&quot;&gt;&lt;code data-lang=&quot;fish&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Asciinema recording function with custom dimensions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;function&lt;&#x2F;span&gt;&lt;span&gt; arecc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Arguments: $argv[1] = columns, $argv[2] = rows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Get current date&#x2F;time for filename&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    set&lt;&#x2F;span&gt;&lt;span&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; datetime &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;%Y%m%d_%H%M%S&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    set&lt;&#x2F;span&gt;&lt;span&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; filepath ~&#x2F;Movies&#x2F;asciinema_&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span&gt;datetime&lt;&#x2F;span&gt;&lt;span&gt;.cast&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Launch fish with autosuggestions disabled and custom alias&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Note the escaped quotes for the alias&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    set&lt;&#x2F;span&gt;&lt;span&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; init_commands &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;set -g fish_autosuggestion_enabled 0; alias jj=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;jj --no-pager&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;    #&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Launch asciinema with fish using the commands&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    asciinema&lt;&#x2F;span&gt;&lt;span&gt; rec&lt;&#x2F;span&gt;&lt;span&gt; --cols&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; --rows&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; --command&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;fish -C &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span&gt;init_commands&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span&gt;filepath&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;Recording saved to &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span&gt;filepath&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6E7781, #8B949E);&quot;&gt; Asciinema recording function with default dimensions (80×24)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;function&lt;&#x2F;span&gt;&lt;span&gt; arec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;    arecc&lt;&#x2F;span&gt;&lt;span&gt; 80 24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#CF222E, #FF7B72);&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What&#x27;s going on here:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;arecc&lt;&#x2F;code&gt; function takes two arguments: the number of columns and rows for the terminal window and &lt;code&gt;arec&lt;&#x2F;code&gt; is a wrapper for it with default values of 80 and 24 which I used for all of my videos&lt;&#x2F;li&gt;
&lt;li&gt;All of the recordings are saved in &lt;code&gt;~&#x2F;Movies&lt;&#x2F;code&gt; directory with a timestamp in the filename. They looked like &lt;code&gt;Movies&#x2F;asciinema_20250420_021157.cast&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;I used a subshell with custom initialization commands:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set -g fish_autosuggestion_enabled 0&lt;&#x2F;code&gt; disables the autosuggestions in the terminal. otherwise Fish would pollute the output with suggestions which are relevant to my environment, but not useful for the video&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;alias jj=&quot;jj --no-pager&quot;&lt;&#x2F;code&gt; forces jujutsu not to use pager for &lt;code&gt;jj status&lt;&#x2F;code&gt; and other commands. I wanted to show the linear flow and pager would redraw the screen and show only output of the single command.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&#x27;s pretty much it.&lt;&#x2F;p&gt;
&lt;p&gt;To start recording, I just run &lt;code&gt;arec&lt;&#x2F;code&gt; in the terminal and then execute several commands I want to record. When I am done, I press &lt;code&gt;Ctrl+D&lt;&#x2F;code&gt; to stop the recording.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-in-article&quot;&gt;Using in article&lt;&#x2F;h2&gt;
&lt;p&gt;The files are saved in a compact format which is trivially parsed and displayed by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;asciinema&#x2F;asciinema-player&quot;&gt;asciinema-player&lt;&#x2F;a&gt; js library.&lt;&#x2F;p&gt;
&lt;p&gt;So, I just needed to:&lt;&#x2F;p&gt;
&lt;p&gt;Put asciinema-player.min.js, asciinema-player.css and and my recorder cast-sessions into the &lt;code&gt;static&lt;&#x2F;code&gt; directory of my zola-powered blog.&lt;&#x2F;p&gt;
&lt;p&gt;I added the following lines to the &lt;code&gt;header.html&lt;&#x2F;code&gt; partial of the template:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#1F2328, #E6EDF3); background-color: light-dark(#FFFFFF, #0D1117);&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;link&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; rel&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;stylesheet&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;text&#x2F;css&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; href&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&#x2F;asciinema-player.css&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; src&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&#x2F;asciinema-player.min.js&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, I added the blocks like this to the markdown-source of the article:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#1F2328, #E6EDF3); background-color: light-dark(#FFFFFF, #0D1117);&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;div&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; id&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;ascii-jj-describe&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  AsciinemaPlayer&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#8250DF, #D2A8FF);&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&#x2F;jujutsu-different-approach&#x2F;jj-describe.cast&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    document&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#8250DF, #D2A8FF);&quot;&gt;getElementById&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;ascii-jj-describe&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      rows&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      idleTimeLimit&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  )&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#116329, #7EE787);&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I create a &lt;code&gt;&amp;lt;div&amp;gt;&lt;&#x2F;code&gt; container and connect js-player to it, passing some settings.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rows&lt;&#x2F;code&gt; limits the height of the player to 5 lines (which is enough for this animation)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;idleTimeLimit&lt;&#x2F;code&gt; is set to 0.2 seconds to fast-forward thru the pauses in the recording. I am not the fastest person in the world and this setting makes sure that you do not suffer from this :)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Jujutsu: different approach to versioning</title>
        <published>2025-04-20T00:00:00+00:00</published>
        <updated>2025-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://thisalex.com/posts/2025-04-20/"/>
        <id>https://thisalex.com/posts/2025-04-20/</id>
        
        <content type="html" xml:base="https://thisalex.com/posts/2025-04-20/">&lt;p&gt;&lt;em&gt;In the &lt;a href=&quot;https:&#x2F;&#x2F;thisalex.com&#x2F;posts&#x2F;2025-01-19&#x2F;&quot;&gt;previous article&lt;&#x2F;a&gt; I told about my history with different version control systems and how I ended up using Jujutsu. This part will focus on why I think it is an important improvement over the git&#x27;s status-quo and why I use it daily.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-way-of-git&quot;&gt;The way of Git&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start by defining the aforementioned status-quo. Typical user sees interaction with Git as moving files between 3 stages:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Files are edited in the file system. Git doesn&#x27;t know anything about them. Some of the commands can compare the changed parts against other stages (think &lt;code&gt;git status&lt;&#x2F;code&gt; or &lt;code&gt;git diff&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Some [parts] of the files are added to the &quot;staging area&quot; using &lt;code&gt;git add [--interactive]&lt;&#x2F;code&gt; command. These changes are not yet part of the tracked history, but Git knows about them.&lt;&#x2F;li&gt;
&lt;li&gt;Proper content-snapshot with identifier and metadata is injected into the repository using &lt;code&gt;git commit&lt;&#x2F;code&gt; command.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Linus called this system &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git&quot;&gt;the stupid content tracker&lt;&#x2F;a&gt;&quot; because at its core it doesn&#x27;t try to do anything smart. It doesn&#x27;t try to understand the content, it doesn&#x27;t try to understand the changes, it doesn&#x27;t try to understand the history. It just stores the snapshots and the metadata. In the grand scheme of things, it is up to the user to make sense of it. And to be effective with git, users &lt;em&gt;have&lt;&#x2F;em&gt; to make sense of it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;install-jujutsu&quot;&gt;Install Jujutsu&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jj-vcs.github.io&#x2F;&quot;&gt;Jujutsu&lt;&#x2F;a&gt;, a VCS which I started to use recently, makes some very different choices. Let&#x27;s see how it handles this. I will be talking about the concepts and showing the commands. If you want to follow along, you can install it and try it out in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;On macOS with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt; it is as simple as &lt;code&gt;brew install jj&lt;&#x2F;code&gt;. You can find instructions for other platforms on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jj-vcs.github.io&#x2F;jj&#x2F;latest&#x2F;install-and-setup&#x2F;&quot;&gt;official site&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Jujutsu allows you to work with arbitrary git repositories. You can use both &lt;code&gt;git&lt;&#x2F;code&gt; and &lt;code&gt;jj&lt;&#x2F;code&gt; at the same time. Adding jujutsu support to repo is as simple as running &lt;code&gt;jj git init --colocate&lt;&#x2F;code&gt; in it. Jujutsu will detect existing git repository and will configure itself to transparently sync with it.&lt;&#x2F;p&gt;
&lt;div class=&quot;note-container&quot;&gt;
  
    &lt;button class=&quot;note-toggle&quot;&gt;
      
        &lt;div class=&quot;note-icon&quot;&gt;
        &lt;p&gt;Advanced topic&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
      
    &lt;&#x2F;button&gt;

    
    &lt;div class=&quot;note-content&quot; style=&quot;display: none;&quot;&gt;
    
    &lt;p&gt;Jujutsu has plans to provide several opensource backend implementations: git-based one and the native one. Google has a backend powered by Piper, their internal VCS system, but it is not public. Native backend is not ready yet, and while it will have some interesting properties, for now it is not a practical topic. The rest of this post would be talking only about git-backend.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
  
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;everything-s-a-part-of-change&quot;&gt;Everything&#x27;s a part of &quot;change&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;Git, as I shown above, expects user to work on files and then to &quot;commit&quot; their snapshot to the repository. Thus, the verb became a noun and we say that Git-repository stores commits.&lt;&#x2F;p&gt;
&lt;p&gt;Jujutsu uses a different terminology: repository stores changes. At any point in time, whenever you edit, add or remove a file, these modifications become a part of the &quot;current change&quot;. You never need to commit them explicitly.&lt;&#x2F;p&gt;
&lt;p&gt;As soon as we connected jj to the repository it has created a new &lt;strong&gt;empty&lt;&#x2F;strong&gt; change with &lt;strong&gt;no description&lt;&#x2F;strong&gt;. We can check this by running &lt;code&gt;jj status&lt;&#x2F;code&gt; (or &lt;code&gt;jj st&lt;&#x2F;code&gt;) command.&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-status&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-status.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-status&#x27;),
  {
    rows: 10,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;Important bits here:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nonwtwyp&lt;&#x2F;code&gt; is an id of the change. it would remain static no matter how we change the contents in the future.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;126fcd52&lt;&#x2F;code&gt; is a content-hash which corresponds to the id of the git commit. As soon as we add a single new letter to the files it will change.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(empty)&lt;&#x2F;code&gt; means that this change is allocated, but it doesn&#x27;t have any content yet. Again, as soon as we modify a single letter in files, this marker will disappear.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(no description set)&lt;&#x2F;code&gt; means that we didn&#x27;t bother to set the description of the change yet (it corresponds to the &quot;commit message&quot; in git).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Jujutsu doesn&#x27;t require you to set descriptions of changes until you want to make them public. In Jujutsu it is perfectly fine to have multiple non-described changes. I still prefer to set descriptions early on, but it is not a requirement.&lt;&#x2F;p&gt;
&lt;p&gt;The command to set the description is &lt;code&gt;jj describe&lt;&#x2F;code&gt;. This command does not create a new change. It modifies the description of current change. You can call it several times and it will be modifying description of the same change.&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-describe&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-describe.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-describe&#x27;),
  {
    rows: 5,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;How do you start a new change? Well, you just use &lt;code&gt;jj new&lt;&#x2F;code&gt; for that.&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-new&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-new.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-new&#x27;),
  {
    rows: 5,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;h2 id=&quot;branches-don-t-have-names&quot;&gt;Branches don&#x27;t have names&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s take a look at the log of our changes. We&#x27;ll use &lt;code&gt;jj log&lt;&#x2F;code&gt; for that.&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-move&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-move.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-move&#x27;),
  {
    rows: 15,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;The thing I&#x27;d like to focus on is the &lt;code&gt;main&lt;&#x2F;code&gt; marker, which stayed at exactly the same place where it was in this git repository initially. Branches in jujutsu do not have names, which might be contra-intuitive at first. Previously, we created a single branch of changes starting from git&#x27;s &quot;main&quot; branch, but we can create more like this: &lt;code&gt;jj new main&lt;&#x2F;code&gt; and they wouldn&#x27;t be lost, as Jujutsu&#x27;s log would give us access to all of them without any issues. Strictly speaking, this is exactly what was done as part of &lt;code&gt;jj git init&lt;&#x2F;code&gt; under the hood: it created one empty change for us automatically.&lt;&#x2F;p&gt;
&lt;p&gt;And, as we can create multiple independent branches of changes from any point of the tree, Jujutsu can not meaningfully make assumptions about moving the marker.&lt;&#x2F;p&gt;
&lt;p&gt;In previous paragraphs I said &quot;marker&quot;, but the proper Jujutsu term for this is &quot;bookmark&quot;. Literally, the &quot;main&quot; is a bookmark in tree, which can be referenced by name, and moved as we need (just as we move a bookmark, when we read the book).&lt;&#x2F;p&gt;
&lt;p&gt;So, whenever we&#x27;re ready to tell: &quot;this is, what everyone should consider &lt;strong&gt;main&lt;&#x2F;strong&gt; from now on!&quot;, we just type &lt;code&gt;jj bookmark move main --to=@&lt;&#x2F;code&gt;. At this moment, git&#x27;s &quot;main&quot; branch would start to point at this commit (&quot;current&quot; commit has special id &lt;code&gt;@&lt;&#x2F;code&gt;) and the whole branch would become visible to the git. Other branches we created would be mostly hidden from git tools (but the commits would still be stored in git&#x27;s repository).&lt;&#x2F;p&gt;
&lt;p&gt;The next step would be able to push the &lt;em&gt;bookmark&lt;&#x2F;em&gt; to the upstream repository (such as github) using &lt;code&gt;jj git push&lt;&#x2F;code&gt; command. Except that we still have some undescribed changes. It is not prohibited to have that in git, but it would definitely look strange. Let&#x27;s play nice and that.&lt;&#x2F;p&gt;
&lt;p&gt;One way to do it is to use &lt;code&gt;jj describe k&lt;&#x2F;code&gt;. A lot of jj&#x27;s commands accept &lt;code&gt;‌[REVSETS]&lt;&#x2F;code&gt; argument which allows to specify the change-id, which is the target of command. In this case, change-id is &lt;code&gt;kqvmuvwn&lt;&#x2F;code&gt;, but we can use &lt;code&gt;k&lt;&#x2F;code&gt; as it was hilighted in the log. Jujutsu always highlights shortest non-ambiguous prefix of the change-id in the log.&lt;&#x2F;p&gt;
&lt;p&gt;Another approach is more generic. We can use &lt;code&gt;jj edit k&lt;&#x2F;code&gt; to resume work on the change and just call &lt;code&gt;jj describe&lt;&#x2F;code&gt; without arguments while we do it.&lt;&#x2F;p&gt;
&lt;p&gt;Whether we modify the description or the contents of the change it&#x27;s content-hash would change, but it&#x27;s change-id would not. And, as descendent commits are linked via change-ids and bookmarks are attached to change-ids as well, the branch would maintain it&#x27;s shape after the changes. So, now we should finally be able to push our changes.&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-edit&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-edit.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-edit&#x27;),
  {
    rows: 15,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;div class=&quot;note-container&quot;&gt;
  
    &lt;button class=&quot;note-toggle&quot;&gt;
      
        &lt;div class=&quot;note-icon&quot;&gt;
        &lt;p&gt;Advanced topic&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
      
    &lt;&#x2F;button&gt;

    
    &lt;div class=&quot;note-content&quot; style=&quot;display: none;&quot;&gt;
    
    &lt;p&gt;Editing pre-existing changes of the upstream branch and pushing them to git again would result in a force-push. From Git&#x27;s point of view these new commits are not connected to the old ones and history rewriting happens.&lt;&#x2F;p&gt;
&lt;p&gt;Jujutsu uses several heuristics to prevent &quot;dangerous&quot; situations such as &quot;moving&quot; the branch which was already merged into something else, but overall it is much more forgiving in this regard.&lt;&#x2F;p&gt;
&lt;p&gt;In cases when several people work on the same branch such pushes would result in the need to re-sync local branches. In the future, when we have &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Forge_(software)&quot;&gt;forges&lt;&#x2F;a&gt; with native jujutsu support, these operations would be trivial and boring (in a good way).&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
  
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;conflicts-happen&quot;&gt;Conflicts happen&lt;&#x2F;h2&gt;
&lt;p&gt;In the previous section we were modifying the change in the middle of the branch. How would Jujutsu react if we introduced the conflict? Let&#x27;s check!&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-conflict&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-conflict.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-conflict&#x27;),
  {
    rows: 15,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;You see that the upper change is marked with a red &quot;conflict&quot; word now, but Jujutsu still allows us to work on whatever we want. It doesn&#x27;t force us to resolve conflict now. The most interesting part is, that we do not have to resolve the conflict at the point where it was introduced.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll create a new change at the top of the branch: &lt;code&gt;jj new m&lt;&#x2F;code&gt; and will edit the code to resolve the conflict there. Take a look at the log now:&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-resolve&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-resolve.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-resolve&#x27;),
  {
    rows: 15,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;We have intermediate change in &quot;conflicted&quot; state, but above it the branch is clean again. And we could leave it at that, but let&#x27;s apply the fix to the broken change instead to get a clean history. We will use &lt;code&gt;jj squash --to v&lt;&#x2F;code&gt; command for that:&lt;&#x2F;p&gt;
&lt;div id=&quot;ascii-jj-squash&quot;&gt;&lt;&#x2F;div&gt;
&lt;script&gt;
AsciinemaPlayer.create(
  &#x27;&#x2F;jujutsu-different-approach&#x2F;jj-squash.ascii&#x27;,
  document.getElementById(&#x27;ascii-jj-squash&#x27;),
  {
    rows: 15,
    idleTimeLimit: 0.2,
  }
);
&lt;&#x2F;script&gt;
&lt;p&gt;&lt;strong&gt;Squash&lt;&#x2F;strong&gt; gathers the modifications from the current change and makes them a part of the specified change instead. Done. Conflict is gone. New empty change is automatically created for us. We can continue working on the branch.&lt;&#x2F;p&gt;
&lt;p&gt;One more thing…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;jj squash&lt;&#x2F;code&gt; without &lt;code&gt;--to&lt;&#x2F;code&gt; argument applies modifications to the parent change. It can be used to emulate a staging area of git. The basic idea is that you keep the parts which you&#x27;re sure about in one change and experimental modifications in the next one. And as soon as you&#x27;re sure in the quality of your experimental code you squash it into the proper change. A lot of people consider this to be the recommended flow for Jujutsu.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;merge-is-not-special&quot;&gt;Merge is not special&lt;&#x2F;h2&gt;
&lt;p&gt;Until this point I was talking about linear changes and diverging branches, but nothing about merges. Two reasons: a). I wanted to lay the groundwork; b). There isn&#x27;t much to talk about :)&lt;&#x2F;p&gt;
&lt;p&gt;In Jujutsu, one doesn&#x27;t make a merge of branches. Instead, one makes a change with several parents: &lt;code&gt;jj new rev1 rev2 rev3&lt;&#x2F;code&gt;, where &lt;code&gt;rev1&lt;&#x2F;code&gt;, etc. are either change-ids or branch-names (or some other interesting things we did not talk about yet).&lt;&#x2F;p&gt;
&lt;p&gt;Resulting change would reside on it&#x27;s own anonymous branch, as usually and you&#x27;ll need to assign some bookmark to it to make it visible in git.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, equivalent of &lt;code&gt;git merge&lt;&#x2F;code&gt; would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#1F2328, #E6EDF3); background-color: light-dark(#FFFFFF, #0D1117);&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;jj&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; new&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; feature&#x2F;name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;jj&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; describe&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;m&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;Merge &amp;quot;name&amp;quot; feature&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#953800, #FFA657);&quot;&gt;jj&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; bookmark&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; move&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0A3069, #A5D6FF);&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#0550AE, #79C0FF);&quot;&gt;-to=@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is more verbose, but gives you more control over the process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I hope I managed to spark your interest in jujutsu. This post is definitely not an exhaustive guide, but I wanted to give you a taste of what it is like to work with it.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to learn more, I encourage you to check out:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jj-vcs.github.io&#x2F;&quot;&gt;Jujutsu&#x27;s official site&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;steveklabnik.github.io&#x2F;jujutsu-tutorial&#x2F;&quot;&gt;Steve&#x27;s Jujutsu Tutorial&lt;&#x2F;a&gt; by Steve Klabnik&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;v5.chriskrycho.com&#x2F;essays&#x2F;jj-init&#x2F;&quot;&gt;&quot;jj init&quot;&lt;&#x2F;a&gt; article by Chris Krycho&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;discussions&quot;&gt;Discussions&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43740846&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;1k3mjlz&#x2F;jujutsu_different_approach_to_versioning&#x2F;&quot;&gt;r&#x2F;programming&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;atom.xml&quot;&gt;Subscribe via RSS&lt;&#x2F;a&gt; or follow me on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hachyderm.io&#x2F;@thisalex&quot;&gt;Mastodon&lt;&#x2F;a&gt; to avoid missing updates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My way from CVS to Jujutsu</title>
        <published>2025-01-19T00:00:00+00:00</published>
        <updated>2025-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://thisalex.com/posts/2025-01-19/"/>
        <id>https://thisalex.com/posts/2025-01-19/</id>
        
        <content type="html" xml:base="https://thisalex.com/posts/2025-01-19/">&lt;p&gt;&lt;em&gt;Alternative title&lt;&#x2F;em&gt;: &quot;&lt;strong&gt;On benefits of going out of your comfort zone&lt;&#x2F;strong&gt;&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Hi, I&#x27;ve been an early adopter of different Version Control Systems.&lt;&#x2F;p&gt;
&lt;p&gt;I started with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Concurrent_Versions_System&quot;&gt;CVS&lt;&#x2F;a&gt; in the 1990s. &lt;strong&gt;CVS&lt;&#x2F;strong&gt; was based on the earlier &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Revision_Control_System&quot;&gt;RCS&lt;&#x2F;a&gt; file-versioning tool, but introduced concepts of &quot;module&quot; and &quot;client-server architecture&quot;. Still, each of the files was versioned separately which led to various complications.&lt;&#x2F;p&gt;
&lt;p&gt;I switched to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Apache_Subversion&quot;&gt;Subversion&lt;&#x2F;a&gt; in early 2000s. It was a breath of the fresh air, as it was possible to track all of the project as a whole. Branches worked much faster and were not as painful to use. At this point, the world of open-source software was split in two parts: older projects used &lt;strong&gt;CVS&lt;&#x2F;strong&gt;, newer used &lt;strong&gt;Subversion&lt;&#x2F;strong&gt;. And while there were tools for migration they were not super-reliable and a lot of older established projects didn&#x27;t feel it was worth it to invest into migration. Pretty much all of the active developers learned how to use both of these. &lt;em&gt;This is a very important take and I will return to it later.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Still, both &lt;strong&gt;CVS&lt;&#x2F;strong&gt; and &lt;strong&gt;Subversion&lt;&#x2F;strong&gt; were created to be used online: only the current revision was available on the workstation and all of the commits were negotiated with centralized server in real-time. It mostly worked fine if you worked from the office and the team of people working on project wasn&#x27;t too big…, but it wasn&#x27;t comfortable if you wanted to work offline. In a lot of real-world situations, people ended up making large monolithic commits which combined all of their day&#x27;s work.&lt;&#x2F;p&gt;
&lt;p&gt;Due to my changed course of work, I was getting interested both in offline work and being able to create a nicely written history of commits (I had to do some &quot;software archeology&quot;, which showed importance of this) and started to look for the solution. I think it was 2004 when I found &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20080708175203&#x2F;https:&#x2F;&#x2F;svk.bestpractical.com&#x2F;view&#x2F;HomePage&quot;&gt;SVK&lt;&#x2F;a&gt;, which was eye-opening. The idea was pretty simple: &lt;strong&gt;SVK&lt;&#x2F;strong&gt; was working as a local mirror of external repository. I could make my commits to this mirror and, compared to &lt;strong&gt;Subversion&lt;&#x2F;strong&gt; and &lt;strong&gt;CVS&lt;&#x2F;strong&gt; they were instantaneous, as there was no network trips involved. Later, when I got online, I could initiate mirror-synchronization. Sure, there could be conflicts, but there were tools to solve those. It felt like freedom.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;SVK&lt;&#x2F;strong&gt; didn&#x27;t gain a lot popularity, except for a small bubble. I tried to do my share of evangelizing, but wasn&#x27;t too successful: colleagues didn&#x27;t feel that they needed this kind of complexity. Anyway, it wasn&#x27;t important as it was a layer on top of &lt;strong&gt;Subversion&lt;&#x2F;strong&gt; which was a lingua-franca of VCSs at that point. I could work the way I like and still stay compatible with the rest of the world.&lt;&#x2F;p&gt;
&lt;p&gt;Couple of years later, the world of open-source was bubbling with the news about &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Git&quot;&gt;&quot;that VCS created by Linus Torvalds&quot;&lt;&#x2F;a&gt;. Everyone felt that it is important, but majority of people were struggling with concept of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Distributed_version_control&quot;&gt;&quot;distributed&quot; VCS&lt;&#x2F;a&gt;. It was foreign to them and software companies were going through something akin to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Five_stages_of_grief&quot;&gt;Five stages of grief&lt;&#x2F;a&gt;. It was easier for me because of the previous experience with SVK and I didn&#x27;t hesitate to make the switch right after &lt;strong&gt;Git&lt;&#x2F;strong&gt; made its 1.0 release in the end of 2005.&lt;&#x2F;p&gt;
&lt;p&gt;There were two distinct features of &lt;strong&gt;Git&lt;&#x2F;strong&gt;, which were important to me: it was extremely fast and I could host my own &quot;remote&quot; for backups, while still being able to push code to public &lt;strong&gt;Subversion&lt;&#x2F;strong&gt; repositories using git-svn tool. It was simpler than my previous setup and conflict resolution felt superior. At this point I was still using a very limited subset of git commands. It was still mostly &quot;my toy&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;In 2008 a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GitHub#History&quot;&gt;social-network called GitHub was launched&lt;&#x2F;a&gt; and the world was never the same again.&lt;&#x2F;p&gt;
&lt;p&gt;At that point I was fluent with &lt;strong&gt;Git&lt;&#x2F;strong&gt;&#x27;s more advanced workflows: I was actively using interactive rebase to reorder my commits, I knew how to juggle the staging area to split it into separate commits line by line and how to save the day by using reflog. I started to do the talks for colleagues about it. I was experimenting with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Mercurial&quot;&gt;Mercurial&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GNU_Bazaar&quot;&gt;GNU Bazaar&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fossil_(software)&quot;&gt;Fossil&lt;&#x2F;a&gt; and some of the lesser known systems, but didn&#x27;t feel the urge to switch &quot;for real&quot;: it seemed that everything they provide I can do in &lt;strong&gt;Git&lt;&#x2F;strong&gt;, which has greater momentum. There was a lot of talk about &lt;strong&gt;Git&lt;&#x2F;strong&gt;&#x27;s CLI commands being obscure and illogical, and while I agreed with the sentiment the knowledge was already there at my fingertips. I didn&#x27;t feel like I was suffering.&lt;&#x2F;p&gt;
&lt;p&gt;Mind you, I was still looking for the ways to make some operations less verbose, but there was more and more good tooling available. In 2015, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swisspol&quot;&gt;@swisspol&lt;&#x2F;a&gt; created &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitup.co&#x2F;&quot;&gt;GitUp&lt;&#x2F;a&gt; GUI for macOS, which, as far as I know, is still unbeaten if you need to reorder branch commits in a fast intuitive fashion. Take a look at the videos on app&#x27;s website — it&#x27;s a truly unique UX. I use it daily since then.&lt;&#x2F;p&gt;
&lt;p&gt;Another extremely useful GUI is the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.jetbrains.com&#x2F;guide&#x2F;java&#x2F;tips&#x2F;magic-wand&#x2F;&quot;&gt;&quot;magic wand&quot; conflict resolver&lt;&#x2F;a&gt; included with JetBrans&#x27; IDEs. It solves 70% of conflicts for me.&lt;&#x2F;p&gt;
&lt;p&gt;So, as of now, I have spent 20 years of my life using Git. And while I like stable software and value the comfort of verified solutions, I still have a fear of stagnation: It felt obvious, that 20 years is more than enough time for someone to invent solution which would be the new revolution in VCS-productivity. I needed something new. And, boy, was I right!&lt;&#x2F;p&gt;
&lt;div class=&quot;note-container&quot;&gt;
  
    &lt;button class=&quot;note-toggle&quot;&gt;
      
        &lt;div class=&quot;note-icon&quot;&gt;
        &lt;p&gt;TL&#x2F;DR (Short recap on productivity benefits in VCS generations)&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
      
    &lt;&#x2F;button&gt;

    
    &lt;div class=&quot;note-content&quot; style=&quot;display: none;&quot;&gt;
    
    &lt;ul&gt;
&lt;li&gt;CVS (over RCS):
&lt;ul&gt;
&lt;li&gt;Repository-wide commits&lt;&#x2F;li&gt;
&lt;li&gt;Network protocol (No need to sync the changes manually)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Subversion
&lt;ul&gt;
&lt;li&gt;Lightweight branches&lt;&#x2F;li&gt;
&lt;li&gt;Repository-level history of changes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Distributed VCSs (SVK, Git, Mercurial, …)
&lt;ul&gt;
&lt;li&gt;Offline work&lt;&#x2F;li&gt;
&lt;li&gt;Post-factum regrouping of commits&lt;&#x2F;li&gt;
&lt;li&gt;Ability to have Local-only branches&lt;&#x2F;li&gt;
&lt;li&gt;Ability to manage several forks from one local repository&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

    &lt;&#x2F;div&gt;
  
&lt;&#x2F;div&gt;
&lt;p&gt;One day last november I was browsing HackerNews posts and found someone mentioning &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jj-vcs.github.io&#x2F;&quot;&gt;Jujutsu VCS&lt;&#x2F;a&gt;. I went to check and noticed, that &lt;strong&gt;1.&lt;&#x2F;strong&gt; I opened the website earlier (&lt;em&gt;good sign!&lt;&#x2F;em&gt;) and that &lt;strong&gt;2.&lt;&#x2F;strong&gt; it is using &lt;strong&gt;Git&lt;&#x2F;strong&gt; as the backend (&lt;em&gt;e.g. still can be used to collaborate with everyone else!&lt;&#x2F;em&gt;), while &lt;strong&gt;3.&lt;&#x2F;strong&gt; being inspired by &lt;strong&gt;Mercurial&lt;&#x2F;strong&gt; and having new interesting features (&lt;em&gt;wow!&lt;&#x2F;em&gt;). I spent an evening reading [unfinished] &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;steveklabnik.github.io&#x2F;jujutsu-tutorial&#x2F;&quot;&gt;Steve&#x27;s Jujutsu Tutorial&lt;&#x2F;a&gt; (by Steve Klabnik, who&#x27;s work I respect immensely) and started to use &lt;strong&gt;jj&lt;&#x2F;strong&gt; the very next morning for one of my work-projects.&lt;&#x2F;p&gt;
&lt;p&gt;The first couple of days were rough: I remember that feeling from the earlier times when I tried new VCSs. It&#x27;s quite similar to how you feel when trying new programming language for the first time. All of the pieces were somewhere there, but they were lying in unexpected places. I needed to find how to do the things I always did and then I needed to find what are the alternatives to my old ways.&lt;&#x2F;p&gt;
&lt;p&gt;Two months later: I use &lt;strong&gt;jj&lt;&#x2F;strong&gt; daily for everything and am not looking back. I feel much more productive in my creative phase, as &lt;strong&gt;jj&lt;&#x2F;strong&gt; lets me spend way less time on formalities, while maintaining full control, which I need to confidentely continue the work. Colleagues didn&#x27;t notice a thing until I started to advertise &lt;strong&gt;Jujutsu&lt;&#x2F;strong&gt; to them.&lt;&#x2F;p&gt;
&lt;p&gt;p.s. While this post was mostly about my history with VCSs, the &lt;a href=&quot;https:&#x2F;&#x2F;thisalex.com&#x2F;posts&#x2F;2025-04-20&#x2F;&quot;&gt;follow-up article&lt;&#x2F;a&gt; focuses on practical aspects of work with &lt;strong&gt;jj&lt;&#x2F;strong&gt;. I show how to use it, what makes it different from &lt;strong&gt;Git&lt;&#x2F;strong&gt; and tell why I think it is advantageous.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;atom.xml&quot;&gt;Subscribe via RSS&lt;&#x2F;a&gt; or follow me on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hachyderm.io&#x2F;@thisalex&quot;&gt;Mastodon&lt;&#x2F;a&gt; to avoid missing updates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
