<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Thomas Letan's Blog - git</title>
    <link>https://soap.coffee/~lthms/tags/git.html</link>
    <description>Posts tagged "git"</description>
    <atom:link href="https://soap.coffee/~lthms/tags/git.xml" rel="self"
               type="application/rss+xml" />
    
    
    <item>
      <title>Using git maintenance with Encrypted SSH Keys</title>
      <link>https://soap.coffee/~lthms/posts/GitMaintenanceSshEncryptedKeys.html</link>
      <guid>https://soap.coffee/~lthms/posts/GitMaintenanceSshEncryptedKeys.html</guid>
      <pubDate>February 18, 2024</pubDate>
      <description>
        
        &lt;h1&gt;Using &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt; with Encrypted SSH Keys&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-peach&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;This year, I went to &lt;a href=&quot;https://fosdem.org/2024&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;FOSDEM 2024&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It was nice and
&lt;s&gt;cosy&lt;/s&gt; crowded, and I really enjoyed my time there. The very last talk I
could attend to before having to leave for the train station was “&lt;a href=&quot;https://www.youtube.com/watch?v=aolI_Rz0ZqY&amp;amp;pp=ygUZc28geW91IHRoaW5rIHlvdSBrbm93IGdpdA%3D%3D&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;So You Think
You Know
Git&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#youtube&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;”
by &lt;a href=&quot;https://twitter.com/chacon&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;Scott Chacon&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. If you haven’t already, go and
watch it. It is a very good and educational presentation. You will learn what
&lt;code class=&quot;hljs&quot;&gt;git blame -C -C -C&lt;/code&gt; does and never be the same.&lt;/p&gt;
&lt;p&gt;Another takeaway for me was &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt;. &lt;code class=&quot;hljs&quot;&gt;git maintenance&lt;/code&gt; allows running
in the background a set of tasks which optimize commands like &lt;code class=&quot;hljs&quot;&gt;git add&lt;/code&gt; and
&lt;code class=&quot;hljs&quot;&gt;git fetch&lt;/code&gt; for a responsive user experience. I mean, count me in! Our git
repository at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt; has become fairly big over the years&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Not &lt;a href=&quot;https://youtu.be/aolI_Rz0ZqY?si=-ielyNVXwREJqupo&amp;amp;t=1430&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;&lt;em&gt;mono-repo&lt;/em&gt;
big&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; yet, but
still big enough to make &lt;code class=&quot;hljs&quot;&gt;git fetch --all --prune&lt;/code&gt; feels… well,
unresponsive. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So, when I came back to work the next day, I run the magic command the speaker
had mentioned&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Following &lt;a href=&quot;https://twitter.com/leostera/status/1740796853174596007&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;a petition from the
Internet&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, my
terminal prompt is &lt;code class=&quot;hljs&quot;&gt;;&lt;/code&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; git maintenance start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This created a bunch of user systemd services and timers which I decided to run
immediately to test that everything was working correctly, starting with the
hourly service responsible for prefetching remote branches.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user start git-maintenance@hourly.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, this did not work out, and for predictable reasons.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user status git-maintenance@hourly.service
(...)
systemd[1706]: Starting Optimize Git repositories data...
git[76228]: git@gitlab.com: Permission denied (publickey).
git[76226]: error: failed to prefetch remotes
git[76226]: error: task &lt;span class=&quot;hljs-string&quot;&gt;&apos;prefetch&apos;&lt;/span&gt; failed
systemd[1706]: git-maintenance@hourly.service: Main process exited, code=exited, status=&amp;gt;
systemd[1706]: git-maintenance@hourly.service: Failed with result &lt;span class=&quot;hljs-string&quot;&gt;&apos;exit-code&apos;&lt;/span&gt;.
systemd[1706]: Failed to start Optimize Git repositories data.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The culprit here is the fact I am using an encrypted SSH key to connect to
Gitlab where our repository is hosted and out of the box the scripts run by
&lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt; have now way to use them. This is because &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt;
is not aware of the existence of the SSH agent running on my laptop.&lt;/p&gt;
&lt;p&gt;The solution can be read in the Man page of &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;(…) any customization should be done by creating a drop-in file, &lt;em&gt;i.e.&lt;/em&gt; a
&lt;code class=&quot;hljs&quot;&gt;.conf&lt;/code&gt; suffixed file in the
&lt;code class=&quot;hljs&quot;&gt;~/.config/systemd/user/git-maintenance@.service.d&lt;/code&gt; directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn’t know this general purpose trick which should work for any systemd
service running on a Linux machine! Thanks, anonymous technical writer who took
the time to contribute to this Man page.&lt;/p&gt;
&lt;p&gt;And indeed, creating a file named &lt;code class=&quot;hljs&quot;&gt;10-ssh.conf&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The prefix number is as important as the &lt;code class=&quot;hljs&quot;&gt;.conf&lt;/code&gt; suffix mentioned in
the &lt;code class=&quot;hljs&quot;&gt;git-maintenance&lt;/code&gt; Man page for systemd to load the drop-in file. &lt;/span&gt;
&lt;/span&gt; in
&lt;code class=&quot;hljs&quot;&gt;${HOME}/.config/systemd/user/git-maintenance@.service.d/&lt;/code&gt; to set the
&lt;code class=&quot;hljs&quot;&gt;SSH_AUTH_SOCK&lt;/code&gt; environment variable solved my issue. Its value depends on your
personal setup. In my case, I am using the systemd &lt;code class=&quot;hljs&quot;&gt;ssh-agent.service&lt;/code&gt; user
unit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user show ssh-agent.service | grep Environment=SSH_AUTH_SOCK
Environment=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We replicate this in our &lt;code class=&quot;hljs&quot;&gt;10-ssh.conf&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-systemd&quot;&gt;[Service]
Environment=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we are done! This time, executing the service manually will work (assuming
the necessary encrypted key has been &lt;code class=&quot;hljs&quot;&gt;ssh-add&lt;/code&gt; to the agent).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;; systemctl --user daemon-reload
; systemctl --user start git-maintenance@hourly.service
; systemctl --user status git-maintenance@hourly.service
(...)
systemd[1706]: Starting Optimize Git repositories data...
systemd[1706]: Finished Optimize Git repositories data.
&lt;/code&gt;&lt;/pre&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>Patch Dependencies for Stacked Git</title>
      <link>https://soap.coffee/~lthms/posts/StackedGitPatchTheory.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGitPatchTheory.html</guid>
      <pubDate>January 26, 2023</pubDate>
      <description>
        
        &lt;h1&gt;Patch Dependencies for Stacked Git&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/opinions.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;opinions&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Every time I catch myself thinking about dependencies between
changeset of a software project, the fascinating field of patch
theories comes to my mind.&lt;/p&gt;
&lt;p&gt;A “patch theory” usually refers to the mathematical foundation behind
the data model of so-called Patch-based DVCS like Darcs and
Pijul. More precisely, a patch theory is an encoding of the state of a
repository, equipped with operations (gathered in so-called patches,
not to be confused with &lt;code class=&quot;hljs&quot;&gt;GNU diff&lt;/code&gt; patches) one can do to this
state. For instance, my rough understanding of Pijul’s patch theory is
that a repository is an oriented graph of lines, and a patch is a set
of operations onto this graph.&lt;/p&gt;
&lt;p&gt;An interesting aspect of patch theory is that it requires a partial
order for its patches, from which a Patch-based DVCS derives a
dependency graph. In a nutshell, a patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; depends on the patches
which are responsible for the presence of the lines that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
modifies.&lt;/p&gt;
&lt;p&gt;I have always found this idea of a dependency graph for the patches
of a repository fascinating, because I though it would be a very
valuable tool in the context of software development.&lt;/p&gt;
&lt;p&gt;I wanted to slightly change the definition of what a patch
dependency is, though. See, the partial order of Darcs and Pijul
focus on syntactic dependencies: the relation between lines in text
files. They need that to reconstruct these text files in the file
system of their users. As a software developers writing these text
files, I quickly realized these dependencies were of little interest
to me, though. What I wanted to be able to express was that a
feature introduced by a patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; relied on a fix introduced by a
patch &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&apos;&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I have experimented with Darcs and Pijul quite a bit, with this idea
stuck in the back of my mind. At the end of this journey, I
convinced myself&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I am not trying to convince you, per say. This is a very personal
and subjective feedback, it does not mean someone else couldn&apos;t reach a
different conclusion. &lt;/span&gt;
&lt;/span&gt; (1) this beautiful idea I
had simply could not scale, and (2) neither I nor our industry is
ready to give up on the extensive ecosystem that has been built on top
of &lt;code class=&quot;hljs&quot;&gt;git&lt;/code&gt; just yet. As a consequence, my interest in Patch-based DVCS
decreased sensibly.&lt;/p&gt;
&lt;p&gt;Until very recently, that is. I got reminded of the appeal of a
dependency graph for changesets when I started adopted a Gitlab
workflow centered around Stacked Git and smaller, sometimes
interdependent MRs.&lt;/p&gt;
&lt;p&gt;A manually curated graph dependency for a whole repository is not
practical, but what about my local queue of patches, patiently
waiting to be integrated into the upstream repository I am
contributing too?  Not only does it look like a more approachable
task, it could make synchronizing my stacked MRs a lot easier.&lt;/p&gt;
&lt;p&gt;The workflow I have in mind would proceed as follows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stacked Git’s &lt;code class=&quot;hljs&quot;&gt;new&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;edit&lt;/code&gt; commands could be extended to let
developers declare dependencies between their patches. It would be
the commands’ responsibility to enforce the wellfoundness of the
dependency graph (&lt;em&gt;e.g.&lt;/em&gt;, prevent the introduction of cycles in the
graph, and maybe diamonds too&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;At least in a first version. There is definitely value in being
able to work with two independent patches in conjunction with a third one
that needs them both. That being said, our goal here is to organize our
work locally, and if it is made easier by declaring artificial dependency,
this is a pragmatic sacrifice I am personally willing to make. &lt;/span&gt;
&lt;/span&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;hljs&quot;&gt;series&lt;/code&gt; command could be improved to display the resulting
dependency graph.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;push&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt; would automatically take care (pushing or popping)
of the selected patch(es) dependencies.&lt;/li&gt;
&lt;li&gt;Ideally, Stacked Git would get a new command &lt;code class=&quot;hljs&quot;&gt;prepare &amp;lt;PATCH NAME&amp;gt;&lt;/code&gt;
which would pop every patches applied, then only only push &lt;code class=&quot;hljs&quot;&gt;&amp;lt;PATCH NAME&amp;gt;&lt;/code&gt; and its dependencies (in the reverse order). Developers could
fix conflicts if need be. That is, Stacked Git would not be
responsible for the consistency or correctness of the dependency
graph.&lt;/li&gt;
&lt;li&gt;Stacked Git could get commands to detect potential issues with the
dependency graph specified by the developer (mostly consisting in
dry-run of &lt;code class=&quot;hljs&quot;&gt;prepare&lt;/code&gt; to check if it would lead to conflicts).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because what we want is semantic dependencies, not syntactic dependencies
between patches, I really think it makes a lot of sense to completely delegate
the dependencies declaration to the developer&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Further versions of Stacked Git could explore computing the
dependency graph automatically, similarly to what Git does. But I think
that if Darcs and Pijul told us anything, it&apos;s that this computation is far
from being trivial. &lt;/span&gt;
&lt;/span&gt;. The very mundane
example that convinced me is the &lt;code class=&quot;hljs&quot;&gt;CHANGELOG&lt;/code&gt; file any mature software project
ends up maintaining. If the contribution guidelines require to modify the
&lt;code class=&quot;hljs&quot;&gt;CHANGELOG&lt;/code&gt; file in the same commit as a feature is introduced, then the
patches to two independent features will systematically conflict. This does not
mean, from my patch queue perspective, I should be forced to &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt; the first
commit before starting to work on the second one. It just means that when I
call &lt;code class=&quot;hljs&quot;&gt;stg prepare&lt;/code&gt;, I can have to fix a conflict, but fixing Git conflicts is
part of the job after all&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;And we have tools to help us. I wonder to which extends &lt;code class=&quot;hljs&quot;&gt;git rerere&lt;/code&gt;
could save the day in some cases, for instance. &lt;/span&gt;
&lt;/span&gt;. If for some reasons solving a conflict
proves to be too cumbersome, I can always acknowledge that, and declare a new
dependency to the appropriate patch. It only means I and my reviewers will be
constrained a bit more than expected when dealing with my stack of MRs.&lt;/p&gt;
&lt;p&gt;I am under the impression that this model extends quite nicely the current way
Stacked Git is working. To its core, it extends its data model to constraint a
bit &lt;code class=&quot;hljs&quot;&gt;push&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;pop&lt;/code&gt;, and empowers developers to organize a bit its local mess.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>How I Keep Using Stacked Git at $WORK</title>
      <link>https://soap.coffee/~lthms/posts/StackedGit2.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGit2.html</guid>
      <pubDate>January 16, 2023</pubDate>
      <description>
        
        &lt;h1&gt;How I Keep Using Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-mint&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;One year ago, I have published an article summarizing &lt;a href=&quot;/~lthms/posts/StackedGit.html&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;my experience using
Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/a&gt;. Twelve months later,
enough has changed to motivate a spin-off piece.&lt;/p&gt;
&lt;h2&gt;Stacked Git is &lt;em&gt;Fast&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Firstly, it is important to state that my main complaint about
Stacked Git is now a thing of the past&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For fairness, I have removed the related section in my previous
write-up. &lt;/span&gt;
&lt;/span&gt;! Stacked Git does not feel slow
anymore, and far from it. This is because &lt;a href=&quot;https://github.com/stacked-git/stgit/discussions/185&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;Stacked Git 2.0 has been rewritten
in Rust&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. While RiiR
(&lt;em&gt;Rewrite it in Rust&lt;/em&gt;) is a running meme on the Internet, in this particular
case, the result is very exciting.&lt;/p&gt;
&lt;p&gt;Thanks to the performance boost, my Zsh prompt does not take 0.1s to
appear!&lt;/p&gt;
&lt;p&gt;Speaking of Zsh prompt, basically what I ended up displaying is &lt;code class=&quot;hljs&quot;&gt;(&amp;lt;TOP PATCH NAME&amp;gt; &amp;lt;APPLIED PATCHES COUNT&amp;gt;/&amp;lt;PATCHSET SIZE&amp;gt; &amp;lt;HIDDEN PATCHES COUNT)&lt;/code&gt;. For
instance, &lt;code class=&quot;hljs&quot;&gt;(fix-1337 1/2 3)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In case you want to take inspiration in my somewhat working configuration, here
is the snippet of interest.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; series_top=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg top 2&amp;gt; /dev/null)&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; total=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series 2&amp;gt; /dev/null | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; hidden=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series --hidden 2&amp;gt; /dev/null | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${total}&lt;/span&gt;&quot;&lt;/span&gt; -gt 0 ]]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; not_applied=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series | grep -E &apos;^-&apos; | wc -l)&lt;/span&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt; applied=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(($total - $not_applied)&lt;/span&gt;)&quot;&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${series_top}&lt;/span&gt;&quot;&lt;/span&gt; ]]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
        series_top=&lt;span class=&quot;hljs-string&quot;&gt;&quot;·&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;(&lt;span class=&quot;hljs-variable&quot;&gt;${status_color}&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;${series_top}&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${applied}&lt;/span&gt;/&lt;span class=&quot;hljs-variable&quot;&gt;${total}&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${hidden}&lt;/span&gt;)&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;  (&lt;span class=&quot;hljs-subst&quot;&gt;$(current_branch)&lt;/span&gt;)&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Branchless Workflow&lt;/h2&gt;
&lt;p&gt;Last year, I was using Stacked Git on top of git branches. More precisely, I
had one branch for each (stack of) Merge Request. It worked well, because my
typical MR counted 3 to 4 commits in average.&lt;/p&gt;
&lt;p&gt;Fast forward today, and things have changed on this front too. In a nutshell, I
have become a “one commit per MR” maximalist of sort&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It goes without saying that this approach comes with its set of
drawbacks too.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;During the past year, I’ve pushed fairly large commits which could have
been split into several smaller ones, for the sake of keeping my “one
commit per MR” policy. I have also had to manage large stacks of MRs. &lt;/span&gt;
&lt;/span&gt;. I find this
approach very effective to get more focused reviews, and to reduce the time it
takes for a given MR to be integrated into the main branch.&lt;/p&gt;
&lt;p&gt;My previous approach based on git branches did not scale well with
this new mindset, and during the course of the year, I stopped using
branches altogether&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I have not invented the branchless workflow, of
course.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;After it was first published, someone posted a link to my Stacked Git
article on Hacker News, and &lt;a href=&quot;https://news.ycombinator.com/item?id=29959224&quot; class=&quot;hover-rose&quot; marked=&quot;&quot;&gt;&lt;em&gt;@arxanas&lt;/em&gt; posted a comment about
&lt;code class=&quot;hljs&quot;&gt;git-branchless&lt;/code&gt;&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. I tried
the tool, and even if it never clicked for me, I was really compelled by
its core ideas.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;Similarly, &lt;a href=&quot;https://drewdevault.com/2020/04/06/My-weird-branchless-git-workflow.html&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Drew DeVault has published a complete article on its own
branchless workflow in
2020&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;These days, I proceed as follows.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I name each patch after the branch to which I will push it on our
upstream Git remote.&lt;/li&gt;
&lt;li&gt;99% of the time, I push my work using &lt;code class=&quot;hljs language-bash&quot;&gt;git push -f upstream @:$(stg top)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;I created a small git plugin I called &lt;code class=&quot;hljs&quot;&gt;git-prepare&lt;/code&gt; which allows
me to select one of the patch of my current patchset using &lt;code class=&quot;hljs&quot;&gt;fzf&lt;/code&gt;,
and which pops all other patches that are currently applied.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code class=&quot;hljs&quot;&gt;git-prepare&lt;/code&gt; is really straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/sh&lt;/span&gt;
patch=$(stg series -P | fzf)

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! $? -eq 0 ]] ; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; $?
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ -n &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;$(stg series -A)&lt;/span&gt;&quot;&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
    stg pop -a
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;

stg push &lt;span class=&quot;hljs-variable&quot;&gt;${patch}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main hurdle which I still need to figure out is how to deal with
stacked MRs. Currently, this is very manual. I need to remember
which commit belongs to the stack, the order and dependencies of
these commits, and I need to publish each commit individually using
&lt;code class=&quot;hljs language-bash&quot;&gt;stg push; git push @:$(stg top)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The pragmatic answer is definitely to come back to git branches &lt;em&gt;for
this particular use case&lt;/em&gt;, but it&apos;s not the &lt;em&gt;fun&lt;/em&gt; answer. So from
time to time, I try to experiment with alternative approaches. My current
intuition is that, by adopting a naming convention for my patches, I
could probably implement a thin tooling on top of Stacked Git to
deal with dependents commits.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Putting aside stacked MRs for now, I am really satisfied with my
workflow. It’s very lightweight and intuitive, and working without
Stacked Git now feels backward and clunky.&lt;/p&gt;
&lt;p&gt;So I will take this opportunity to thank one more time Stacked Git’s
authors and contributors. You all are making my professional like
easier with your project.&lt;/p&gt;
        
      </description>
    </item>
    
    
    
    <item>
      <title>How I Use Stacked Git at $WORK</title>
      <link>https://soap.coffee/~lthms/posts/StackedGit.html</link>
      <guid>https://soap.coffee/~lthms/posts/StackedGit.html</guid>
      <pubDate>January 16, 2022</pubDate>
      <description>
        
        &lt;h1&gt;How I Use Stacked Git at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;&lt;/h1&gt;&lt;div id=&quot;tags-list&quot;&gt;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/git.html&quot; class=&quot;tag hover-coral&quot; marked=&quot;&quot;&gt;git&lt;/a&gt; &lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#tag&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;/~lthms/tags/workflow.html&quot; class=&quot;tag hover-periwinkle&quot; marked=&quot;&quot;&gt;workflow&lt;/a&gt; &lt;/div&gt;
&lt;p&gt;According to &lt;a href=&quot;https://lobste.rs/s/s6quvg/stacked_git&quot; class=&quot;hover-peach&quot; marked=&quot;&quot;&gt;my Lobste.rs history&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, I
have run into &lt;a href=&quot;https://stacked-git.github.io&quot; class=&quot;hover-sky&quot; marked=&quot;&quot;&gt;Stacked Git&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; in early April
2021, and I remember that its promises hit a soft spot. A few weeks later, I was
submitting &lt;a href=&quot;https://github.com/stacked-git/stgit/pull/100&quot; class=&quot;hover-coral&quot; marked=&quot;&quot;&gt;a &lt;em&gt;pull request&lt;/em&gt; to teach Stacked Git to sign
commits&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#github&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;. It was all I needed to
start using it at &lt;code class=&quot;hljs language-bash&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;$WORK&lt;/span&gt;&lt;/code&gt;, and now it has become a cornerstone of my
development workflow.&lt;/p&gt;
&lt;h2&gt;What is Stacked Git?&lt;/h2&gt;
&lt;p&gt;Before going any further, it is probably a good idea to take a moment and
present Stacked Git. The website introduces the tool as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Stacked Git, &lt;em&gt;StGit&lt;/em&gt; for short, is an application for managing Git
commits as a stack of patches.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a few things to unpack here. First and as its name suggests, Stacked
Git is a tool built on top of Git&lt;label for=&quot;fn1&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn1&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;My main takeaway from my Pijul adventure is connected to this. Git
is not limited to the &lt;code class=&quot;hljs&quot;&gt;git&lt;/code&gt; binary. Git comes with a collection of powerful
forges, nice editor plugins, and years of good practices.&lt;/span&gt;
&lt;span class=&quot;footnote-p&quot;&gt;To this day, it’s neither the bugs nor the breaking changes that made me
quite Pijul. Those were expected. What I naively did not anticipate is the
dry feeling that Pijul was just the &lt;code class=&quot;hljs&quot;&gt;pijul&lt;/code&gt; binary, which left me with a
lot of tasks to do manually. &lt;/span&gt;
&lt;/span&gt;. It is &lt;em&gt;not&lt;/em&gt; a brand new VCS, and as
a consequence you keep using all your existing tools and plugins&lt;label for=&quot;fn2&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn2&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I am looking at you, Magit. &lt;/span&gt;
&lt;/span&gt;.
Secondly, Stacked Git helps you curate your Git history, by turning your
commits into patches, and your branches into stacks of patches. This speaks to
me, maybe because I have been fascinated by email-based workflows for quite
some time.&lt;/p&gt;
&lt;p&gt;To me, the two core features of Stacked Git are (1) allowing you to
name your commits, and (2) to navigate among them.
Together, they create a wonderful companion to help you keep your
history clean.&lt;/p&gt;
&lt;h2&gt;My Subset of Stacked Git&lt;/h2&gt;
&lt;p&gt;I do not want this article to be a Stacked Git tutorial.
Fortunately, I don’t really use the tool at its full potential.
I only care about a relatively small subset of commands I feel
comfortable with and use daily.&lt;/p&gt;
&lt;p&gt;First, to decide which commits are part of my “stack of patches,” I
can count of these commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg new NAME&lt;/code&gt; creates an empty commit, and gives it the name
&lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt;.
Having a way to identify a patch with a meaningful name that is
resistant to rebase and amend is very nice.
These are two properties commit hashes do not have.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg uncommit NAME&lt;/code&gt; names the most recent commit under my
stack with &lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt; and integrates it into it. I do this when I am
tasked to work on a merge request made by a colleague, for
instance.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg commit&lt;/code&gt; removes from my stack its last patch. I do this when
said commit has been merged into &lt;code class=&quot;hljs&quot;&gt;master&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once my stack of patches is ready, the fun begins.&lt;/p&gt;
&lt;p&gt;At a given time, a patch can either be (1) applied, (2) unapplied, or (3)
hidden. On the one hand, if a patch is applied it is part of the Git history.
On the other hand, unapplying a patch means removing it from the working branch
(but not from the stack of patches of Stacked Git). If a patch becomes
irrelevant, but you don’t want to remove it entirely because it can become
handy later, you can hide it. A hidden patch sits beside the stack of patches,
and can be reintegrated if need be.&lt;/p&gt;
&lt;p&gt;Analogous to &lt;code class=&quot;hljs&quot;&gt;git log&lt;/code&gt; ---which allows you to visualize your Git history---,
&lt;code class=&quot;hljs&quot;&gt;stg series&lt;/code&gt; gives you a view of the state of your stack of patches. Patches
prefixed with &lt;code class=&quot;hljs&quot;&gt;+&lt;/code&gt; (or &lt;code class=&quot;hljs&quot;&gt;&amp;gt;&lt;/code&gt;) are applied, while &lt;code class=&quot;hljs&quot;&gt;-&lt;/code&gt; means the patch is unapplied.&lt;/p&gt;
&lt;p&gt;Then,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg pop&lt;/code&gt; unapplies the patch on top of the list of applied
patches.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt; applies the patch on the bottom of the list of unapplied
patches.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;hljs&quot;&gt;stg goto NAME&lt;/code&gt; unapplies or applies the necessary patches so that
&lt;code class=&quot;hljs&quot;&gt;NAME&lt;/code&gt; becomes the top patch of the list of applied patches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; and the work tree are updated accordingly.&lt;/p&gt;
&lt;p&gt;In addition, &lt;code class=&quot;hljs&quot;&gt;stg sink&lt;/code&gt; and &lt;code class=&quot;hljs&quot;&gt;stg float&lt;/code&gt; allow reorganizing your
stack of patches, moving patches around.
Basically, they are like &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;, but without having to use
&lt;code class=&quot;hljs&quot;&gt;$EDITOR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Modifying patches is done with &lt;code class=&quot;hljs&quot;&gt;stg refresh&lt;/code&gt;.
It’s akin to &lt;code class=&quot;hljs&quot;&gt;git commit --amend&lt;/code&gt;, except it is more powerful because
you can modify any applied patches with the &lt;code class=&quot;hljs&quot;&gt;-p&lt;/code&gt; option.
I’d always encourage you to &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; first, because &lt;code class=&quot;hljs&quot;&gt;stg refresh -p&lt;/code&gt; remains unfortunately error-prone (nothing prevents you from targeting
the wrong patch).
But when used carefully, it can be very handy.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code class=&quot;hljs&quot;&gt;stg rebase REF&lt;/code&gt; moves your stack of patches on top of &lt;code class=&quot;hljs&quot;&gt;REF&lt;/code&gt;&lt;label for=&quot;fn3&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn3&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Stacked Git is supposedly able to detect, during a rebase, which of
your patches have been applied to your target branch. I’d rather use &lt;code class=&quot;hljs language-bash&quot;&gt;stg uncommit&lt;/code&gt; before doing the rebase, though. &lt;/span&gt;
&lt;/span&gt;.
It is akin to &lt;code class=&quot;hljs&quot;&gt;git rebase --onto&lt;/code&gt;, but more straightforward. What happens is
Stacked Git pop all the patches of my stack, reset the &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; of the current
branch to &lt;code class=&quot;hljs&quot;&gt;REF&lt;/code&gt;, and tries applying the patches one by one In case of
conflicts, the process stop, and I am left with an empty patch, and a dirty
work tree with conflicts to solve. The hidden gem is that, contrary to &lt;code class=&quot;hljs&quot;&gt;git rebase&lt;/code&gt;, the repository is not “in the middle of a rebase.”&lt;/p&gt;
&lt;p&gt;Suppose there are many conflicting patches still waiting in my stack of patches,
and an urgent task I need to take care of first. I can just leave them here. I
can switch to another branch, and when I come back, I get my patches back. I
call this feature “incremental rebases.”&lt;/p&gt;
&lt;p&gt;And that is basically it. In a nutshell, Stacked Git equips commits with the
same features as branches.&lt;/p&gt;
&lt;h2&gt;My Stacked Git Workflow&lt;/h2&gt;
&lt;p&gt;As mentioned in the introduction of this article, Stacked Git has become a
cornerstone of my workflow. I’ve been asked a few times what this workflow is,
and why Magit is not enough&lt;label for=&quot;fn4&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn4&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-left sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It’s always about Magit. ;) &lt;/span&gt;
&lt;/span&gt;. So let’s try to do that. But first, a
warning. Yes, because Stacked Git is only a wrapper above Git, everything I
will explain can be achieved using Git alone, especially if you are a Magit
wizard.&lt;/p&gt;
&lt;p&gt;Stacked Git makes just everything so more convenient to me.&lt;/p&gt;
&lt;h3&gt;Planning My Commits Ahead Of Time&lt;/h3&gt;
&lt;p&gt;I’ve been introduced to Git with a pretty simple workflow: I am
supposed to start working on a feature, and once it’s ready, I
can commit, and move on to the next task on my to-do list.&lt;/p&gt;
&lt;p&gt;To me, this approach is backward.
It makes you set your intent after the fact.
With Stacked Git, I often try to plan my final history /before
writing the very first line of code/.
Using &lt;code class=&quot;hljs&quot;&gt;stack new&lt;/code&gt;, I create my patches, and take the time to write
their description.
It helps me visualize where I want to go.
Then, I use &lt;code class=&quot;hljs&quot;&gt;stack goto&lt;/code&gt; to go back to the beginning of my stack,
and start working.&lt;/p&gt;
&lt;p&gt;It is not, and cannot be, an exact science. I often have to refine
them as my work progresses.
Yet, I think my Git history is cleaner, more focused, since I have
started this exercise.&lt;/p&gt;
&lt;h3&gt;Getting My Fixup Commits Right&lt;/h3&gt;
&lt;p&gt;Reviews are a fundamental aspect of a software developer job.
At &lt;code class=&quot;hljs&quot;&gt;$WORK&lt;/code&gt;, we use Gitlab and their merge requests workflow,
which I find very annoying, because it does not provide meaningful
ways to compare two versions of your submission&lt;label for=&quot;fn5&quot; class=&quot;sidenote-number margin-toggle&quot;&gt;&lt;/label&gt;&lt;input id=&quot;fn5&quot; type=&quot;checkbox&quot; class=&quot;margin-toggle&quot;&gt;&lt;span class=&quot;note-right sidenote note&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There is a notion of “versions” in Gitlab, but its ergonomics fall
short of my expectations for such a tool. &lt;/span&gt;
&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;What we end up doing is creating “fixup commits,” and we push them
to Gitlab so that reviewers can easily verify that their feedback
has correctly been taken into account.&lt;/p&gt;
&lt;p&gt;A fixup commit is a commit that will eventually be squashed into
another.
You can understand it as a delayed &lt;code class=&quot;hljs&quot;&gt;git commit --amend&lt;/code&gt;.
Git has some built-in features to manipulate them.
You create them with &lt;code class=&quot;hljs&quot;&gt;git commit --fixup=&amp;lt;HASH&amp;gt;&lt;/code&gt;, and they are
interpreted in a specific manner by &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;.
But they have always felt to me like a sordid hack.
It is way too easy to create a fixup commit that targets the wrong
commit, and you can end up with strange conflicts when you finally
squash them.
That being said, if used carefully, they are a powerful tool to
keep a Git history clean.&lt;/p&gt;
&lt;p&gt;I am not sure we are using them carefully, though.&lt;/p&gt;
&lt;p&gt;Some reviews can be excruciating, with dozens of comments to
address, and theoretically as many fixup commits to create.
Then you push all of them on Gitlab, and days later, after the
green light from the reviewer, you get to call &lt;code class=&quot;hljs&quot;&gt;git rebase&lt;/code&gt;
and discover your history is broken, you have tones of conflicts
to fix, and you’re good for a long afternoon of untangling.&lt;/p&gt;
&lt;p&gt;The main reason behind this mess is that you end up fixing a commit
from the &lt;code class=&quot;hljs&quot;&gt;HEAD&lt;/code&gt; of your working branch, not the commit itself.
But with Stacked Git, things are different.
With &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt;, I put my working tree in the best state possible
to fix a commit: the commit itself.
I can use &lt;code class=&quot;hljs&quot;&gt;stg new&lt;/code&gt; to create a fixup commit, with a meaningful
name.
Then, I am forced to deal with the potential conflicts it brings
when I call &lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once my reviewer is happy with my work, I can call &lt;code class=&quot;hljs&quot;&gt;stg squash&lt;/code&gt;.
It is less automated than &lt;code class=&quot;hljs&quot;&gt;git rebase -i&lt;/code&gt;, but the comfort I gained
during the development is worth this little annoyance.&lt;/p&gt;
&lt;h3&gt;Managing Stacked Merge Requests&lt;/h3&gt;
&lt;p&gt;At &lt;code class=&quot;hljs&quot;&gt;$WORK&lt;/code&gt;, we are trying to change how we deliver new features to
our &lt;code class=&quot;hljs&quot;&gt;master&lt;/code&gt; branch.
More precisely, we want to merge smaller contributions more
frequently.
We have had our fair share of large and complex merge requests that
were a nightmare to review in the past, and it’s really not a fun
position to be put in.&lt;/p&gt;
&lt;p&gt;For a few months, I have been involved in a project wherein we
decided /not/ to fall in the same trap again.
We agreed on a “planning of merge requests” and started working.
The first merge request was soon opened.
We’ve nominated an “owner” to take care of the review, and the rest
of the team carried on.
Before the first merge request was merged, the second one was
declared ready, and another owner was appointed.
Then, the owner of the first merge request had a baby, and yours
truly ended up having to manage two interdependent merge requests.&lt;/p&gt;
&lt;p&gt;It turns out Stacked Git is a wonderful tool to help me keep this
under control.&lt;/p&gt;
&lt;p&gt;I only have one branch, and I use the same workflow to deal with
feedback, even if they are coming from more than one merge
request.
To remember the structure of everything, I just prefix the name of
my patches with a merge request nickname.
So my stack will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;+ mr1-base
+ mr1-tests
+ mr1-doc
&amp;gt; mr2-command
- mr2-tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A reviewer leaves a hard-truth comment that requires a significant rework of
the oldest merge request? &lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; reverts my work tree in the appropriate
state, and &lt;code class=&quot;hljs&quot;&gt;stg push&lt;/code&gt; allows me to deal with conflicts one patch at a time. If
I need to spend more time on the oldest merge request at some point, I can
continue my work, knowing the patches related to the newest one are awaiting in
my stack.&lt;/p&gt;
&lt;p&gt;The most annoying part is when the time comes to push everything. I need to
&lt;code class=&quot;hljs&quot;&gt;stg goto&lt;/code&gt; at the last patch of each merge request, and &lt;code class=&quot;hljs&quot;&gt;git push HEAD:the-branch&lt;/code&gt;. It’s not horrible. But I will probably try to automate it at
some point.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I am really thankful to Stacked Git’s authors! Thank you! You are
making my interactions with Git fun and carefree. You provide me some of the
convenience of patch-based VCS like &lt;a href=&quot;http://darcs.net&quot; class=&quot;hover-mint&quot; marked=&quot;&quot;&gt;Darcs&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt; and
&lt;a href=&quot;https://pijul.org&quot; class=&quot;hover-lavender&quot; marked=&quot;&quot;&gt;Pijul&amp;nbsp;&lt;span class=&quot;icon&quot;&gt;&lt;svg&gt;&lt;use href=&quot;/~lthms/img/icons.svg#external-link&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/a&gt;, but without sacrificing the power of Git.&lt;/p&gt;
&lt;p&gt;I encourage anyone to at least give it a try, and I really hope I
will be able to contribute back to Stacked Git in the near future.&lt;/p&gt;
        
      </description>
    </item>
    
    
  </channel>
</rss>
