<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Matheus Tavares</title>
    <description>Matheus Tavares' personal website</description>
    <link>https://matheustavares.dev</link>
    <atom:link href="https://matheustavares.dev/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Committing without git</title>
        <description>&lt;p&gt;Our goal is to create a branch with two commits: the first adding a single
README file, and the second changing this file slightly. &lt;strong&gt;All of this
without running git.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;first-of-all-why&quot;&gt;First of all, why?&lt;/h2&gt;

&lt;p&gt;Chances are if you clicked on this post I don’t have to convince you why anyone
would want to do this… ‘cause it’s fun! :) But also, it should help understand
some of the main data structures in git, the “git objects”. I personally think
understanding how they work and how they relate to one another is deeply
valuable and allows for a better experience when using git.&lt;/p&gt;

&lt;h2 id=&quot;what-will-you-need&quot;&gt;What will you need?&lt;/h2&gt;

&lt;p&gt;This is a hands-on tutorial, in the sense that you should be able to copy
the code snippets and make commits without git on your own machine. We will be
doing everything with python (I wanted to do it in Bash, but Bash
strings cannot include the null byte and that complicates things quite a bit).&lt;/p&gt;

&lt;p class=&quot;warn-box&quot;&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; although following these steps should produce a valid git commit,
it’s advisable not to use this “in production” as git commands will perform
a lot of safe checks and special handling that we will skip for the sake
of simplicity. If you need to create commits programmatically, check
&lt;a href=&quot;https://libgit2.org/&quot;&gt;libgit2&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-git-object-btw&quot;&gt;What is a git object, BTW?&lt;/h2&gt;

&lt;p&gt;Object are immutable units of storage in Git. They are compressed using the
DEFLATE algorithm, and referenced by the SHA-1 hash of their contents (though
there is a work in progress to support SHA-256). You can see the objects at the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/objects&lt;/code&gt; directory of any git repo; some will be inside two-hex-digits
subdirectories (these are called loose object), and some will be collective
stored in files under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/objects/pack&lt;/code&gt; (these are called
packed objects). The latter is more optimized as it allows to use “deltas” to
minimize redundancies when storing similar objects.&lt;/p&gt;

&lt;p&gt;Objects are one of the most important structures in Git; they are responsible
for storing the different versions of the project files, as well as other
metadata like the structure of the directories, authors and dates of each
commit, etc. Here is an example containing the four most important git
objects and how they interact with one another:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/committing-without-git/git-objects.png&quot; alt=&quot;git objects diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yes, &lt;strong&gt;commits are not diffs&lt;/strong&gt;, but snapshots of the whole project at a given
time (stored in an efficient manner, of course). The diffs are generated on-the-fly
when needed, such as when running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git show &amp;lt;commit&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;making-a-blob&quot;&gt;Making a blob&lt;/h2&gt;

&lt;p&gt;Without further ado, let’s start writing some code. To start, we need a way
to make blobs (Binary Large Objects), which are used to store file contents. A
blob has the following structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;blob {content size}{null byte}{content}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In fact, the header part is similar across different objects, so let’s create a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_obj()&lt;/code&gt; auxiliary function, which will be responsible for creating and
storing a loose object in our git repo:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;hashlib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objtype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&apos;&apos;&apos;
    Writes the loose object to the git object data base and returns
    its sha1 object. The content must be a byte stream.
    &apos;&apos;&apos;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objtype&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashlib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hex_sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hex_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hex_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;makedirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist_ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Writing a blob now it’s a piece of cake:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write_blob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blob&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;making-a-tree&quot;&gt;Making a tree&lt;/h2&gt;

&lt;p&gt;Next, we need a way to describe the directory structure which will contain
our README file. That’s the job for a tree object, which is structured as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tree {content size}{null byte}[list of entries]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where each entry has the format:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{mode} {filename}{null byte}{sha1 of tree or blob in binary}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We won’t go into to much detail about the file mode, so its sufficient to say
that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100644&lt;/code&gt; represents a regular file with no execution permission.&lt;/p&gt;

&lt;p&gt;Note that, in git, all the file attributes (i.e. its name and mode) are stored
in the directory structure, not the blob. The blob only holds the file
contents. “What about subdirectories?” - you may ask. These are represented by
trees as well, whose hashes are referenced by the parent tree. Anyway, here is
our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write_tree()&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write_tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filenames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;entries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filenames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;entries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tree&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;commit-it&quot;&gt;Commit it&lt;/h2&gt;

&lt;p&gt;The last step is to create a commit to encompass our tree object. A commit
in git has the following structure, where the “parents” section is optional
and may contain as many parents as needed:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tree {hash}
parent hash1
parent hash2
...
author {name} &amp;lt;{email}&amp;gt; {author_date} {author_timezone}
committer {committer} &amp;lt;{email}&amp;gt; {committer_date} {committer_timezone}

{commit message}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Some important things to highlight here: the author and committer date are
stored as seconds since the Epoch; the timezone is encoded as an offset from
UTC; and yes, the author may be different from the committer. This happens,
for example, when you cherry-pick a commit authored by another person. The
new commit will have the same author, but you will be set as the committer.&lt;/p&gt;

&lt;p&gt;OK, let’s write our function to create a commit:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write_commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;committer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tree &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree_sha1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;parent &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;%z&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;committer &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;committer&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;%z&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;commit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;branches&quot;&gt;Branches&lt;/h2&gt;

&lt;p&gt;With all of the above set, we can write a simple function that takes one of
our created commits’ hash and creates a branch on it:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write_branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/refs/heads/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If this seems confusing to you it may be because we usually think of branches
as commit chains, but in reality, they are nothing more than labels. The way
git retrieves the commit chain (or better yet, the graph) is by traversing
the commits through their “parent” pointers, starting from the branch’s tip
commit. Furthermore, if we didn’t create a branch after making our commits here,
they would be considered dangling objects because they can’t be reached from
any reference (branch, tag, HEAD, etc.). So git’s garbage collector would
eventually prune them from the repo.&lt;/p&gt;

&lt;h2 id=&quot;lets-test&quot;&gt;Let’s test!&lt;/h2&gt;

&lt;p&gt;Finally, let’s wrap it all together:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# First commit
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;John Doe &amp;lt;john@doe&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;blob1_sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_blob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;This is a simple README file&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tree1_sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;README&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob1_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;commit1_sha1&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree1_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;s&quot;&gt;&quot;Add the README file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Second commit
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob2_sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_blob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;This is a simple README file&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;With one extra line&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tree2_sha1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;README&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blob2_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;commit2_sha1&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write_commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree2_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit1_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt;
                             &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Add another line to README&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Create branch
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my_branch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commit2_sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And now, let’s validate it with git:&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; git log -p my_branch

commit 28188fd39b658ff830cd063de722e3803561eef2 (my_branch)
&lt;span class=&quot;p&quot;&gt;Author: John Doe &amp;lt;john@doe&amp;gt;
Date:   Thu Dec 28 08:07:23 2023 -0300
&lt;/span&gt;
    Add another line to README

diff --git a/README b/README
&lt;span class=&quot;gh&quot;&gt;index a0a40df..fe62de5 100644
&lt;/span&gt;&lt;span class=&quot;gd&quot;&gt;--- a/README
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+++ b/README
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@@ -1 +1,2 @@&lt;/span&gt;
 This is a simple README file
&lt;span class=&quot;gi&quot;&gt;+With one extra line
&lt;/span&gt;
commit a33ef02efcf8616ff65faf746780971e740c31c6
&lt;span class=&quot;p&quot;&gt;Author: John Doe &amp;lt;john@doe&amp;gt;
Date:   Thu Dec 28 08:07:23 2023 -0300
&lt;/span&gt;
    Add the README file

diff --git a/README b/README
&lt;span class=&quot;p&quot;&gt;new file mode 100644
&lt;/span&gt;&lt;span class=&quot;gh&quot;&gt;index 0000000..a0a40df
&lt;/span&gt;&lt;span class=&quot;gd&quot;&gt;--- /dev/null
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+++ b/README
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@@ -0,0 +1 @@&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+This is a simple README file
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Success! :) You can find a condensed script version of this code here: &lt;a href=&quot;https://matheustavares.dev/assets/committing-without-git/commit.py&quot;&gt;commit.py&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Git Book, &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-Objects&quot;&gt;Chapter 10.2 - Git Objects&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;My &lt;a href=&quot;/slides/git_under_the_hood_en.pdf&quot;&gt;“Git Under the Hood”&lt;/a&gt; slides&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xbLVvrb2-fY&quot;&gt;Introduction to Git&lt;/a&gt; talk by Scott Chacon&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/5dab3dc6-3942-422e-d29d-3e8682ebc4df@gmail.com/T/#mf6c760fd87f7416d39e5ac54e9e33df9d835be87&quot;&gt;post: a tour of git’s object types&lt;/a&gt; by Emily Shaffer, Junio C Hamano, and others.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/pack-format&quot;&gt;pack-format docs&lt;/a&gt; (to understand more about packfiles and deltification).&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Thu, 28 Dec 2023 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/committing-without-git</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/committing-without-git</guid>
      </item>
    
      <item>
        <title>Git: Rewriting History 101</title>
        <description>&lt;p&gt;If there is one thing time-travel movies taught us is that trying to fix the
past may lead to dangerous consequences. Fortunately for us programmers, fixing
our development branches on Git is quite straightforward if you understand how
the commands work and what you should or should not do.&lt;/p&gt;

&lt;p&gt;Stick to the end for a terminal example :)&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/rewriting-history-101/bttf-meme.jpg&quot; alt=&quot;Back to the future meme&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with a simple question: why would you want to rewrite a Git branch?
The most common case, in my personal workflow, is to fix a series of commits
before publishing/merging them to a public branch or to apply review comments
before sending the next patch set iteration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING: As a rule of thumb, we should avoid rewriting a public branch that
is already being used by others!&lt;/strong&gt; (Read more about it
&lt;a href=&quot;https://git-scm.com/docs/git-rebase#_recovering_from_upstream_rebase&quot;&gt;here&lt;/a&gt;
and
&lt;a href=&quot;https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If you do so, the other developers who have work based onto your branch will
have a hard time fixing the diverged history later. The easiest way to “fix” a
commit that is already in a public branch is to make another commit on top.
You can even use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git revert &amp;lt;hash&amp;gt;&lt;/code&gt; to create a new commit that will
completely revert the unwanted commit for you.  Besides not breaking the
workflow of other devs, this has the added benefit of keeping the “real”
history of the code, as it has evolved.&lt;/p&gt;

&lt;p&gt;On the other hand, there is not much value in keeping the history of changes
made to a personal development branch (before being merged upstream) at each
review iteration.  Furthermore, you may want to commit frequently (even
incomplete work), but then rewrite history to organize your commits before
sending a Pull Request, for example. With that in mind, I will now discuss
about three techniques that allows us to rewrite branch history.&lt;/p&gt;

&lt;h2 id=&quot;1-git-reset-&quot;&gt;1) git reset &lt;hash&gt;&lt;/hash&gt;&lt;/h2&gt;

&lt;p&gt;This is by far the easiest way to “rewrite history” in Git. Passing a commit
hash to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset&lt;/code&gt; sets the current &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; to that commit. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; is
a branch, it will will effectively move the branch reference, thus rewriting
the branch. See an example below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/rewriting-history-101/reset.svg&quot; alt=&quot;git reset example&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset&lt;/code&gt; accepts many options like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--hard&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--soft&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--mixed&lt;/code&gt;,
etc.  See the &lt;a href=&quot;https://git-scm.com/docs/git-reset&quot;&gt;git reset man page&lt;/a&gt; for more
information.&lt;/p&gt;

&lt;h2 id=&quot;2-git-commit-amend&quot;&gt;2) git commit –amend&lt;/h2&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --amend&lt;/code&gt; we can actually modify a commit. However, it won’t
get you too far, as it only operates on the commit at the tip of the current
branch. You can edit both the commit’s contents (adding, removing, or
modifying files) and the commit’s metadata (i.e. the message, author, date,
etc.). Let’s see a toy example:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# First, let&apos;s create a commit:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;a &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;a
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add a
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Add a&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; a
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git log &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt;

commit 67afb26fbc2dd5018608d61803068405bcba4c6c &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Author: A U Thor &amp;lt;author@example.com&amp;gt;
Date:   Fri Jul 8 12:04:57 2022 &lt;span class=&quot;nt&quot;&gt;-0300&lt;/span&gt;

    Add a

diff &lt;span class=&quot;nt&quot;&gt;--git&lt;/span&gt; a/a b/a
new file mode 100644
index 0000000..7898192
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; /dev/null
+++ b/a
@@ &lt;span class=&quot;nt&quot;&gt;-0&lt;/span&gt;,0 +1 @@
+a

&lt;span class=&quot;c&quot;&gt;# Now suppose we want to amend this commit and add another file to it:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;a b
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add b
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;--amend&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# By default, `git commit --amend` will open your editor to amend the commit&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# message. You can supress this behavior with `--no-edit`. However, since we&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# are changing the commit&apos;s contents, let&apos;s modify the message accordingly.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Let&apos;s see the results:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git log &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt;

commit 9754c684d430ef206cbc65141bea20f82f9d51fa &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Author: A U Thor &amp;lt;author@example.com&amp;gt;
Date:   Fri Jul 8 12:04:57 2022 &lt;span class=&quot;nt&quot;&gt;-0300&lt;/span&gt;

    Add a and b

diff &lt;span class=&quot;nt&quot;&gt;--git&lt;/span&gt; a/a b/a
new file mode 100644
index 0000000..7898192
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; /dev/null
+++ b/a
@@ &lt;span class=&quot;nt&quot;&gt;-0&lt;/span&gt;,0 +1 @@
+a
diff &lt;span class=&quot;nt&quot;&gt;--git&lt;/span&gt; a/b b/b
new file mode 100644
index 0000000..7898192
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; /dev/null
+++ b/b
@@ &lt;span class=&quot;nt&quot;&gt;-0&lt;/span&gt;,0 +1 @@
+a

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the hash of the commit changed since its data changed. Now a fun
side-track experiment:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt;
9754c68 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Add a and b

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;--amend&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-edit&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt;
e9475a6 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Add a and b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We did not change any files, author, or the message this time. So why did the
hash change? That’s because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --amend&lt;/code&gt; automatically updates the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit date&lt;/code&gt; (but not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;author date&lt;/code&gt;). You can see that running
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git show --format=fuller 9754c68 e9475a6&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;3-git-rebase--i-aka-interactive-rebase&quot;&gt;3) git rebase -i (a.k.a. interactive rebase)&lt;/h2&gt;

&lt;p&gt;Finally, let’s get to the fun stuff!&lt;/p&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt; takes a set of commits and reapply them over a
different base commit. It can be used as a “substitute” for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt;,
although the end result in the commit graph is not the same (rebase will rewrite
history, merge won’t). I won’t go into any further details about this in this
post, but I have some visual explanations at &lt;a href=&quot;/slides/git_under_the_hood.pdf#page=48&quot;&gt;this set of slides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will focus on a specific rebase operation mode, called “interactive rebase”,
which is enabled with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--interactive&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-i&lt;/code&gt;) flag. In this mode, git
will let you edit the commits before rebasing them. Note that, if you do not
specify a different base, you are effectively only editing the commits :)&lt;/p&gt;

&lt;p&gt;Time for another example! For the simplicity, I will use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make_commit&lt;/code&gt; bash
function which receives a single parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt;, creates a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt;
containing the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt;, and then commits the file with a message “Add $1”.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# First let&apos;s create a few commits&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make_commit a
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make_commit b
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make_commit c
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make_commit d
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt;

83671c8 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD -&amp;gt; main&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Add d
c83b71b files: Add c
c467721 files: Add b
f997aea files: Add a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To specify how far back we want to rewrite our branch, we will give git a base
commit. You can use a SHA-1 hash or a &lt;a href=&quot;https://git-scm.com/docs/gitrevisions&quot;&gt;revision
parameter&lt;/a&gt;, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD~3&lt;/code&gt;, which
&lt;em&gt;roughly&lt;/em&gt; means “the third ancestor of HEAD”. So, if we want to modify the last
two commits from our example above, we can specify the base either as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c467721&lt;/code&gt;
or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD~2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, when you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase -i HEAD~2&lt;/code&gt;, git will open a file called
“git-rebase-todo” in your configured editor. This file will contain all commits
in the range between (but not including) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD~2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; (including).
Something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pick c83b71b Add c
pick 83671c8 Add d

# &amp;lt;a bunch of comment lines&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each [uncommented] line in this file is an action that git will perform (from
top to bottom) on top of our base (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD~2&lt;/code&gt;), in order to reconstruct the
branch. The first word of each line is the command. By default, all lines will
have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick&lt;/code&gt; command, which will basically apply the commit as-is. But there
are many other commands, and their syntax might differ a bit from each other.
Fortunately, you don’t have to memorize anything! All of the commands and their
syntaxes are displayed as comments in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-rebase-todo&lt;/code&gt; file for our
reference.&lt;/p&gt;

&lt;p&gt;Back to our example, suppose we want to change the commit message of the commit
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;83671c8 Add d&lt;/code&gt;. To do that, simply replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reword&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;, as the
commands can be abbreviated), save the file, and close it. Git will apply
the commit and open your editor with the previous message so that you can
rewrite it. After you complete, you can save and close the file, and that is
it. The rebase is done :)&lt;/p&gt;

&lt;p&gt;What about a more complex change? What if we want to add extra changes to
a commit? Well, than we can replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edit&lt;/code&gt;, making git stop right
after applying that commit and giving us the chance to modify it with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --amend&lt;/code&gt;. You can even make new commits at this point or use
something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cherry-pick&lt;/code&gt;. After you are done with the changes, use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase --continue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;During an interactive rebase, there may be conflicts between a commit git is
trying to apply (marked with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick&lt;/code&gt;) and a previous one that you have modified.
In case that happens, you have to delete your whole re… NO, no, wait! Don’t
panic. You just have to resolve the conflict, mark the files as resolved with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;, and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase --continue&lt;/code&gt; :)&lt;/p&gt;

&lt;p&gt;At any point in time, you can also abort the whole rebase operation with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git
rebase --abort&lt;/code&gt; or edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-rebase-todo&lt;/code&gt; file (with the remaining actions
to be performed) by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase --edit-todo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, it is worth noticing that you can combine two (or more) commits with
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squash&lt;/code&gt; command. Git will meld the said commit with the previous one on
the todo list and open an editor so that you can adjust the message of the
combined commit as appropriate. Although there is no command to split a commit
in two (or more), you can also do that by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edit&lt;/code&gt;. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt; hits
that commit, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset HEAD^&lt;/code&gt; to undo the commit, leaving the changes in
the working tree. Then add the changes you want in the first commit and
run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit&lt;/code&gt;, repeating that until you have all the individual changes
in their respective commits.&lt;/p&gt;

&lt;h3 id=&quot;a-complete-example&quot;&gt;A complete example&lt;/h3&gt;

&lt;div class=&quot;asciicast-target&quot; data-fname=&quot;git-rebase-i-examples&quot;&gt;&lt;/div&gt;

&lt;h3 id=&quot;extra-rebase-tips&quot;&gt;Extra rebase tips&lt;/h3&gt;

&lt;p&gt;To remove a commit, you can either use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drop&lt;/code&gt; command or simply remove
the line from the todo file. Note however that the second way is a bit
dangerous as you might accidentally remove a line and have a commit dropped.
To avoid that, you can set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rebase.missingCommitsCheck&lt;/code&gt; with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git config rebase.missingCommitsCheck error &lt;span class=&quot;c&quot;&gt;# or warn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will make git rebase abort if a expected line is missing, forcing you
to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drop&lt;/code&gt; but also avoiding the accidental drop possibility.&lt;/p&gt;

&lt;p&gt;Also, note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase -i&lt;/code&gt; can also be used for other things besides
rewriting history. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec&lt;/code&gt; command (or the analogous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-x&lt;/code&gt; CLI option) are
very useful when you want to run a given command after each commit in a series.
For example, if you want to make sure that every commit in your development
branch is buildable and passes the automated tests, you could use something
like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase -i -x &apos;make &amp;amp;&amp;amp; make tests&apos; HEAD~10&lt;/code&gt;. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make &amp;amp;&amp;amp; make tests&lt;/code&gt;
fail in any commit, git will stop the rebase and let you fix the bug before
continuing.&lt;/p&gt;

&lt;p&gt;Finally, if you need to rewrite &lt;strong&gt;all&lt;/strong&gt; commits in a branch, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD~&amp;lt;n&amp;gt;&lt;/code&gt;
strategy won’t work… But fear not! There is an option for that: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--root&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h2&gt;

&lt;p&gt;If you want to know more about rewriting history, I &lt;strong&gt;really recommend&lt;/strong&gt; this
chapter from the Pro Git book:
&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History&quot;&gt;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you liked this post and got as excited as I was the first time I learned
about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase -i&lt;/code&gt;. I think this was one of the features that inspire me to
learn more about Git and, later, start contributing to the project. Thanks
for reading. Happy [and wise] rebasing :)&lt;/p&gt;
</description>
        <pubDate>Fri, 08 Jul 2022 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/rewriting-history-101</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/rewriting-history-101</guid>
      </item>
    
      <item>
        <title>The "Schrödinger's tree object": is it there or not?</title>
        <description>&lt;p&gt;Reading &lt;a href=&quot;https://www.reddit.com/r/git/comments/qeya3e/comment/hhyoyx7/?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;a reddit comment&lt;/a&gt;
a while ago, I learned about a somewhat “&lt;em&gt;mysterious&lt;/em&gt;” git object which can be both present
and absent at the same time! Well… not by the same definition of “&lt;em&gt;presence&lt;/em&gt;”,
but that spoils the fun, right? :P Let’s see this object in more details.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;If you want to check whether a given object &lt;strong&gt;exists&lt;/strong&gt; in a git repository, you
can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rev-parse&lt;/code&gt;. As the man page says:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;--verify
	   Verify that exactly one parameter is provided, and that it can be
	   turned into a raw 20-byte SHA-1 that can be used to access the
	   object database. If so, emit it to the standard output; otherwise,
	   error out.
	   [...]
	   To make sure that $VAR names an existing object of any
           type, git rev-parse &quot;$VAR^{object}&quot; can be used.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s run an example inside the git.git repository:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git rev-parse &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; e83c5163316f89bfbde7d9ab23ca2e25604af290^&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;object&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
e83c5163316f89bfbde7d9ab23ca2e25604af290
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok. What about an nonexistent object?&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git rev-parse &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; 0000000000000000000000000000000000000000^&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;object&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
fatal: Needed a single revision
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
128
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hm, nothing out of the ordinary here. But the fun starts when we look at the
“&lt;em&gt;mysterious&lt;/em&gt;” SHA1 hash &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4b825dc642cb6eb9a060e54bf8d69288fbee4904&lt;/code&gt;. If we
list all objects in the git.git repository using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cat-file&lt;/code&gt; and grep for
this particular hash, we get &lt;strong&gt;nothing&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git cat-file &lt;span class=&quot;nt&quot;&gt;--batch-check&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%(objectname)&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--batch-all-objects&lt;/span&gt; | &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;4b825dc642cb6eb9a060e54bf8d69288fbee4904
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;However …&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rev-parse&lt;/code&gt; seems to disagree about the object’s &lt;strong&gt;presence&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git rev-parse &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; 4b825dc642cb6eb9a060e54bf8d69288fbee4904^&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;object&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
4b825dc642cb6eb9a060e54bf8d69288fbee4904
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hmm, what is happening here? Is the object there or not? Let’s go a bit further
with a reduced test case:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git init /tmp/repo
Initialized empty Git repository &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; /tmp/repo/.git/

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /tmp/repo rev-parse &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; 4b825dc642cb6eb9a060e54bf8d69288fbee4904^&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;object&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
4b825dc642cb6eb9a060e54bf8d69288fbee4904
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wait, what? The just-created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp/repo&lt;/code&gt; repository clearly has no objects:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /tmp/repo/.git/objects

/tmp/repo/.git/objects
├── info
└── pack

2 directories, 0 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Is rev-parse broken? Let’s try something else… Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cat-file&lt;/code&gt; to
print all object hashes and grep for our target did not produce any result.
But &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; can also be used to print metadata about a given list of hashes.
Let’s try that with our hash:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;4b825dc642cb6eb9a060e54bf8d69288fbee4904 | &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	git &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /tmp/repo cat-file &lt;span class=&quot;nt&quot;&gt;--batch-check&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;%(objectname) %(objecttype) %(objectsize) %(objectsize:disk)&apos;&lt;/span&gt;
4b825dc642cb6eb9a060e54bf8d69288fbee4904 tree 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hmmmm, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4b825dc642&lt;/code&gt; is a tree object of size 0, both on disk and
decompressed. Nevertheless, we saw that there are no objects on disk… I was
intrigued.  Is this hardcoded somewhere in git? And if so, why?&lt;/p&gt;

&lt;p&gt;My first attempt to “uncover the mystery” was:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; git.git &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;4b825dc642
git-rebase--preserve-merges.sh:288:             &lt;span class=&quot;nv&quot;&gt;ptree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4b825dc642cb6eb9a060e54bf8d69288fbee4904
t/oid-info/hash-info:16:empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
t/t0015-hash.sh:26:     &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;4b825dc642cb6eb9a060e54bf8d69288fbee4904 actual
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first match comes from a shell script which uses our mysterious hash
(a.k.a. the empty tree hash) as a fallback if a commit does not have a parent.
This is done to compare the hashes of a commit’s tree and its parent commit’s
tree to decide whether the commit is considered “empty” (i.e. its tree is the
same as the parent). The other two matches come from the test suite. Hmm, so no
hardcoded value on the actual object reading code? That’s curious… Let’s see
what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; has to show us! Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rev-parse -e
4b825dc642cb6eb9a060e54bf8d69288fbee4904&lt;/code&gt; through the debugger, we can see the
following call chain:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cmd_cat_file()
  cat_one_file()
    repo_has_object_file()
      ...
        do_oid_object_info_extended()
	  find_cached_object()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And at the footer of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find_cached_object()&lt;/code&gt; we have this code:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oideq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the_hash_algo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty_tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty_tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aha! So we have this “empty tree” hash saved somewhere… Well, turns out that
my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git grep&lt;/code&gt; search did not found it because it is not defined in hex format!
See:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define EMPTY_TREE_SHA1_BIN_LITERAL \
	 &quot;\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60&quot; \
	 &quot;\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04&quot;
#define EMPTY_TREE_SHA256_BIN_LITERAL \
	&quot;\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1&quot; \
	&quot;\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5&quot; \
	&quot;\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc&quot; \
	&quot;\x53\x21&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last thing to “uncover” is: why is this hash value hardcoded? Well, for
that we can find the explanation using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git blame&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tig blame&lt;/code&gt;).
The code at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find_cached_object()&lt;/code&gt; comes from the commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;346245a1bb
(&quot;hard-code the empty tree object&quot;,
2008-02-13)&lt;/code&gt;, which says:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit 346245a1bb6272dd370ba2f7b9bf86d3df5fed9a
Author: Jeff King &amp;lt;peff@peff.net&amp;gt;
Date:   Wed Feb 13 06:25:04 2008 -0500

    hard-code the empty tree object
    
    Now any commands may reference the empty tree object by its
    sha1 (4b825dc642cb6eb9a060e54bf8d69288fbee4904). This is
    useful for showing some diffs, especially for initial
    commits.
    
    Signed-off-by: Jeff King &amp;lt;peff@peff.net&amp;gt;
    Signed-off-by: Junio C Hamano &amp;lt;gitster@pobox.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There we have it, mystery uncovered!&lt;/p&gt;

&lt;p&gt;Ok, Ok… I definitely over-dramatized this process… But I find it quite
interesting to run this kind of analysis! It helps better understand parts of a
code base, reproduce bugs, or even find the reason why a certain function (or
line of code) was written in a given way. So I decided to document this
particular small adventure. I hope you also enjoyed the “Schrödinger’s
object” :)&lt;/p&gt;
</description>
        <pubDate>Sun, 05 Jun 2022 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/empty-tree</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/empty-tree</guid>
      </item>
    
      <item>
        <title>Faster Git checkouts on NFS and SSD with parallelism</title>
        <description>&lt;p class=&quot;warn-box&quot;&gt;&lt;strong&gt;Update (2022/07/13)&lt;/strong&gt;: I defended my Master’s dissertation about parallel
checkout and was approved in the program :) Here are the dissertation and
defense slides:&lt;br /&gt;&lt;br /&gt;
&lt;span style=&quot;display: block&quot; class=&quot;tc&quot;&gt;
&lt;a href=&quot;https://matheustavares.dev/assets/msc-dissertation.pdf&quot; class=&quot;mh2&quot;&gt;MSc Dissertation&lt;/a&gt; |
&lt;a href=&quot;https://matheustavares.dev/assets/msc-defense-slides.pdf&quot; class=&quot;mh2&quot;&gt;MSc Defense Slides&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;June 2021 marked the release of 
&lt;a href=&quot;https://lore.kernel.org/git/xmqqa6o3xj2e.fsf@gitster.g/&quot;&gt;Git 2.32.0&lt;/a&gt;, which
includes the new “parallel checkout” mode. This feature can &lt;strong&gt;speed up
some checkout operations by up to 3.6x on SSDs and 4.5x on NFS mounts!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, it benefits not only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;, but all Git commands that make
use of the checkout machinery, including: clone, reset, switch, restore, merge,
and others.&lt;/p&gt;

&lt;p&gt;I’ve worked on this project with other Git contributors for about an
year, and I’m very happy that it is finally available for everyone to try it
out! In this post, I’d like to discuss a little bit about the cases in which
parallel checkout works the best, and why is that.&lt;/p&gt;

&lt;div class=&quot;success-box&quot;&gt;
  &lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;Parallel checkout produces the best results for &lt;strong&gt;(large)&lt;/strong&gt; repos on
SSDs and NFS mounts.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;It is &lt;strong&gt;not recommended&lt;/strong&gt; for small repos and/or repos on HDDs
(without prior benchmarking), as it can worsen performance.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Enable parallel checkout by setting the desired number of parallel
workers with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git config checkout.workers &amp;lt;N&amp;gt;&lt;/code&gt;. One means sequential mode
(default).&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#motivation&quot;&gt;Motivation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#benchmark&quot;&gt;Benchmark&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#ssds&quot;&gt;SSDs&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#hdds&quot;&gt;HDDs&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#nfs&quot;&gt;NFS&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#win-benchmark&quot;&gt;Windows benchmark&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;Conclusions&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#how-to-enable&quot;&gt;How to enable&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#notes-on-parallel-ineligible-entries&quot;&gt;Notes on parallel-ineligible entries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#source-code-and-extra-material&quot;&gt;Source code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Checkout is usually a fast operation when updating a small number of files,
but performance can become a problem as the workload grows. This is specially
critical for Git users over networked file systems; which, due to the higher
I/O latencies, may experience some checkout commands taking up to 50x or even
130x more time than local file systems.&lt;/p&gt;

&lt;p&gt;To put it into perspective, a full
checkout of the Linux repository (which contains over 70K files), takes around
8 seconds on a local Linux machine with SSD, but it can take &lt;strong&gt;5 to 15 minutes on
network file systems&lt;/strong&gt;. Furthermore, Linux is not even the largest repository
versioned through Git: the Chromium repository has about 400K working tree
files with a repo size of 36 GiB; and Windows has &lt;a href=&quot;https://devblogs.microsoft.com/bharry/the-largest-git-repo-on-the-planet/&quot;&gt;over 3.5M working tree
files, in a repo of 300
GiB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that in mind, the goal of this project was &lt;strong&gt;to parallelize the
working tree update phase of checkout and improve its performance for large
workloads, specially over NFS&lt;/strong&gt;. Note that other important subtasks of
checkout, like the tree traversal or index update code, are beyond the scope of
this work.&lt;/p&gt;

&lt;h2 id=&quot;benchmark&quot;&gt;Benchmark &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Since the primary goal was to speedup operations with many file creations,
I chose to benchmark a command where this is the main bottleneck:
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout .&lt;/code&gt; execution on an empty working tree of the Linux kernel
repository (version 5.12). This requires the creation of over 70 thousand
files.&lt;/p&gt;

&lt;p&gt;The command was benchmarked on two instances of the Linux kernel repository:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Packed Objects&lt;/strong&gt;: a Linux clone containing all objects reachable from v5.12
on a single packfile (8.2M objects, totaling 3.5 GiB of real and disk size);&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Loose Objects&lt;/strong&gt;: a shallow clone (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--depth=1&lt;/code&gt;) containing only the
objects from v5.12 itself, expanded to loose format (~76K objects, totaling
254MiB of real size, or 454MiB of disk size);&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; the “Loose Objects” benchmark was created mostly for research purposes.
This artificial case should not happen much in practice, since Git packs loose
objects when they surpass the 6700 threshold (and our repo have 12x that
value).&lt;/p&gt;

&lt;p&gt;I’ll interleave the benchmark results with some profiling plots (for the
sequential checkout). These were generated to better understand which
tasks/functions consume the most time during the execution of the benchmarked
checkout command in each storage type.  The profiling data were collected using
the &lt;a href=&quot;https://github.com/iovisor/bcc&quot;&gt;bcc-tools&lt;/a&gt;, which provides both on- and
off-CPU profilers, allowing us to properly see the time spent on I/O. For
simplicity, I’ll only show a summary of the most time-consuming functions, but
you can &lt;a href=&quot;https://matheustavares.dev/annexes/parallel-checkout/profiling&quot;&gt;check this page&lt;/a&gt;
for the full Flamegraphs.&lt;/p&gt;

&lt;p&gt;The benchmark was executed on different Linux machines (with SSDs, HDDs, and NFS
mounts), and sampled each measurement 15 times to plot the mean runtime with a
confidence interval of 95%. Additionally, the machines caches have been
cleaned before each sampling.&lt;/p&gt;

&lt;p class=&quot;warn-box&quot; id=&quot;machines-info&quot;&gt;&lt;strong&gt;Machines info&lt;/strong&gt;&lt;br /&gt;
Please &lt;a href=&quot;https://matheustavares.dev/annexes/parallel-checkout/machine-info&quot;&gt;check this page&lt;/a&gt;
for the hardware and software description of the machines used in this benchmark.&lt;/p&gt;

&lt;h3 id=&quot;ssds&quot;&gt;SSDs &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Starting with the SSDs, we have three machines: Mango and Grenoble both have 4
cores with 2 threads per core (8 logical cores), and Songbird has 6 cores with
2 threads per core (12 logical cores):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/mango-ssd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Mango&amp;quot; - SSD&quot; /&gt;
&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/grenoble-ssd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Grenoble&amp;quot; - SSD&quot; /&gt;
&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/songbird-ssd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Songbird&amp;quot; - SSD&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;success-box&quot;&gt;&lt;strong&gt;The SSD plots show speedups ranging from 2.5x to 3.6x on the packed objects
case, and 5.6x to 7.2x on the loose objects case!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On all three machines, we got the best overall results at around 16 to 32
workers for the packed objects, and 64 workers for the loose objects. But
notice that we start seeing diminishing returns around 8 workers. Thus, values
higher than that may not be worth the additional usage of system resources
(like RAM and I/O bandwidth).&lt;/p&gt;

&lt;p&gt;Let’s take a look at the most time consuming functions on a sequential checkout
in one of these machines:
&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/ebpf-summary/mango-ssd.svg&quot; alt=&quot;Checkout Profile on Mango - SSD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For the packed case, most of the time is spent on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inflate()&lt;/code&gt;, which is the
zlib function responsible for decompression. This is CPU-bound, and parallelizes
quite well with multiple objects. On the loose case, most of the time is spent
on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filemap_fault()&lt;/code&gt;, which is the kernel function responsible for reading
file’s contents on a page fault of a memory mapped region (see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap(2)&lt;/code&gt;).
Because of its architecture, SSD allows for
&lt;a href=&quot;https://www.csc.lsu.edu/~fchen/publications/papers/TOS16.pdf&quot;&gt;internal parallelism&lt;/a&gt;,
which can be better exploited when there are more outstanding requests in the I/O queue.
The increased I/O queue depth also allows for better optimizations to
be employed by the I/O scheduler (such as request reordering and merging).&lt;/p&gt;

&lt;h3 id=&quot;hdds&quot;&gt;HDDs &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;We will be looking at three machines on the HDD tests: Wall-e and Cicada have
4 logical cores each, and Grenoble has 8 (all with Intel’s Hyper-Threading).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/wall-e-hdd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Wall-e&amp;quot; - HDD&quot; /&gt;
&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/grenoble-hdd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Grenoble&amp;quot; - HDD&quot; /&gt;
&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/cicada-hdd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Cicada&amp;quot; - HDD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see, parallel checkout was not very effective on the HDDs. All three
machines achieved &lt;em&gt;some&lt;/em&gt; improvement in the packed objects case, but the
overall speedup was too small. The loose case, on the other hand, saw massive
performance degradations. Again, let’s take a look at the performance
profile for one of these machines:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/ebpf-summary/cicada-hdd.svg&quot; alt=&quot;Checkout Profile on Cicada - HDD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we can see, checkout spends almost all its run time reading the objects
from the HDD. However, unlike the SSD, HDDs can typically only execute a single
operation at each time. Depending on the I/O patterns, the increase in the I/O queue
depth &lt;em&gt;*might*&lt;/em&gt; allow for some scheduler optimizations that reduce the overall
disk-seeking time. If that is not the case, however, the concurrent requests
from parallel checkout may end up only further stressing the disk (think about
fights for critical resources), and degrading the performance. I &lt;strong&gt;suspect&lt;/strong&gt; that
this is what we are seeing in the loose case checkout. The files may be so
scattered over the disk that there is not enough opportunity for request merging
by the I/O scheduler. As for the packed case, the scheduler should be able to
take more advantage of the increased I/O queue depth, as the objects are stored
in a single file.&lt;/p&gt;

&lt;p&gt;Yes, there is fragmentation – and the more fragmented case, Wall-e, actually
saw higher speedups than the less fragmented ones – however, the number of
fragments here don’t come even close to the number of discontinuous disk
chunks used to store the loose objects.&lt;/p&gt;

&lt;h3 id=&quot;nfs&quot;&gt;NFS &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;I used two setups for the NFS tests: one with machine Cicada as the NFS server
and machine Mango as the NFS client (both on LAN connected through 5GHz Wi-Fi),
and another one using two AWS EC2 instances and an EBS gp3 volume for storage
(which is SSD-based). Let’s start with the EBS one:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/nfs-gp3.svg&quot; alt=&quot;Checkout Times on NFS from SSD - AWS EBS gp3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the Cicada NFS setup, the checkout benchmark with the Linux repository was
taking too much time &lt;em&gt;(almost an hour for
a single execution of the sequential checkout on the SSD and over two hours on
the HDD)&lt;/em&gt;, so I used the Git repository instead. This repo contains
about 4k files at v2.32.0. The packed and loose repository versions were set up
exactly like the Linux ones. The first ended up with ~310K objects,
and the second ended up with ~4K objects. Let’s see the results:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/nfs-cicada-hdd.svg&quot; alt=&quot;Checkout Times on NFS from HDD - Cicada&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We obviously cannot compare the times from the two plots above as they are using
different repositories, hardware, configurations, and etc. But I wanted
to see what difference an SSD makes on a parallel checkout over NFS.
Fortunately, Cicada also has a small 20 GiB SSD :) Well, it is meant for
caching and accelerating the Windows boot, not for general storage. But let’s
give it a shot anyway:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/nfs-cicada-ssd.svg&quot; alt=&quot;Checkout Times on NFS from HDD - Cicada&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;success-box&quot;&gt;
  &lt;p&gt;&lt;strong&gt;On the NFS tests we got the following speedups (respectively for packed and
loose case):&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;4.5x and 5.2x on the EBS gp3 SSD setup &lt;em&gt;with the Linux repository&lt;/em&gt;;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;2.6x and 3.4x on the Cicada  HDD setup &lt;em&gt;with the Git repository&lt;/em&gt;;&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;2.9x and 5.5x on the Cicada  SSD setup &lt;em&gt;with the Git repository&lt;/em&gt;.&lt;/strong&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;The best results were at around 32 to 64 workers on all three setups. But we
start to get diminishing returns from 8 workers, so this seems to be a good
value for NFS mounts, as we can achieve good performance without overusing the
system’s resources.&lt;/p&gt;

&lt;p&gt;Let’s see the profile plot for the NFS from EBS:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/ebpf-summary/nfs-gp3.svg&quot; alt=&quot;Checkout Profile on NFS - EBS gp3 SSD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Two functions dominate the execution time: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open()&lt;/code&gt; with 44% of the total
runtime, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstat()&lt;/code&gt;, with 33~40%. For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open()&lt;/code&gt;, the most time consuming
calls are the ones creating new files in the working tree, and their runtime is
equally divided between two NFS operations: OPEN and SETATTR. Both of them
require one round-trip to the server for each call.  As for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstat()&lt;/code&gt;, the cost
majorly comes from having to flush previous write operations (which were
locally cached) to the server. This is required in order to update some file
attributes, like the last modification time, which must be returned by
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstat()&lt;/code&gt;. For both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstat()&lt;/code&gt;, practically the entire time is
spent off-CPU, either sending requests to the NFS server or waiting on its
responses. Since NFS servers are typically able to process multiple connections
simultaneously, parallel checkout can be an effective way to amortize the
network latency and also promote parallelism in server work associated with
these operations.&lt;/p&gt;

&lt;p&gt;Finally, I also wanted to see what results we could get on single-core
machines. To do that, I disabled all cores but one on both the NFS client and
server of the Cicada setup (which can be done by writing ‘0’ to the special
files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/sys/devices/system/cpu/cpu[1-9]*/online&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/benchmark/one-core/nfs-cicada-hdd.svg&quot; alt=&quot;Checkout Times on NFS from HDD - Cicada - One Core&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The results were very similar to the ones above, with the optimal configuration
around 8 to 16 workers. This suggests that the performance gain we get from the
parallelism on NFS is also applicable for single-core machines.&lt;/p&gt;

&lt;h2 id=&quot;win-benchmark&quot;&gt;Windows benchmark &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;It would be impracticable to repeat this performance tests in every system and
machine architecture where Git is used. However, I still wanted to see how
parallel checkout behaves on a different operating system, so I ran the local
benchmarks on Microsoft Windows as well. It has a large user base and an active
development community on Git. Besides, it is not a UNIX-like system (differently
then macOS, BSD, and Linux), so it is a good choice to complement the benchmarks
we already have on Linux.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/windows/mango-ssd.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Mango&amp;quot; - SSD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://matheustavares.dev/assets/parallel-checkout/windows/cicada-hdd-linux.svg&quot; alt=&quot;Checkout Times on Machine &amp;quot;Cicada&amp;quot; - HDD&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;From the benchmarks, I would suggest using something around 8
workers on NFS mounts, and perhaps as many workers as the number of logical
cores on local SSDs (at least on Linux).&lt;/p&gt;

&lt;p&gt;For HDDs, I would not recommend enabling parallel checkout, unless you have
already ran some tests to access the performance on your specific machine and
Git repo. You can do that, for example, with something like the following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Note: expects $PWD to be the git repo you want to run the benchmark at.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Also, hyperfine (https://github.com/sharkdp/hyperfine) must be installed.&lt;/span&gt;


&lt;span class=&quot;nv&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mktemp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; ./tmp-worktree-XXXX&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
git worktree add &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tmpdir&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; HEAD &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tmpdir&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    hyperfine &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; /bin/bash &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rm -rf * &amp;amp;&amp;amp; sync &amp;amp;&amp;amp; sudo /sbin/sysctl vm.drop_caches=3&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; WORKERS 1,2,4,8,16,32,64 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;&apos;git -c checkout.workers={WORKERS} checkout .&apos;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
git worktree remove &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$tmpdir&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;how-to-enable&quot;&gt;How to enable &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Set the desired number of parallel workers with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext tc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git config [--global|--local] checkout.workers &amp;lt;N&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The default value is one, i.e. sequential mode.&lt;/p&gt;

&lt;p&gt;You can also change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout.thresholdForParallelism&lt;/code&gt; configuration, which
defines the minimum number of files for which Git should enable parallelism.
This avoids the cost of spawning multiple workers and performing inter-process
communication when there is not enough workload for parallelism. (The default
value is 100, which should be reasonable in most cases.)&lt;/p&gt;

&lt;h2 id=&quot;notes-on-parallel-ineligible-entries&quot;&gt;Notes on parallel-ineligible entries &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Some files are currently checked out sequentially, regardless of the checkout
mode configured. These are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Symbolic links;&lt;/li&gt;
  &lt;li&gt;Regular files that require external smudge filters (like Git-LFS).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This limitation exists to prevent race conditions and to avoid breaking
non-concurrency assumption that external filters might have. (You can read more
about this
&lt;a href=&quot;https://github.com/git/git/blob/68e66f2987724a639c896e7996ea347be62ef578/Documentation/technical/parallel-checkout.txt#L205&quot;&gt;here&lt;/a&gt;.)
Additionally, all file removals and directory creations are currently performed
sequentially.&lt;/p&gt;

&lt;h2 id=&quot;source-code-and-extra-material&quot;&gt;Source code &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The three series of patches that compose this project can be seen at:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/git/git/compare/a5828ae6b52137b913b978e16cd2334482eb4c1f...ae22751f9b4bbbebcd0366a48a118b5a575af72d&quot;&gt;Part 1: preparatory API changes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/git/git/compare/a0dda6023ed82b927fa205c474654699a5b07a82...68e66f2987724a639c896e7996ea347be62ef578&quot;&gt;Part 2: core parallel checkout implementation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/git/git/compare/68e66f2987724a639c896e7996ea347be62ef578...87094fc2daa9613c2fad454dbb068a8f23ce8de8&quot;&gt;Part 3: tests and extended support to other commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments &lt;a href=&quot;#table-of-contents&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Thanks to Jeff Hostetler and Nguyễn Thái Ngọc Duy, who I co-developed parallel
checkout with, and to all reviewers for dedicating their time and effort to
improve the quality of this feature. In particular, special thanks to Christian
Couder, Junio Hamano, and Derrick Stolee. Finally, thanks to Amazon for
sponsoring me in this project.&lt;/p&gt;
</description>
        <pubDate>Sat, 31 Jul 2021 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/parallel-checkout</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/parallel-checkout</guid>
      </item>
    
      <item>
        <title>Git 2.26: Up to 3.3x faster pattern searches in git-grep</title>
        <description>&lt;p class=&quot;success-box&quot;&gt;&lt;strong&gt;Quick Links&lt;/strong&gt;: 
&lt;a href=&quot;https://matheustavares.dev/assets/tavares-final-essay.pdf&quot; class=&quot;mh2&quot;&gt;Final Essay&lt;/a&gt; |
&lt;a href=&quot;#results&quot; class=&quot;mh2&quot;&gt;Timing Results&lt;/a&gt; |
&lt;a href=&quot;https://matheustavares.dev/assets/tavares-capstone-project-poster.pdf&quot; class=&quot;mh2&quot;&gt;Poster&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Two weeks ago, Git 2.26.0 &lt;a href=&quot;https://lore.kernel.org/git/xmqqa7477u6j.fsf@gitster.c.googlers.com&quot;&gt;was released&lt;/a&gt;!
And among many great changes, I’m very happy to say that you can expect faster
multithreaded git-grep searches! This is the project I’ve worked on for about a
year, as my &lt;a href=&quot;https://summerofcode.withgoogle.com/archive/2019/projects/4787791739748352/&quot;&gt;Google Summer of Code project&lt;/a&gt;
and &lt;a href=&quot;https://matheustavares.dev/assets/tavares-final-essay.pdf&quot;&gt;Undergraduate Thesis&lt;/a&gt;,
at the University of São Paulo.&lt;/p&gt;

&lt;p&gt;I’ve been posting about the project development &lt;a href=&quot;https://matheustavares.dev/tags/gsoc&quot;&gt;here&lt;/a&gt;.
But with the 2.26.0 release, the project is finally concluded, and I think it’s
a great time to wrap it all up and present the final results. For those
interested in knowing more about the development process, the final
thesis is also attached in the &lt;a href=&quot;#additional-resources&quot;&gt;Additional Resources&lt;/a&gt;
section and the top of the page.&lt;/p&gt;

&lt;h2 id=&quot;motivation-and-goal&quot;&gt;Motivation and Goal&lt;/h2&gt;

&lt;p&gt;Git has become the most popular&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; version control system for software
development. Being used to manage a large variety of projects, with different
magnitudes (in both content and history sizes), it must be built to scale. With
this in mind, Git’s grep command – which searches for text patterns in the
tracked files – was made parallel in 2010 using a producer-consumer mechanism.
However, when operating in Git’s internal object store (e.g. for a search in
older revisions), the multithreaded version became slower than the sequential
code. For this reason, threads were later disabled in this case.&lt;/p&gt;

&lt;p&gt;The main goal of this work was to &lt;strong&gt;improve the parallelization of the grep
command&lt;/strong&gt; and re-enable threads for all its use cases. In this process, it was
also desired to &lt;strong&gt;implement an optimized and secure thread access to the object
reading functions&lt;/strong&gt;, which could be future used to parallelize other sections
of the codebase.&lt;/p&gt;

&lt;h2 id=&quot;development&quot;&gt;Development&lt;/h2&gt;

&lt;p&gt;The initial phase of the project involved running several tests to determine
which sections of the code were the most time-consuming. For this task, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gprof&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perf&lt;/code&gt; were used in conjunction with visualization tools such as
&lt;a href=&quot;https://github.com/jrfonseca/gprof2dot&quot;&gt;gprog2dot&lt;/a&gt; and
&lt;a href=&quot;https://github.com/brendangregg/FlameGraph&quot;&gt;FlameGraph&lt;/a&gt;. The results showed
that, in some cases, the object decompression routines accounted for up to
one-third of git-grep’s total execution time. These routines, despite being
thread-safe, had to be serialized due to the surrounding thread-unsafe object
reading machinery.&lt;/p&gt;

&lt;p&gt;With improvements to the object reading code and to the parallelism of
git-grep, it was possible to allow safe parallel access to the decompressing
functions. This, in turn, resulted in an acceleration of over 3x, with 8
threads on a 4-core processor w/ hyper-threading. Some of the changes, such as
reducing the code inside critical sections, also brought speedups for the
working tree searches, as we will see in the next section. In addition, the
process of studying git-grep’s code and its call graph allowed us to find and
fix some race condition cases and 
&lt;a href=&quot;https://public-inbox.org/git/ba3d8a953a2cc5b4ff03fefa434ffd7bd6a78f15.1564505605.git.matheus.bernardino@usp.br/&quot;&gt;a bug regarding searches in submodules&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;The following plots compare git-grep’s execution times before and after the
proposed changes. The results presented are all means of 30 executions with a
95% confidence interval. Each plot corresponds to a different machine where the
tests were executed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grenoble&lt;/code&gt; has an HDD and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mango&lt;/code&gt; an SSD). Also, note that
the original code didn’t allow multiple threads for object store searches, but
we enabled them just for comparison. See more info at the
&lt;a href=&quot;#annex-tests-methodology&quot;&gt;Tests Methodology&lt;/a&gt; Annex.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/capstone/final_timings_grenoble.svg&quot; alt=&quot;Time comparison between original and final git-grep code (on grenoble)&quot; /&gt;
&lt;img src=&quot;/assets/capstone/final_timings_mango.svg&quot; alt=&quot;Time comparison between original and final git-grep code (on mango)&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the cached searches, we observed &lt;strong&gt;speedups of up to 3.34x over the original
code&lt;/strong&gt;, and almost 5x over the original code with threads re-enabled but
without the improvements. Additionally, the &lt;strong&gt;working tree searches also got
faster&lt;/strong&gt; with our changes, showing &lt;strong&gt;speedups of up to 1.53x&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;

&lt;h3 id=&quot;final-essay-and-other-documents&quot;&gt;Final Essay (and other documents)&lt;/h3&gt;

&lt;p&gt;Below are some additional materials which describe the development process in
much more detail. The first (and most complete) one is the final undergraduate
thesis; the second one is the poster presented at the university in an open
session; and the third one is the initial proposal (which is considerably
outdated, since the project’s main idea changed quite a bit during the
development course).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://matheustavares.dev/assets/tavares-final-essay.pdf&quot;&gt;Final Essay&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://matheustavares.dev/assets/tavares-capstone-project-poster.pdf&quot;&gt;Poster&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://matheustavares.dev/assets/tavares-capstone-project-proposal.pdf&quot;&gt;Initial Proposal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: Both the Final Essay and the Poster mention that there was still a
race condition case to fix. But, as we &lt;a href=&quot;https://public-inbox.org/git/CAHd-oW5qT5LmUd6GTL=O+-yXPmq5Uy9gk3ohL_2r+_K+6UJS3Q@mail.gmail.com/&quot;&gt;later discovered&lt;/a&gt;,
the code was already protected. To understand how, please check &lt;a href=&quot;https://public-inbox.org/git/b72e90f229dbf7d5be016fd6251a9b3ef76f2431.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;this patch&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;code&quot;&gt;Code&lt;/h3&gt;

&lt;p&gt;Below is the list of code patches originated from this work, and sent to the Git
project. All of them have already been incorporated into the
&lt;a href=&quot;https://git.kernel.org/pub/scm/git/git.git/&quot;&gt;upstream Git repository&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;mb0&quot;&gt;&lt;strong&gt;Solo patch “grep: fix worktree case in submodules” [version 1]&lt;/strong&gt;&lt;br /&gt;
Merged, part of Git version 2.24.0.&lt;/p&gt;
&lt;ul class=&quot;mt0&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/ba3d8a953a2cc5b4ff03fefa434ffd7bd6a78f15.1564505605.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[1/1]&lt;/strong&gt; grep: fix worktree case in submodules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;mb0&quot;&gt;&lt;strong&gt;Patchset &lt;a href=&quot;https://lore.kernel.org/git/cover.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;“grep: improve threading and fix race conditions”&lt;/a&gt; [version 3]&lt;/strong&gt;&lt;br /&gt;
Merged, part of Git version 2.26.0.&lt;/p&gt;
&lt;ul class=&quot;mt0&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/e2f3d377f5408d3d9365b8ac1b785d6d3f0437a9.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[01/12]&lt;/strong&gt; grep: fix race conditions on userdiff calls&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/6f0899701b88e255bae68e16e11a978488c0b1cd.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[02/12]&lt;/strong&gt; grep: fix race conditions at grep_submodule()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/5295c892ee12eb4f8a2fab2cd7e419dc04b18203.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[03/12]&lt;/strong&gt; grep: fix racy calls in grep_objects()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/d7f739bc57b6f59cab7c718300c28b8c6b0a61a8.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[04/12]&lt;/strong&gt; replace-object: make replace operations thread-safe&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/b72e90f229dbf7d5be016fd6251a9b3ef76f2431.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[05/12]&lt;/strong&gt; object-store: allow threaded access to object reading&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/fc1200bb07f749420dad044d39dfe30ae73ad640.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[06/12]&lt;/strong&gt; grep: replace grep_read_mutex by internal obj read lock&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/d39d2ce9c4c4975969a7b99cbe1ee6c8abb586c1.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[07/12]&lt;/strong&gt; submodule-config: add skip_if_read option to repo_read_gitmodules()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/af8ad95d413aa3d763769eb3ae9544e25ccbe2d1.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[08/12]&lt;/strong&gt; grep: allow submodule functions to run in parallel&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/0ccf79ba863a1a512506cc3aae4cc523d64ab8ae.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[09/12]&lt;/strong&gt; grep: protect packed_git [re-]initialization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/6c09e9169dfb21fc2cd3f69700316d3a87e72019.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[10/12]&lt;/strong&gt; grep: re-enable threads in non-worktree case&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/2f72f3034118432381f3c9378e70a65d27e3dfbb.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[11/12]&lt;/strong&gt; grep: move driver pre-load out of critical section&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lore.kernel.org/git/a5891176d7778b98ac35c756170dd334b8ee21c7.1579141989.git.matheus.bernardino@usp.br/&quot;&gt;&lt;strong&gt;[12/12]&lt;/strong&gt; grep: use no. of cores as the default no. of thread&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;annex-tests-methodology&quot;&gt;Annex: Tests Methodology&lt;/h2&gt;

&lt;p&gt;The plots presented in the &lt;a href=&quot;#results&quot;&gt;Results&lt;/a&gt; section were generated with
timings of the command below (adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cached&lt;/code&gt; option when testing searches
in the object store). The regular expression chosen represents a realistic and
time-consuming search case.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git &lt;span class=&quot;nt&quot;&gt;--no-pager&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;never &lt;span class=&quot;nt&quot;&gt;--extended-regexp&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;--threads&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;number of threads&amp;gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;&apos;(static|extern) (int|double) \*&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Chromium repository&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; was used as test data, for being a relatively large
repo in both content and history size. Also, Chromium’s developers had already
reported some difficulties regarding a couple of slow Git commands in their daily
usage.&lt;/p&gt;

&lt;p&gt;As the problem we were trying to solve is related to I/O, the tests were
repeated in two different machines: one with HDD (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grenoble&lt;/code&gt;) and one with SSD
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mango&lt;/code&gt;). Both powered by quad-core CPUs with hyper-threading, running a Linux
distribution. More information about the machines and tests can be found in the
&lt;a href=&quot;https://matheustavares.dev/assets/tavares-final-essay.pdf&quot;&gt;Final Essay&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;According to the &lt;a href=&quot;https://insights.stackoverflow.com/survey/2018#work-_-version-control&quot;&gt;Stack Overflow Developer Survey Results from 2018&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;Downloaded from
&lt;a href=&quot;https://chromium.googlesource.com/chromium/src/&quot;&gt;https://chromium.googlesource.com/chromium/src/&lt;/a&gt;
at commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;03ae96f (“Add filters testing at DSF=2”, 04-06-2019)&lt;/code&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 06 Apr 2020 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/git-2.26-faster-git-grep</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/git-2.26-faster-git-grep</guid>
      </item>
    
      <item>
        <title>GSoC Follow Ups</title>
        <description>&lt;p&gt;This is a quick follow up post to talk about the status of my project after
GSoC has finished.&lt;/p&gt;

&lt;p&gt;The Git community was very receptive and I definitely wanted to keep
contributing to the project after GSoC ended. Besides, my project wasn’t
complete yet and I had some ideas in mind I wanted to try. So it was time for a
v2!&lt;/p&gt;

&lt;p&gt;I also took some time to write a post talking about
&lt;a href=&quot;https://matheustavares.dev/posts/first-steps-contributing-to-git&quot;&gt;how to start contributing to Git&lt;/a&gt;
based on the experiences I had during this period. I’m very happy that some
people who wanted to start contributing reported it was helpful in some way :)&lt;/p&gt;

&lt;h2 id=&quot;where-were-we&quot;&gt;Where were we?&lt;/h2&gt;

&lt;p&gt;As a brief recap, the idea was to make object reading thread-safe (and with
good parallel performance) so that we could re-enable threading in git-grep for
the non-worktree case. Part of this goal was already accomplished during GSoC by
allowing zlib inflation to be performed in parallel and protecting the other
object reading section. However, the code for some of git-grep’s options
(namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;) wasn’t fully protected
yet, forcing git-grep to run sequentially when these options were given.&lt;/p&gt;

&lt;h2 id=&quot;main-idea-for-v2&quot;&gt;Main idea for v2&lt;/h2&gt;

&lt;p&gt;For this new version, I’ve rewritten the patches almost entirely from scratch.
My main idea was to turn the mutex that would protect object reading into a
recursive mutex. And then, make use of it at external places that needed to be
protected against concurrent object reading operations. In particular, I
wanted to use it to protect some of the code concerning git-grep’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; options.&lt;/p&gt;

&lt;p class=&quot;info-box&quot;&gt;The need for the mutex to be recursive comes from the fact that some of the
external places it was used in this patchset also perform object reading behind
the curtains (so if it weren’t recursive, the thread would try to double lock
the mutex leading to possible errors).&lt;/p&gt;

&lt;p&gt;I also realized that protecting only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt; wouldn’t be
enough for the desired usecase at git-grep. So, between other changes, another
mutex was added to protect the operations at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace-object.c&lt;/code&gt; and some lazy
initializers were forced to perform eagerly (before dispatching the worker
threads, to avoid races). Namely, these were the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitmodules&lt;/code&gt; file loading and
the initialization of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packed_git&lt;/code&gt;.  The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt; function was also
refactored to safelly perform as many parallel submodule operations as
possible, aiming to increase performance.&lt;/p&gt;

&lt;h2 id=&quot;inspecting-call-graphs&quot;&gt;Inspecting call graphs&lt;/h2&gt;

&lt;p&gt;To make sure we were race-free, before re-enabling threads for all git-grep
cases, I decided to generate and inspect some call graphs. Especially, I was
looking for paths in git-grep’s call graph that would lead to unprotected
functions without acquiring locks. For this task, I tried many tools, such
as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;My &lt;a href=&quot;https://github.com/matheustavares/callpath&quot;&gt;callpath&lt;/a&gt; script&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&quot;https://github.com/chaudron/cally&quot;&gt;Cally&lt;/a&gt; tool&lt;/li&gt;
  &lt;li&gt;GNU’s &lt;a href=&quot;https://www.gnu.org/software/cflow/&quot;&gt;Cflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But none of them gave me the picture I wanted. The main problem I had with some
of the tools was not being able to handle multiple valid functions with the
same name, as I described in &lt;a href=&quot;https://github.com/chaudron/cally/issues/2&quot;&gt;this&lt;/a&gt;
issue.&lt;/p&gt;

&lt;p&gt;At this point, I got a great help from
&lt;a href=&quot;https://github.com/giulianobelinassi/&quot;&gt;Giuliano Belinassi&lt;/a&gt;, a friend of mine
who contributes to GCC. He wrote a patch to make GCC dump the whole call graph
for the program being compiled, in dot’s format. (He’s still improving the patch
to send it upstream. I’ll try to remember to update this post with the patch
link once he sends it.)&lt;/p&gt;

&lt;p&gt;Then, I wrote a python script to filter only the paths starting from a group of
functions A and ending in another group of functions B (making sure to include
all paths, including recursive ones). I also added an option to exclude all
paths that contained any function from a group C. With the patched GCC and the
filter script, I began the journey of generating and analyzing git-grep’s call
graph. This took me a lot longer than I thought it would, but I think it was
worth the effort. I focused in searching for paths departing from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd_grep()&lt;/code&gt;
or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run()&lt;/code&gt; (the worker threads’ start routine) and leading to any of the
thread-unsafe functions that would also be present in object reading’s call
chain (at least, the ones I know to be thread-unsafe).&lt;/p&gt;

&lt;p&gt;As an example, I knew that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parse_object()&lt;/code&gt; wasn’t thread-safe and that it was
present at object reading call chains. So I wanted to check for other calls to
it outside object reading (as these were already protected). With that in mind,
I generated &lt;a href=&quot;https://matheustavares.dev/assets/paths_to_parse_object.png&quot;&gt;this&lt;/a&gt;
graph.&lt;/p&gt;

&lt;p&gt;I know, it’s a *huge* graph and too hard to be manually analyzed. But
starting at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd_grep()&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run()&lt;/code&gt; and eliminating the paths we know that are
protected (in the dot file, before generating the image), we are left with a
smaller subgraph which indicates the currently unprotected (and racy) paths. As
an example of unprotected and possibly racy path that can be found in the above
graph, we have:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cmd_grep() &amp;gt; grep_objects() &amp;gt; deref_tag() &amp;gt; parse_object()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this technique, I found other 5 spots in git-grep that were already in race
condition, even for the worktree case. This lead to the 3 first patches of this
new iteration:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/0f31cb0c126e824008d35d5cba52dd1c3c115c00.1569808052.git.matheus.bernardino@usp.br/&quot;&gt;grep: fix race conditions on userdiff calls&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/be32683f1d59786550138169200d29bf67a822ca.1569808052.git.matheus.bernardino@usp.br/&quot;&gt;grep: fix race conditions at grep_submodule()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/34aeb218bf266ac1a8fabcd9e8b307130d31eb0b.1569808052.git.matheus.bernardino@usp.br/&quot;&gt;grep: fix racy calls in grep_objects()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(the other ones can be seen in the link bellow)&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;The final patches can be seen
&lt;a href=&quot;https://public-inbox.org/git/cover.1569808052.git.matheus.bernardino@usp.br/&quot;&gt;here&lt;/a&gt;.
They have been already picked up and are now cooking at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pu&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;I’m really glad to see git-grep running faster and with full threading support
(even when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; are used)! Now that the main
goal was reached, I want to work on some side issues I found during the
process of examining git-grep for this project. The first one is trying to make
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt; stop adding the submodule’s odbs to the in-memory alternates
list.&lt;/p&gt;

&lt;p&gt;Another problem I stumble across during GSoC is the textconv cache been always
written to (and read from) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;the_repository&lt;/code&gt;, even for submodules’ objects. That
doesn’t perform well when we git-grep the superprobject and then go down to the
subproject to further inspect it. I have told a friend about this issue and he
is making progress trying to solve it :) I hope I can pair up with him to help.&lt;/p&gt;

&lt;p&gt;I also have to finish writing the monograph for my college capstone project
(whose theme is my GSoC project :).&lt;/p&gt;

</description>
        <pubDate>Fri, 18 Oct 2019 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/gsoc-follow-ups</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/gsoc-follow-ups</guid>
      </item>
    
      <item>
        <title>First steps contributing to Git</title>
        <description>&lt;p&gt;Git is an amazing tool with worldwide use! Being a tool we use daily, as
developers, it’s a real pleasure being able to see how it works internally. And
since Git is a free and open source project, we can do that! Even more, we can
join the community and contribute to further improve this great software :)
That’s what we’ll talk about in this [not so] brief post.&lt;/p&gt;

&lt;h3 id=&quot;index&quot;&gt;Index&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#glossary&quot;&gt;0) Glossary&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#community&quot;&gt;1) Community&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#downloading-the-source&quot;&gt;2) Downloading the Source&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#overview-of-the-repository&quot;&gt;3) Overview of the Repository &lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#compiling-installing-and-running-tests&quot;&gt;4) Compiling, Installing and Running Tests&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#submitting-patches&quot;&gt;5) Submitting Patches&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#where-to-contribute&quot;&gt;6) Where to Contribute&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#some-extra-tips&quot;&gt;7) Some Extra Tips&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#extra-references&quot;&gt;8) Extra References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;glossary&quot;&gt;0) Glossary &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;There’re some words we’ll see a lot throughout this post, so let’s stop for a
minute to recap their meanings. If you’re already comfortable with them, please,
feel free to skip this section.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Patch&lt;/strong&gt;: A patch is a file containing a collection of changes to a given
code. When we talk about patches, in this post, we are in fact talking about
“source code patches”. This subset comprehends the set of textual patches
which can be applied over source code. They are usually a “diff” containing
the “additions” and “removals” of code lines. (You may think of a patch as a
diff between two commits in a row).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Patchset or series&lt;/strong&gt;: a set of patches that usually refer to the same
thematic. Although each patch has its own set of changes, the patchset usually
has a common goal and there may be dependencies between a patch and its
“parent”.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: a series of comments and suggestions on a patch, to help improve
its quality.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Patch version&lt;/strong&gt;: the patch’s current iteration. It’s very common for a patch
not to be merged in its first version. So after getting reviews and fixing
what is needed, the author will send a “v2” (version 2). This process may
repeat for some iterations (v3, v4, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;community&quot;&gt;1) Community &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The Git community communicates mainly through:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The &lt;a href=&quot;https://public-inbox.org/git/&quot;&gt;Git mailing list&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;IRC, in channel #git-devel at freenode.org&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;mailing-list&quot;&gt;Mailing List&lt;/h3&gt;

&lt;p&gt;In order to &lt;a href=&quot;http://vger.kernel.org/vger-lists.html#git&quot;&gt;subscribe&lt;/a&gt; to the
mailing list, you have to send an email with no subject to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;majordomo@vger.kernel.org&lt;/code&gt; containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;subscribe git&lt;/code&gt; at the body. Then wait
for a follow-up email from majordomo, which will give the next instructions.
Basically, you’ll receive an authentication token that must be sent back to
confirm subscription. Finally, if everything goes well, you will receive a
welcome message from majordomo :)&lt;/p&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: All messages to majordomo (and to the mailing list) must be sent in
‘plain text’ mode, without HTML code. In Gmail, you can enable this mode in the
tree dots icon when writing an email. Regarding posting style, the preferred
method is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Posting_style#Interleaved_style&quot;&gt;inline reply&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;whats-cooking&quot;&gt;What’s Cooking&lt;/h4&gt;

&lt;p&gt;The maintainer frequently sends a “What’s Cooking” message containing
information about each topic branch he’s holding and how they are evolving in
the workflow (more on that later). It’s always good to keep an eye on these
emails to check on updates. If you are working on a new version of a patch which
is marked as “Will be merged into &lt;branch&gt;&quot;, you may also reply to Junio asking
him not to merge it yet.&lt;/branch&gt;&lt;/p&gt;

&lt;h4 id=&quot;filters&quot;&gt;Filters&lt;/h4&gt;

&lt;p&gt;As the volume of messages is quite high, you may also use a combination of
filter and label in your mail server to keep the list messages separated from
your main inbox. In Gmail, you can create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; label and use the following
filter and action options:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/first-steps-contributing-to-git/filter.png&quot; alt=&quot;Gmail label&quot; width=&quot;312&quot; /&gt;
&lt;img src=&quot;/assets/first-steps-contributing-to-git/action.png&quot; alt=&quot;Gmail filters&quot; width=&quot;312&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;archives-and-referencing-emails&quot;&gt;Archives and referencing emails&lt;/h4&gt;

&lt;p&gt;The mailing list also has some archives, which are very handy when looking for
specific topics (or conversations that happened before you subscribed). Links to
the archive are also quite often used as references when talking about a
specific mail thread. Here are some public archives:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://public-inbox.org/git/&quot;&gt;http://public-inbox.org/git/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://marc.info/?l=git&quot;&gt;http://marc.info/?l=git&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.spinics.net/lists/git/&quot;&gt;http://www.spinics.net/lists/git/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When referencing an email, the community usually opts for the first archive. It
uses &lt;a href=&quot;https://en.wikipedia.org/wiki/Message-ID&quot;&gt;Message-IDs&lt;/a&gt; as identifiers in
URLs, which makes it quite easy to use as a reference. (As we’ll see latter, you
may use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--in-reply-to=&amp;lt;Message-ID&amp;gt;&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-format-patch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-send-email&lt;/code&gt;
to send a reply to a specific email). Besides that, public-inbox has some really
&lt;a href=&quot;https://public-inbox.org/git/_/text/help/&quot;&gt;nice filtering options&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;patchwork&quot;&gt;Patchwork&lt;/h4&gt;

&lt;p&gt;There’s a &lt;a href=&quot;http://jk.ozlabs.org/projects/patchwork/&quot;&gt;patchwork&lt;/a&gt; instance at
kernel.org that also tracks all the patches sent to the Git mailing list. You
can check it &lt;a href=&quot;https://patchwork.kernel.org/project/git/list/&quot;&gt;here&lt;/a&gt;. It’s a nice
way to list patches and their series.&lt;/p&gt;

&lt;h3 id=&quot;irc&quot;&gt;IRC&lt;/h3&gt;

&lt;p&gt;If you have never used IRC (or perhaps wants to refresh your knowledge of it),
FLUSP has a nice tutorial on
&lt;a href=&quot;https://flusp.ime.usp.br/others/2019/01/14/chatting-on-irc-with-weechat-and-znc/&quot;&gt;how to chat on IRC with weechat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’re two channels, both at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;irc.freenode.net&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#git&lt;/code&gt;: for questions on how to use Git. There’s a log &lt;a href=&quot;http://colabti.org/irclogger/irclogger_log/git&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#git-devel&lt;/code&gt;: for Git development discussions. There’s a log &lt;a href=&quot;http://colabti.org/irclogger/irclogger_log/git-devel&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Part of the community also &lt;a href=&quot;https://public-inbox.org/git/20190916195058.GA67467@google.com/&quot;&gt;gets together at IRC&lt;/a&gt;
every other Monday at 17:00 UTC for a virtual &lt;a href=&quot;https://en.wikipedia.org/wiki/Stand-up_meeting&quot;&gt;standup meeting&lt;/a&gt;.
All are welcome to join in :) To avoid missing the dates, you might want to
subscribe to the &lt;a href=&quot;https://calendar.google.com/calendar/embed?src=nk8ph2kh4p5tgfcctb8i7dm6d4%40group.calendar.google.com&quot;&gt;Git Events calendar&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;calendar&quot;&gt;Calendar&lt;/h3&gt;

&lt;p&gt;Talking about calendars, we also have the public &lt;a href=&quot;https://calendar.google.com/calendar/embed?src=jfgbl2mrlipp4pb6ieih0qr3so%40group.calendar.google.com&quot;&gt;Git calendar&lt;/a&gt;
where it’s possible to check the development phases for each Git version.&lt;/p&gt;

&lt;h2 id=&quot;downloading-the-source&quot;&gt;2) Downloading the Source &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Git’s source code is available at
&lt;a href=&quot;https://git.kernel.org/pub/scm/git/git.git/&quot;&gt;https://git.kernel.org/pub/scm/git/git.git/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are also some alternative mirrors at:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://kernel.googlesource.com/pub/scm/git/git&quot;&gt;https://kernel.googlesource.com/pub/scm/git/git&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://repo.or.cz/w/alt-git.git&quot;&gt;http://repo.or.cz/w/alt-git.git&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/git/git&quot;&gt;https://github.com/git/git&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may also want to check Junio’s (the maintainer) fork at GitHub. There you’ll
not only find the main integration branches but also individual topic branches
being cooked:
&lt;a href=&quot;https://github.com/gitster/git/&quot;&gt;https://github.com/gitster/git/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get familiar with the branches workflow, you can read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man gitworkflows&lt;/code&gt;
page.&lt;/p&gt;

&lt;p&gt;Some sections of the system have dedicated maintainers with their own
repositories. If you wish to contribute to these sections, your work must be
based on their trees. These sections are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;‘git-gui/’, maintained by Pratyush Yadav: &lt;a href=&quot;https://github.com/prati0100/git-gui/&quot;&gt;https://github.com/prati0100/git-gui/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;‘gitk-git/’, maintained by Paul Mackerras: clone from git://ozlabs.org/~paulus/gitk&lt;/li&gt;
  &lt;li&gt;‘po/’, maintained by Jiang Xin: &lt;a href=&quot;https://github.com/git-l10n/git-po/&quot;&gt;https://github.com/git-l10n/git-po/&lt;/a&gt;.
Note that you can also contribute with translation through
&lt;a href=&quot;https://hosted.weblate.org/projects/git-manpages/translations/&quot;&gt;weblate&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;overview-of-the-repository&quot;&gt;3) Overview of the Repository &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Git is mostly written in C, but there are also some perl and shell scripts.
You’ll see that each command, in general, has its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command.c&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command.perl&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command.sh&lt;/code&gt; file. However, that’s not always true. For
example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;’s entry function, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd_status&lt;/code&gt; (another pattern), is
at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builtin/commit.c&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;info-box&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Take some time to browse the code and inspect the implementation for some of the
commands you use daily. It’s really fun! You can check, for example:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Git&lt;/code&gt;’s main function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;common-main.c&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Some commands’ entry functions (usually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd_*&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;The way Git declares options (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct option&lt;/code&gt; arrays for each command)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; directory is where the tests reside. We’ll talk more about them later,
but it’s important to highlight the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t/README&lt;/code&gt; file. That’s were the test lib,
test structure and execution options are described.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation&lt;/code&gt; directory is a very precious information container. There
you will find, for example:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-*.txt&lt;/code&gt; files, which becomes the Git manpages;&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;technical&lt;/code&gt; dir, containing nice descriptions of APIs and protocols;&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;howto&lt;/code&gt; dir, containing tutorial-like articles for both users and
contributors.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;warn-box&quot;&gt;
  &lt;h3 id=&quot;how-to-contribute-documentation&quot;&gt;How-to-contribute documentation&lt;/h3&gt;

  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation&lt;/code&gt; dir also holds some &lt;strong&gt;very important&lt;/strong&gt; files on the
contributing process. Make sure to read these before sending your first
patch.&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmittingPatches&lt;/code&gt;: contains a lot of useful information on the contributing
 process. &lt;a href=&quot;https://git-scm.com/docs/SubmittingPatches&quot;&gt;Here&lt;/a&gt; is the HTML
 version.&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodingGuidelines&lt;/code&gt;: describes the coding style used by the community.&lt;/li&gt;
    &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyFirstContribution&lt;/code&gt;: a great tutorial on how to start contributing to Git.
 It helps better understand the code flow, by walking the reader through the
 process of creating a new Git command!
 &lt;a href=&quot;https://git-scm.com/docs/MyFirstContribution&quot;&gt;Here&lt;/a&gt; is the HTML version.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;h2 id=&quot;compiling-installing-and-running-tests&quot;&gt;4) Compiling, Installing and Running Tests &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;h3 id=&quot;compiling&quot;&gt;Compiling&lt;/h3&gt;

&lt;p&gt;To compile, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make -j&amp;lt;num_threads&amp;gt;&lt;/code&gt;, replacing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;num_threads&amp;gt;&lt;/code&gt; by the
desired number of threads.&lt;/p&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: You may need to install some additional dependencies. But if
compilation fails, you can check what you need to install by the error messages.&lt;/p&gt;

&lt;h4 id=&quot;configmak&quot;&gt;config.mak&lt;/h4&gt;

&lt;p&gt;This file is ignored by Git and should be used to enable custom compilation
options. It is automatically included by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One thing you may want to do at this file is setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEVELOPER&lt;/code&gt; knob. This
will enable the most important compilation warnings Git community cares about.
To do so, simply add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEVELOPER=1&lt;/code&gt; to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.mak&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.mak&lt;/code&gt; file is also very useful when you want to compile Git to run it
through GDB or Valgrind. For example, you may use:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LDFLAGS += -g3 -O0
CFLAGS += -g3 -O0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;installing&quot;&gt;Installing&lt;/h3&gt;

&lt;p&gt;Normally, to install Git in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/bin&lt;/code&gt; directory, you can simply run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make
install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to do a global install, run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make &lt;span class=&quot;nv&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr all doc info &lt;span class=&quot;c&quot;&gt;# as yourself&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;install-doc install-html install-info &lt;span class=&quot;c&quot;&gt;# as root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;warn-box&quot;&gt;&lt;strong&gt;Warn&lt;/strong&gt;: be sure to carefully read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSTALL&lt;/code&gt; file for more information.&lt;/p&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;

&lt;p&gt;Tests are under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t/&lt;/code&gt; directory, and you can run them by cd-ing to the
directory and invoking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt;, to run all tests, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./&amp;lt;test_file&amp;gt;.sh&lt;/code&gt; to run a
specific test file.&lt;/p&gt;

&lt;p&gt;When debugging a test you may run it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-v -d -x&lt;/code&gt; (check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t/README&lt;/code&gt; for
individual descriptions) and get more information on the test execution. Also,
the directory created to run the test (something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trash
directory.tXXXX-YYY.sh&lt;/code&gt;) won’t be deleted even if there’re no fails so that you
can inspect it after the test is finished.&lt;/p&gt;

&lt;p&gt;Since Git tests output &lt;a href=&quot;http://testanything.org&quot;&gt;TAP&lt;/a&gt;, it’s possible to run
them with any TAP harness such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prove&lt;/code&gt;. Please, read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t/README&lt;/code&gt; for more
information on this.&lt;/p&gt;

&lt;h4 id=&quot;travis-ci&quot;&gt;Travis-CI&lt;/h4&gt;

&lt;p&gt;There’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; file which, in combination with some scripts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ci/&lt;/code&gt;,
enables Travis-CI testing for Git’s repository. As running all tests can take
quite some time and Travis-CI gives support to some additional tests (running on
both Linux and macOS, for example), it’s a nice option to test your patches.
To set it up, just fork Git’s code in GitHub, &lt;a href=&quot;https://travis-ci.org/auth&quot;&gt;sign in to Travis&lt;/a&gt;
and enable builds for Git. Every time you push changes, a build will be
triggered!&lt;/p&gt;

&lt;h2 id=&quot;submitting-patches&quot;&gt;5) Submitting Patches &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;First of all, it’s important to know what branch to base your work on. You
should read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/SubmittingPatches&lt;/code&gt; to know more about it (and other
important information). If you are not used to Git’s branches division and
workflow, you might also run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git help workflows&lt;/code&gt; to read more about it. Also,
don’t forget to check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/CodingGuidelines&lt;/code&gt;, for the used coding
style. This is taken very seriously.&lt;/p&gt;

&lt;h3 id=&quot;commit-message&quot;&gt;Commit message&lt;/h3&gt;

&lt;p&gt;Your work should be divided into separate commits for logically separated
changes. And for each commit, try to describe the changes with a meaningful
message. There’s plenty of information about this at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/SubmittingPatches&lt;/code&gt;. &lt;a href=&quot;https://chris.beams.io/posts/git-commit/&quot;&gt;This post&lt;/a&gt;
on how to write good commit messages is a nice reference as well. And finally,
it’s also a good practice to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log --no-merges&lt;/code&gt; for some real examples.&lt;/p&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Don’t underestimate writing commit messages. It’s a very important
section of the process.&lt;/p&gt;

&lt;p&gt;You can use tags in your commit message. The S-o-B (Signed-off-by) is a
&lt;a href=&quot;https://developercertificate.org/&quot;&gt;required one&lt;/a&gt;. But you can also use
Helped-by, Co-authored-by, Suggested-by, Reported-by, Original-patch-by, and
others. Again, take a look on their uses running a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt; at the repository.
(I also plan to do a separate post about them, soonish)&lt;/p&gt;

&lt;h3 id=&quot;how-to-send&quot;&gt;How to send&lt;/h3&gt;

&lt;p&gt;After you have completed all of the above steps and verified the patches’
correctness (compiling the code without warnings and successfully running the
test suite), it’s time to submit your contribution. As you might have already
noticed, the patch submission and revision process happens in the mailing list
itself (remember, GitHub and Gitlab didn’t even exist when Git was first
released).&lt;/p&gt;

&lt;p&gt;Does that mean we need to manually format the patch, copy and paste it into the
email client and send it? Well, you &lt;strong&gt;can&lt;/strong&gt; do that. But &lt;strong&gt;be careful&lt;/strong&gt; as some
clients may mess up with tabs and/or add HTML tags, corrupting your patch!
Therefore, unless you are sure that your email client won’t cause you problems,
it’s better to avoid this approach…&lt;/p&gt;

&lt;p&gt;So what can we do, then? Hmm, it would be great to have a program that takes a
commit from a local repository, formats it and automatically sends it to the
list, right? Oh, wait… &lt;strong&gt;we have such a program! Git!&lt;/strong&gt; haha You can use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-send-email&lt;/code&gt; to do that. &lt;a href=&quot;https://flusp.ime.usp.br/git/2019/02/15/sending-patches-by-email-with-git/&quot;&gt;Here’s a tutorial&lt;/a&gt;
on how to configure and use it. In general, you will probably use something like
this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git send-email &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;--annotate&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# open in editor before sending&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;--cover-letter&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# add a cover letter (only for series, i.e. &amp;gt;1 patch)&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;--thread&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-chain-reply-to&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# controls mail threading&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;git@vger.kernel.org&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--cc-cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contrib/contacts/git-contacts&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# to and cc&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;-v2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--in-reply-to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;MESSAGE-ID-HERE&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# sending a v2 as reply to your v1&apos;s cover-letter&lt;/span&gt;
     &lt;span class=&quot;nt&quot;&gt;-2&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# number of patches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(You can check more about the command added to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cc-cmd&lt;/code&gt; in this example at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contrib/contacts/git-contacts.txt&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Alternatively, you may also use &lt;a href=&quot;https://gitgitgadget.github.io/&quot;&gt;GitGitGadget&lt;/a&gt;,
which makes the connection between Pull Requests and the mailing list :)
&lt;a href=&quot;https://git-scm.com/docs/MyFirstContribution#howto-ggg&quot;&gt;Here&lt;/a&gt; is more
information on this.&lt;/p&gt;

&lt;h3 id=&quot;reviews&quot;&gt;Reviews&lt;/h3&gt;

&lt;p&gt;After some days you will probably receive some comments on your patch. You might
also want to see if it has already been queued to a topic branch in
&lt;a href=&quot;https://github.com/gitster/git&quot;&gt;the maintainer’s fork&lt;/a&gt;. (you’re looking for a
branch named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xy/topic-of-this-patchset&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xy&lt;/code&gt; is the contributor’s
namespace, usually your initials). If that’s the case, keep following the
“What’s cooking” messages to see the status of your patch. And reply to the
maintainer if you’ll be sending a new version of a patch marked to be merged
into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt;, so that he can postpone merging it.&lt;/p&gt;

&lt;h4 id=&quot;sending-a-new-version&quot;&gt;Sending a new version&lt;/h4&gt;

&lt;p&gt;If you received reviews, do not forget to thank the reviewers and reply to
their comments. It’s a good idea to reply them individually so that reviewers
know what you are doing in v2. You may also suggest other ways to address the
raised points, but it’s important to be opened to other’s suggestions as well :)
Then, you can make the necessary modifications using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase -i&lt;/code&gt; and editing
each commit individually.&lt;/p&gt;

&lt;p class=&quot;success-box&quot;&gt;&lt;strong&gt;Info&lt;/strong&gt;: In theory, you could add a new commit for each necessary fix in your
v1. But since the patches haven’t been merged yet, it’s much better to send a
corrected version of them than a series containing a patch with a mistake
followed by another one fixing it.&lt;/p&gt;

&lt;p&gt;When the new version is ready, you should send it as you did before. This
time, though, you should add the v2 flag (you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git send-email -v2&lt;/code&gt; for
that) and send it in reply to your v1’s cover letter. To do that, get the cover
letter’s Message-ID in the &lt;a href=&quot;https://public-inbox.org/git/&quot;&gt;public-inbox&lt;/a&gt; and
give it to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--in-reply-to&lt;/code&gt; option of git-send-email. This is important as
the history of the patchset is kept together. Oh, and for a single patch you may
send the new version in reply to the patch itself (as there will be no cover
letter).&lt;/p&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Develop each patchset version in a different branch. With that, you
can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff &amp;lt;branch-v1&amp;gt; &amp;lt;branch-v2&amp;gt;&lt;/code&gt; to quickly check your changes and use
git-send-email’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--range-diff&lt;/code&gt; option to send a version changelog with your
patch(es). (Check more about it in git-format-patch’s man page.)&lt;/p&gt;

&lt;h4 id=&quot;i-didnt-get-replies&quot;&gt;I didn’t get replies&lt;/h4&gt;

&lt;p&gt;If you didn’t get replies and your patch wasn’t queued yet, be patient and give
it a couple more days. The other developers are also working on their tasks and
may not have had time to see your patch yet. Also, check
&lt;a href=&quot;https://calendar.google.com/calendar/embed?src=jfgbl2mrlipp4pb6ieih0qr3so%40group.calendar.google.com&quot;&gt;the calendar&lt;/a&gt;
if a new release is approaching. In these periods new features that are not
yet ready for the upcoming release are likely to get less attention, as they are
not as urgent. However, if that’s not the case and there are still no replies in
a few weeks, you may resubmit the patch with the tag “RESEND PATCH” or just
incrementing the version and commenting it in the cover letter. But again, be
patient :)&lt;/p&gt;

&lt;h3 id=&quot;some-more-tips-on-patch-sending&quot;&gt;Some more tips on patch sending&lt;/h3&gt;

&lt;p&gt;Here are some extra tips on patch sending. The flags you’ll see refer to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-send-email&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-format-patch&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Comments section&lt;/strong&gt;: There’s a “comments section” in each patch. The lines
added between the three-dash line (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;---&lt;/code&gt;) and the beginning of the diff will
be excluded when applying the patch. So you may use this space to add any
additional information that you don’t want to be saved in the commit message.
(Such as questions, simple comments or changelogs)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;RFC and WIP&lt;/strong&gt;: If your patch (or patchset) is not finished yet but it’s
almost there and you want some comments from the community, you may use the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[RFC]&lt;/code&gt; and/or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[WIP]&lt;/code&gt; tag. Respectively, they mean “request for comments” and
“work in progress”. Usually, we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[RFC PATCH]&lt;/code&gt; for a patch pretty close to
conclusion and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[RFC WIP PATCH]&lt;/code&gt; for an even cruder version. (You can set them
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--subject-prefix=&quot;RFC PATCH&quot;&lt;/code&gt;, for example)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;git-send-email options&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-send-email&lt;/code&gt; accepts many options from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-format-patch&lt;/code&gt; as well. Thus, when you don’t find a flag in the former’s
man page, try looking for it in the latter’s one.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Area prefix&lt;/strong&gt;: it’s very common to use an “area” prefix in the commits’
titles. For example, if you are factoring out a function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.c&lt;/code&gt;, your
commit title may be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config: factor out obj reading from write_commit()&lt;/code&gt;.
(If you’re not sure about the prefix to use, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log --no-merges &amp;lt;file&amp;gt;&lt;/code&gt;,
in the file you changed, for some real examples.) Also, do not confuse this
with the RFC and WIP tags. While these tags are not kept in the commit
message, the area prefix is.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Version changelogs&lt;/strong&gt;: It’s a good idea to include changelogs between
versions so that reviewers may quickly see what has changed. You can add them
to the cover letter or in the comments section of each individual patch. The
format can be something like this:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Changes since v3:
  - Replaced git_inflate() call for git_inflate_gently()
  - Fixed typo on git_inflate() documentation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;You can also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--range-diff&lt;/code&gt; against the older version.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;where-to-contribute&quot;&gt;6) Where to Contribute &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;For starters, I really like the following advice
&lt;a href=&quot;https://public-inbox.org/git/20110914231427.GA5611@sigill.intra.peff.net/&quot;&gt;from Peff&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;Scratch your own itch. Surely git doesn’t do something that you
wish it did. Or did it faster. Or whatever. Try to dig up past
discussions on the list to make sure you’re not doing something
that has already been tried and rejected, and then start hacking.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Read the [mailing] list. People will report bugs. Try reproducing them,
bisecting them, creating minimal test cases, narrowing the issues
down to certain configurations or a certain bit of code, etc.
Sometimes that will lead you to propose a solution. Sometimes
you’ll just add to the discussion, and then somebody with more
familiarity can pick up the topic from there. But you’ll have
helped them by doing some of the work, and you’ll have learned more
about how git works.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;And here are some extra ideas to help you get started:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://git.github.io/SoC-2019-Microprojects/&quot;&gt;GSoC Microprojects&lt;/a&gt;: Git
usually participates in &lt;a href=&quot;https://summerofcode.withgoogle.com/&quot;&gt;Google Summer of Code&lt;/a&gt;.
As a preparation/exercise for applicants, the community strongly recommend
them to submit a small code-related project as part of their application. You
may take a look in the microprojects from the last years to see if there’s
something you can contribute to. (Note: the link refers to 2019 microprojects
list but feel free to check links from other years as well)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#leftoverbits&lt;/code&gt; in the mailing list. &lt;a href=&quot;https://public-inbox.org/git/87in9ucsbb.fsf@evledraar.gmail.com/&quot;&gt;Here&lt;/a&gt;
and &lt;a href=&quot;https://public-inbox.org/git/87bmcyfh67.fsf@evledraar.gmail.com/&quot;&gt;here&lt;/a&gt;
are some examples.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Look for some tags in the code: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FIXME&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TODO&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEEDSWORK&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUG&lt;/code&gt; (not
to be confused with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUG()&lt;/code&gt; macro). You can search them with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git grep
NEEDSWORK&lt;/code&gt;, for example.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Emphasizing, &lt;strong&gt;keep an eye on the mailing list&lt;/strong&gt;. There’re often discussions
on feature requests, bug reports, etc. It’s also a good idea to read other
people’s patches to keep up with the overall development process. This might
as well ring a bell on other contributions you can work on :) And speaking of
mailing lists, you may also want to check the
&lt;a href=&quot;https://groups.google.com/forum/#!forum/git-users&quot;&gt;users mailing list&lt;/a&gt; once
in a while.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Git community don’t have an official issue tracker (as already said, the list
also serves this purpose, being used to report and discuss bugs). But there’re
some other places where people have been filling and tracking bugs/issues:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://bugs.chromium.org/p/git/issues/list&quot;&gt;crbug&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/gitgitgadget/git/issues&quot;&gt;GitGitGadget&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;And if you are working on Git-for-Windows, you can check its issue tracker
&lt;a href=&quot;https://github.com/git-for-windows/git/issues&quot;&gt;here&lt;/a&gt;. You may also find
general Git issues there as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Look GSoC/Outreachy project ideas from the past years that weren’t selected.
Although they probably require much more work than what’s suitable for a first
contribution, you might try selecting subtasks from them.
&lt;a href=&quot;https://git.github.io/SoC-2019-Ideas/#summer-of-code-main-project-ideas&quot;&gt;Here&lt;/a&gt;
is Git’s list of project ideas for GSoC 2019, for example.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Junio’s blog has &lt;a href=&quot;https://git-blame.blogspot.com/p/leftover-bits.html&quot;&gt;a list of leftover-bits&lt;/a&gt;.
(Check if the issue isn’t solved yet. You may also talk about it in the
mailing list.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Finally, you may check these three pages containing project ideas for Git at
kernel.org:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://git.wiki.kernel.org/index.php/SmallProjectsIdeas&quot;&gt;SmallProjectIdeas&lt;/a&gt;
(and the respective &lt;a href=&quot;https://public-inbox.org/git/86fttvcehs.fsf@matthieu-moy.fr/&quot;&gt;discussion on the mailing list&lt;/a&gt;)&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git.wiki.kernel.org/index.php/Wishlist&quot;&gt;Wishlist&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git.wiki.kernel.org/index.php/Janitor&quot;&gt;Janitor&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;Note: some of these pages may not have been updated recently, so it’s good to
check if the issue isn’t solved yet, before trying to do it.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;some-extra-tips&quot;&gt;7) Some Extra Tips &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Sometimes we get a little lost in Git’s technical terms. A good friend in
these moments is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man gitglossary&lt;/code&gt;!&lt;/li&gt;
  &lt;li&gt;Following the same idea of the previous item, there’s
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man gitrepository-layout&lt;/code&gt;. It is very handy to better understand the
structure of a Git repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;extra-references&quot;&gt;8) Extra References &lt;a href=&quot;#index&quot;&gt;↩&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Although this post didn’t end up so short, it certainly doesn’t cover all
aspects of the contributing process. So here are some great extra readings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xbLVvrb2-fY&quot;&gt;Introduction to Git&lt;/a&gt; - talk by Scott Chacon&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2&quot;&gt;Pro Git&lt;/a&gt; - book by Scott Chacon and Ben Straub
    &lt;ul&gt;
      &lt;li&gt;Section 10, &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain&quot;&gt;Git Internals&lt;/a&gt;,
is a spectacular reading for those wishing to know more about objects,
references, packfile format, etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackernoon.com/understanding-git-index-4821a0765cf&quot;&gt;Understanding Git — Index&lt;/a&gt; - post by Zvonimir Spajic&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://eagain.net/articles/git-for-computer-scientists/&quot;&gt;Git for Computer Scientists&lt;/a&gt; - post by Tv&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs&quot;&gt;Git docs&lt;/a&gt;, especially:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitglossary&quot;&gt;Glossary&lt;/a&gt;: explain many technical words.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitworkflows&quot;&gt;Workflows&lt;/a&gt;: describe the workflows used at git.git.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitrevisions&quot;&gt;Revisions&lt;/a&gt;: an explanation of the &lt;em&gt;extended SHA-1&lt;/em&gt; syntax.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitrepository-layout&quot;&gt;Repository layout&lt;/a&gt;: the structure of repositories created through Git.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/MyFirstContribution&quot;&gt;MyFirstContribution&lt;/a&gt;: a great tutorial on the contributing process.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/SubmittingPatches/&quot;&gt;SubmittingPatches&lt;/a&gt;: a &lt;em&gt;must-read&lt;/em&gt; for everyone who wants to contribute to Git.&lt;/li&gt;
      &lt;li&gt;Other doc files, not present online, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/CodingGuidelines&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/technical/*&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;warn-box&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;: I recommend you to read, at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmittingPatches&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodingGuidelines&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyFirstContribution&lt;/code&gt; while working on your first patch.&lt;/p&gt;

&lt;p&gt;That’s it for this post! I hope to see you soon in the mailing list and IRC :)
(BTW, you can find me as “matheustavares” there).&lt;/p&gt;

&lt;h2 id=&quot;contribute-to-this-post-&quot;&gt;Contribute to this post :)&lt;/h2&gt;

&lt;p&gt;If you find any problem with this post and/or want to propose improvements,
please, feel free to create an issue or submit a merge request &lt;a href=&quot;https://gitlab.com/MatheusTavares/matheustavares.dev&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Mon, 02 Sep 2019 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/first-steps-contributing-to-git</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/first-steps-contributing-to-git</guid>
      </item>
    
      <item>
        <title>GSoC Final Report</title>
        <description>&lt;p class=&quot;success-box&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: I wrote a small follow-up to this post talking about what I’ve done in
my project after GSoC has finished. You can check it
&lt;a href=&quot;https://matheustavares.dev/posts/gsoc-follow-ups&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, this has been the final week of GSoC. It passed so fast! Let’s look back,
summarizing what was done, the current state of the project and what’s next.&lt;/p&gt;

&lt;p&gt;You may also want to check out my weekly posts on the project, which can be
found &lt;a href=&quot;/gsoc/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-project&quot;&gt;The project&lt;/h2&gt;

&lt;p&gt;You can check my project proposal &lt;a href=&quot;https://matheustavares.dev/assets/Matheus_Tavares_GSoC_Proposal.pdf&quot;&gt;here&lt;/a&gt;.
The central idea behind it was to &lt;strong&gt;allow threading to more Git commands&lt;/strong&gt; by
&lt;strong&gt;making the pack access code thread-safe&lt;/strong&gt;. We initially planned to protect the
pack access functions before working to parallelize any specific Git command.
However, without a use of the pack access API in mind, it was difficult to know
which snippets really required thread-safety. In fact, I could potentially be
working on snippets that wouldn’t necessarily need to be called in parallel.
Also, we weren’t able to fully test and validate the changes (or its real
benefits).&lt;/p&gt;

&lt;p&gt;So we changed the approach and decided to work on the pack access code from the
perspective of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt;. This command was already parallel, except when
grepping the index (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cached&lt;/code&gt;) or given trees. And the reason for that was
due to poor performance when the object store was involved, because it had to be
handled sequentially. So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt; was really showing itself as the perfect
candidate for the project.&lt;/p&gt;

&lt;p&gt;Most of GSoC’s first half, I invested in profiling and code analysis (also in
my microproject, as I’ll talk about in the next section). I was trying to
validate the hypothesis that allowing parallel object reading would indeed
speedup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt;. Even more, I wanted to know which sections of object reading
would be more suitable for parallelization. And that’s when I started to
investigate zlib inflation. You can check some of the plots and analysis made
&lt;a href=&quot;/posts/week-4-a-different-approach#studying-git-grep&quot;&gt;in this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;a href=&quot;https://gitlab.com/snippets/1888776&quot;&gt;this patch&lt;/a&gt;, I measured the time
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt; spends on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git_inflate()&lt;/code&gt; alone. And in my test case&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; it accounted
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;49.14%&lt;/code&gt; of the total execution time! This finding defined which way the
project would go from there. From this point, we focused on allowing parallel
inflation and making other improvements to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt;’s thread mechanics.&lt;/p&gt;

&lt;h2 id=&quot;the-patches&quot;&gt;The patches&lt;/h2&gt;

&lt;p&gt;As my first patch in the project, I tried to remove function-scope static
variables from thread-unsafe pack access functions. We ended up not sending this
patch as we changed the project approach, but you can check it here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/353fbe0ca3f3f884b6290bfb08805bc3b9364ab2&quot;&gt;sha1-file: convert some static variables to local&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For my microproject, I worked improving the internal
&lt;a href=&quot;https://github.com/git/git/blob/745f6812895b31c02b29bdfe4ae8e5498f776c26/dir-iterator.h&quot;&gt;dir-iterator API&lt;/a&gt;
and using it in place of readdir/opendir/closedir at
&lt;a href=&quot;https://github.com/git/git/blob/745f6812895b31c02b29bdfe4ae8e5498f776c26/builtin/clone.c#L435&quot;&gt;builtin/clone.c&lt;/a&gt;
(to copy or link objects in a local clone). Although I started this patchset
before GSoC began, there were 8 iterations and the final version was only sent
in the middle of July (it wasn’t so “micro” anymore haha). Here are v8’s
patches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/a2016d9d3b8e54ff9b9e6dfbd3ab4ce4a1bf7e4d.1562801254.git.matheus.bernardino@usp.br/&quot;&gt;1/10: clone: test for our behavior on odd objects/* content&lt;/a&gt; &lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/47a4f9b31c03499bc1317b9a0fccb11c2f5b4d34.1562801254.git.matheus.bernardino@usp.br/&quot;&gt;2/10: clone: better handle symlinked files at .git/objects/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/bbce6a601b9dfe018fb482298ab9e4e79968cd05.1562801254.git.matheus.bernardino@usp.br/&quot;&gt;3/10: dir-iterator: add tests for dir-iterator API&lt;/a&gt; &lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/0cc5f1f0b4ea7de4e0508316e861ace50f39de1f.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;4/10: dir-iterator: use warning_errno when possible&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/f871b5d3f4c916599265d34bbb0f7aeb021392c8.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;5/10: dir-iterator: refactor state machine model&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/fe838d7eb4a3f9affca32478397abf8aca9b0230.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;6/10: dir-iterator: add flags parameter to dir_iterator_begin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/3da6408e045de6e39166227a60472bd1952664ad.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;7/10: clone: copy hidden paths at local clone&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/af7430eb2c29ce35691e15d68e1c59d48d6e9144.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;8/10: clone: extract function from copy_or_link_directory&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/e8308c74085689876e25cc88e5628cfd68fc1606.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;9/10: clone: use dir-iterator to avoid explicit dir traversal&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/782ca07eed2c9bac4378e5128ff996b25ed86a43.1562801255.git.matheus.bernardino@usp.br/&quot;&gt;10/10: clone: replace strcmp by fspathcmp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above were already merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; and were part of Git v2.23.0.&lt;/p&gt;

&lt;p&gt;Working at git-grep, I fixed a bug which would make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git grep --recurse-submodule&lt;/code&gt;
always grep the index for each submodule (whilst grepping the worktree should be
the default). Here is the final v3:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/901ddbf6a1d9eeff51b1b2282ebefad51e61b12d.1564629070.git.matheus.bernardino@usp.br/&quot;&gt;grep: fix worktree case in submodules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; (but not before v2.23.0, so it should be in the
next release).&lt;/p&gt;

&lt;p&gt;The next patchset was the series where I added internal locks to object reading,
releasing it before inflation and reacquiring right after. This way we could
have thread-safe object reading with the benefit of parallel inflation. In the
same series, I also changed git-grep to use this lock instead of its own, which
lead to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3.00x&lt;/code&gt; speedup, as we’ll see later.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/052de4c139bf4962182e6cb8f4aa315aa6130124.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;1/4: object-store: add lock to read_object_file_extended()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/235de7de2874bd089b106be75121e1616308ed55.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;2/4: grep: allow locks to be enabled individually&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/d2e3f4eac24d26210f8962ebd82fd24a99c91fdf.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;3/4: grep: disable grep_read_mutex when possible&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://public-inbox.org/git/8c26abe9156e069ad4d19e9f0ce131cd1453f030.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;4/4: grep: re-enable threads in some non-worktree cases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These were sent and merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pu&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The above series re-enabled threading when grepping the index with a good
speedup, but it didn’t support some flags: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt;. This was due to the thread-unsafeness of functions used when these
options are enabled. So I kept working on a version to protect them and allow
threads in these cases as well. The following patchset is still quite raw and
thus, not sent yet. But it’s possible to see the ideas involved:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/2262495a2bc232cc58d8e9eb5f310abd32fd2669&quot;&gt;1/10: grep: remove racy call to repo_clear()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/299ff9263e34da7992c42202a845f8dc04cb2072&quot;&gt;2/10: grep: move parse_object_or_die() into critical section&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/bda87197340eecfd5f4aead6d377369ae6745414&quot;&gt;3/10: object: add repo_parse_object_or_die()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/e54b669b0a1068bfc80b97540e8180633498f452&quot;&gt;4/10: grep: don’t add submodules to the alternates list&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/72d1d3f8b0f88ba3d3e20926de5bf7ea5d42b75e&quot;&gt;5/10: config: add repo_config_with_options()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/dc2e6637c2f667768314de52b0e98109e0bcea3f&quot;&gt;6/10: submodule-config: don’t add subrepo to alternates&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/84b7ca5d4f8fad7dc37fe762b2f86ffef2f7264f&quot;&gt;7/10: object-store: allow threaded access to object reading&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/b3ffd602a50ef796949aeca5ec53f5da927d1cd4&quot;&gt;8/10: grep: replace grep_read_mutex by obj_read_locks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/a7951a314199700322d1455a5ce831cb4dd8e5ff&quot;&gt;9/10: grep: re-enable threads in some non-worktree cases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/badc9fed9df3ba3d82521f5ff38ceddb0685003b&quot;&gt;10/10: grep: move driver pre-load out of critical section&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;info-box&quot;&gt;&lt;strong&gt;Note&lt;/strong&gt;: You can check all the merged patches it the
&lt;a href=&quot;https://git.kernel.org/pub/scm/git/git.git/&quot;&gt;official repository&lt;/a&gt;, searching
for “Matheus Tavares” in the respective branches. For example, here are the
searches in &lt;a href=&quot;https://git.kernel.org/pub/scm/git/git.git/log/?qt=grep&amp;amp;q=Matheus+Tavares&amp;amp;h=master&quot;&gt;master&lt;/a&gt;
and &lt;a href=&quot;https://git.kernel.org/pub/scm/git/git.git/log/?qt=grep&amp;amp;q=Matheus+Tavares&amp;amp;h=pu&quot;&gt;pu&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;time-results&quot;&gt;Time Results&lt;/h2&gt;

&lt;p&gt;To see how well our optimizations to the cached git-grep have gone, I tested it
at chromium’s repo&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, mainly for two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It has a big object store (around 15GB), which really makes some operations
slow&lt;/li&gt;
  &lt;li&gt;Chromium’s developers already reported some difficulties with slow Git
commands&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The regexes used for the tests were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Regex 1&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abcd[02]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Regex 2&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(static|extern) (int|double) \*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each of them, the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git --no-pager grep --color=never
--threads=&amp;lt;THREADS&amp;gt; &amp;lt;REGEX&amp;gt; HEAD&lt;/code&gt; was repeated 30 times after 2 warmup runs and
the average execution time was taken. This was done to mitigate system
fluctuations. All tests were executed on an i7-7700HQ with 16GB of RAM and SSD.
Finally, here are the results:&lt;/p&gt;

&lt;div class=&quot;wrap-table&quot;&gt;

  &lt;table class=&quot;results-table&quot;&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Threads&lt;/th&gt;
        &lt;th&gt;Regex 1&lt;/th&gt;
        &lt;th&gt;Regex 2&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;1&lt;/td&gt;
        &lt;td&gt;17.3557s&lt;/td&gt;
        &lt;td&gt;20.8410s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2&lt;/td&gt;
        &lt;td&gt;9.7170s&lt;/td&gt;
        &lt;td&gt;11.2415s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;8&lt;/td&gt;
        &lt;td&gt;6.1723s&lt;/td&gt;
        &lt;td&gt;6.9378s&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;

&lt;p&gt;This represents a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3.00x&lt;/code&gt; speedup, in the best case, which is very nice! But to
make sure the optimization also performs well on HDD and/or older machines, the
tests were repeated on an AMD Turion 64 X2 TL-62 (dual-core) with 4GB of RAM and
HDD (SATA-150, 5400 rpm):&lt;/p&gt;

&lt;div class=&quot;wrap-table&quot;&gt;

  &lt;table class=&quot;results-table&quot;&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Threads&lt;/th&gt;
        &lt;th&gt;Regex 1&lt;/th&gt;
        &lt;th&gt;Regex 2&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;1&lt;/td&gt;
        &lt;td&gt;40.3347s&lt;/td&gt;
        &lt;td&gt;47.6173s&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2&lt;/td&gt;
        &lt;td&gt;27.6547s&lt;/td&gt;
        &lt;td&gt;35.1797s&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;

&lt;p&gt;And again, we got a quite good time reduction!&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;We already have a good speedup, but the project isn’t finished yet. In this last
couple weeks, I’ve been struggling to allow threads when grepping the index
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt;. The problem is that the function
calls involved in these options are not thread-safe yet and they might as well
conflict with the now protected object reading functions.&lt;/p&gt;

&lt;p&gt;So, after GSoC, I plan to continue this project tackling this issue. I already
have some drafts on how to do it. For example the last patchset on
&lt;a href=&quot;#the-patches&quot;&gt;The Patches&lt;/a&gt; section (which wasn’t sent due to some yet present
data races).&lt;/p&gt;

&lt;p&gt;However, I’m planning a more incremental process, seeking the best performance
gain without changing too much of the code at a time. Certainly, the solution
won’t be &lt;em&gt;ideal&lt;/em&gt;, but it should bring some improvement in the short term, and be
much less risky.&lt;/p&gt;

&lt;p&gt;So, what I have in mind is to use a single recursive mutex (which Git already
supports for Linux and Windows), to protect both the object reading and
submodules’ functions. With this, conflicting operations would be avoided
through mutual exclusion and submodule’s functions would still be able to load
objects without re-locking errors.&lt;/p&gt;

&lt;p&gt;This will hopefully allow us to re-enable threadings with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;
getting a good speedup and no data races. The downside is that parallelizable
tasks such as object inflation on submodule’s initializations would be
serialized. But aiming for incremental changes, that’s an improvement we can
think of in the future. As my mentors suggested, I can also write a document at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/technical&lt;/code&gt; explaining the parallel git-grep mechanics and how it
could be further improved.&lt;/p&gt;

&lt;p&gt;Finally, there are some extra possible improvements to tackle at git-grep:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Stop adding subrepo’s object directories to the in-memory alternates list.
(This is done at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builtin/grep.c::grep_submodule()&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Move already thread-safe functions out of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt;’s critical sections, for
better performance. One example is the driver pre-loading at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builtin/grep.c::add_work()&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Protect lazy initializations and refine the big object reading lock.&lt;/li&gt;
  &lt;li&gt;Once &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt; already supports threads with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;, do the
same for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;[extra] Refactor the call stack originated at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submodule-config.c::config_from_gitmodules()&lt;/code&gt; so that submodules don’t need
to be added to the in-memory alternates list. This should also bring better
performance to object reading operations. I already developed two patches&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;
during GSoC to tackle this issue, but I have to revisit and test them before
sending.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;adjacent-achievements&quot;&gt;Adjacent achievements&lt;/h2&gt;

&lt;p&gt;Because of GSoC and my work on Git, I also got the opportunity to do some
additional related activities:&lt;/p&gt;

&lt;h3 id=&quot;callpath&quot;&gt;Callpath&lt;/h3&gt;

&lt;p&gt;Working on my project, I often needed to check if some thread-unsafe function
could be present in a call stack or not. GNU &lt;a href=&quot;https://www.gnu.org/software/cflow/&quot;&gt;cflow&lt;/a&gt;
is a good alternative. But it only performs static analysis. So I wrote a simple
&lt;a href=&quot;https://github.com/matheustavares/callpath&quot;&gt;script called callpath&lt;/a&gt; which
uses GDB + dot to plot all the paths that lead to a specific function in an
execution.&lt;/p&gt;

&lt;h3 id=&quot;talk-at-linuxdev-br&quot;&gt;Talk at linuxdev-br&lt;/h3&gt;

&lt;p&gt;I got to present at the &lt;a href=&quot;https://linuxdev-br.net/&quot;&gt;linuxdev-br&lt;/a&gt; conference,
showing a little bit of Git’s code. Renato and I talked about object-oriented
techniques in C using Linux and Git as study cases. I focused mostly on the
dir-iterator API (which I worked on as my GSoC’s microproject). Our slides are
available &lt;a href=&quot;https://matheustavares.dev/assets/oop_git_and_kernel.pdf&quot;&gt;here&lt;/a&gt; and the
lecture recording &lt;a href=&quot;https://www.youtube.com/watch?v=x0ELqk2lCcI&quot;&gt;here&lt;/a&gt;. Bellow
are some pictures of the talk (click to enlarge):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://matheustavares.dev/assets/linuxdev-br-oop-cs-1.jpg&quot;&gt;&lt;img src=&quot;https://matheustavares.dev/assets/linuxdev-br-oop-cs-1.jpg&quot; alt=&quot;OOP a case study at linuxdev-br&quot; class=&quot;banner&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://matheustavares.dev/assets/linuxdev-br-oop-cs-2.jpg&quot;&gt;&lt;img src=&quot;https://matheustavares.dev/assets/linuxdev-br-oop-cs-2.jpg&quot; alt=&quot;dir-iterator API at linuxdev-br&quot; class=&quot;banner&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;mw7 center tc pb4 silver&quot;&gt;(Pictures by &lt;a href=&quot;https://about.me/edsiper&quot;&gt;Eduardo Silva&lt;/a&gt;)&lt;/p&gt;

&lt;h3 id=&quot;git-group-at-flusp&quot;&gt;Git group at FLUSP&lt;/h3&gt;

&lt;p&gt;I’m part of &lt;a href=&quot;https://flusp.ime.usp.br/&quot;&gt;FLUSP&lt;/a&gt;, a group of students at the
University of São Paulo focused on contributing to FLOSS projects. This year,
some of us started meeting weekly to exchange Git learnings and tips on how to
contribute to it. We’ll hopefully see some patches from the group in the ML soon
:)&lt;/p&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;I want to thank my mentors, Christian and Olga, for all their support and always
encouraging comments. Also, I want to thank Duy for helping me investigate the
possible threading improvements in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-grep&lt;/code&gt;. And finally, I thank Junio and
the community for the reviews and support.&lt;/p&gt;

&lt;p&gt;Being part of GSoC on Git was amazing. I certainly want to keep contributing to
Git with whatever I can :)&lt;/p&gt;

&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;/h2&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;The test was made running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time git --no-pager grep --color=never
--threads=1 -E &apos;(static|extern) (int|double) \*&apos; HEAD&lt;/code&gt; on chromium’s
repo&lt;sup id=&quot;fnref:4:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; 5 times and taking the means. The results were:&lt;/p&gt;
      &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Total time:       10.3599s
Time in inflate:  20.3682s
Percentage:       49.14%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;      &lt;/div&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;Patch by Ævar Arnfjörð. I made some small changes and re-sent. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;Patch by Daniel Ferreira. I made some small changes and re-sent. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;chromium’s repo at commit 03ae96f (“Add filters testing at DSF=2”,
04-06-2019), after a ‘git gc’ execution. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt; &lt;a href=&quot;#fnref:4:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/oYe69KzyG_U&quot;&gt;https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/oYe69KzyG_U&lt;/a&gt; &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;The patches removing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt; call from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submodule-config.c::config_from_gitmodules()&lt;/code&gt;:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/72d1d3f8b0f88ba3d3e20926de5bf7ea5d42b75e&quot;&gt;config: add repo_config_with_options()&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://github.com/matheustavares/git/commit/dc2e6637c2f667768314de52b0e98109e0bcea3f&quot;&gt;submodule-config: don’t add subrepo to alternates&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 24 Aug 2019 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/gsoc-final-report</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/gsoc-final-report</guid>
      </item>
    
      <item>
        <title>GSoC Week 13: Going for a [too] big step</title>
        <description>&lt;p&gt;We are approaching the end of GSoC. In fact, this is the final week! A working
version of git-grep with parallel inflation was already sent and merged into
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pu&lt;/code&gt;. But threading is still disabled when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt; are given. So I’ve been working on a v2 to support grepping
submodules and try some more optimizations along the way. It didn’t seem so
complex at the beginning, but I quickly realized I was just at the tip of the
iceberg. This was probably the most &lt;strong&gt;intense&lt;/strong&gt; week in my GSoC. It went like
this:&lt;/p&gt;

&lt;h2 id=&quot;1-submodules-initializations&quot;&gt;1) Submodule’s initializations&lt;/h2&gt;

&lt;p&gt;At first, to efficiently grep submodules in parallel I thought I just had to
internally protect these four functions at the beginning of grep_submodule:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;is_submodule_active()&lt;/li&gt;
  &lt;li&gt;repo_submodule_init()&lt;/li&gt;
  &lt;li&gt;repo_read_gitmodules()&lt;/li&gt;
  &lt;li&gt;add_to_alternates_memory()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing so, I would be able to remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_read_mutex&lt;/code&gt; around them in favor
of the internal object reading locks I added. This would let
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git grep --recurse-submodules --cached&lt;/code&gt; take full advantage of the parallel
inflation. (the internal locks are released when inflating.)&lt;/p&gt;

&lt;h3 id=&quot;11-finding-the-thread-unsafe-spots&quot;&gt;1.1) Finding the thread-unsafe spots&lt;/h3&gt;

&lt;p&gt;The first thing to do was to discover why those functions needed to be in a
critical section. A comment right above them give the answer:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*
 * NEEDSWORK: submodules functions need to be protected because they
 * access the object store via config_from_gitmodules(): the latter
 * uses get_oid() which, for now, relies on the global the_repository
 * object.
 */
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But inspecting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_from_gitmodules()&lt;/code&gt; I discovered the comment was outdated
and the function no longer used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_oid()&lt;/code&gt;. However, it now called
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt;, which adds the subrepo object directory as an
in-memory alternate to the global the_repository. As this operation would be
performed concurrently with the object reading operations by the worker threads,
it could cause data races. (Because it writes to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r-&amp;gt;objects-&amp;gt;odb&lt;/code&gt; list,
while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt;’s call chain may need to iterate through it.)&lt;/p&gt;

&lt;h3 id=&quot;12-removing-1st-add_to_alternates_memory&quot;&gt;1.2) Removing 1st &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_from_gitmodules()&lt;/code&gt; was adding the subrepo to the alternates memory in
order to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_with_options()&lt;/code&gt;, which needs access to the subrepo’s
objects. The call chains I found that reads the subrepo objects are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_with_options() &amp;gt; git_config_from_blob_ref() &amp;gt; get_oid()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_with_options() &amp;gt; git_config_from_blob_ref() &amp;gt; get_oid() &amp;gt; git_config_from_blob_oid() &amp;gt; read_object_file()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, in order to remove the addition to the alternates list, I added a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repo_config_with_options()&lt;/code&gt;, which would take an extra repository parameter and
pass it down in those chains. Then I made &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config_from_gitmodules()&lt;/code&gt; use this
new function.&lt;/p&gt;

&lt;h3 id=&quot;13-thread-safe-initializations&quot;&gt;1.3) Thread-safe initializations?&lt;/h3&gt;

&lt;p&gt;At this point, I was pretty sure the first 3 submodule operations were already
thread-safe without the need of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_read_mutex&lt;/code&gt; or even my internal object
reading locks. But there was no way to be sure other than going through each and
every function in the call chains. I tried that, but as one would imagine, the
call chains were too big for me to manually examine line-by-line…&lt;/p&gt;

&lt;h3 id=&quot;14-removing-2nd-add_to_alternates_memory&quot;&gt;1.4) Removing 2nd &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt;.&lt;/h3&gt;

&lt;p&gt;I still had to take care of one more thread-unsafe function: the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt;. Removing it would not only
help in the parallelization but would also solve another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEEDSWORK&lt;/code&gt; comment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*
 * NEEDSWORK: This adds the submodule&apos;s object directory to the list of
 * alternates for the single in-memory object store.  This has some bad
 * consequences for memory (processed objects will never be freed) and
 * performance (this increases the number of pack files git has to pay
 * attention to, to the sum of the number of pack files in all the
 * repositories processed so far).  This can be removed once the object
 * store is no longer global and instead is a member of the repository
 * object.
 */
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The call was there so that worker threads could access the subrepo’s objects
through the alternates list. Thus, to remove it I had to pass the subrepository
reference down to the threads and make them use it explicitly. Unfotunatelly,
it seems that this patch introduced some data races I wasn’t able to find until
this moment :(&lt;/p&gt;

&lt;h2 id=&quot;2-other-submodules-data-races&quot;&gt;2) Other submodule’s data races&lt;/h2&gt;

&lt;p&gt;I also noticed some other operations on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt; which weren’t
thread-safe:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parse_object_or_die()&lt;/code&gt;, when grepping trees, is outside a lock.
This function may load objects internally, write to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r-&amp;gt;parsed_objects_obj_hash&lt;/code&gt; and also call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_replace_object()&lt;/code&gt;, which is
thread-unsafe. So calls to it must be done in a critical section.&lt;/li&gt;
  &lt;li&gt;To clean the memory allocated for the subrepository, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repo_clear(&amp;amp;subrepo)&lt;/code&gt;
was being called right before returning from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt;. However, by
the time this function is called, there’s no guarantee that the worker threads
have already finished working on the subrepo. To properly avoid that, we would
need to implement a kind of mapping which tells, for each repo, how many
objects are yet to be processed. As this would be somehow laborious, I just
skipped the memory cleaning for now, to implement a testing version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-thread-safe-code-inside-critical-section&quot;&gt;3) Thread-safe code inside critical section&lt;/h2&gt;

&lt;p&gt;I noticed what it seemed to be an already thread-safe code inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_work()&lt;/code&gt;’s
critical section. So I moved it out, which lead to a minor but noticeable
speedup:&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gd&quot;&gt;-static void add_work(struct grep_opt *opt, const struct grep_source *gs)
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+static void add_work(struct grep_opt *opt, struct grep_source *gs)
&lt;/span&gt; {
&lt;span class=&quot;gi&quot;&gt;+       if (opt-&amp;gt;binary != GREP_BINARY_TEXT)
+               grep_source_load_driver(gs, opt-&amp;gt;repo-&amp;gt;index);
+
&lt;/span&gt;        grep_lock();

        while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
                pthread_cond_wait(&amp;amp;cond_write, &amp;amp;grep_mutex);
        }

        todo[todo_end].source = *gs;
&lt;span class=&quot;gd&quot;&gt;-       if (opt-&amp;gt;binary != GREP_BINARY_TEXT)
-               grep_source_load_driver(&amp;amp;todo[todo_end].source,
-                                       opt-&amp;gt;repo-&amp;gt;index);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4-move-the-obj_read_mutex-down&quot;&gt;4) Move the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obj_read_mutex&lt;/code&gt; down&lt;/h2&gt;

&lt;p&gt;I didn’t mention it before, but some of those four submodule operations use
object reading function such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt;, which is not
thread-safe. To overcome this, I decided to move v1’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obj_read_mutex&lt;/code&gt; from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_object_file_extended()&lt;/code&gt; down to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt;. This allowed
even more functions to be called in parallel, but some extra locks were needed.&lt;/p&gt;

&lt;h2 id=&quot;5-replace-grep_read_mutex-by-internal-locks&quot;&gt;5) Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_read_mutex&lt;/code&gt; by internal locks&lt;/h2&gt;

&lt;p&gt;With all the above done, it was time to remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_read_mutex&lt;/code&gt; and enable
the internal object reading locks. This moment, I also re-enabled threads in
the cached grep with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;. Unfortunatelly, the result wasn’t
the best. I tried a lot of changes to this main idea, but all of them ended up
in a data race, Segmentation Fault, failure to read subrepos’ objects, or
performance drop. Each of these alternative versions are in my local branches,
which I thought wouldn’t be worthy uploading to share, but
&lt;a href=&quot;https://github.com/matheustavares/git/commits/parallel-inflation-no-text-and-sub-2&quot;&gt;here&lt;/a&gt;
is the “main” one.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;I believe my idea for v2 turned out to be a very big step and I just got lost in
it. So my current idea is to take a step back and go slower. With that in mind,
I might end up not finishing this version during GSoC. But I thinkg that’s OK as
we already have v1 sent and with good speedup. And I can keep working on this
after GSoC, anyway :)&lt;/p&gt;

&lt;p&gt;So, instead of making more tweaks to my v2 series, I sat down and analysed the
code trying to list what are the real open issues (and how we might solve them):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_to_alternates_memory()&lt;/code&gt;&lt;/strong&gt;: althought this function cannot be called in
parallel, the case in which git-grep uses it, may not be problematic, if:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepare_alt_odb()&lt;/code&gt; is called at repositories’ initalization (at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd_grep()&lt;/code&gt; for the_repository and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule()&lt;/code&gt; for subrepos).
This way, we force eager initialization and avoid data races with the
worker threads in the initialization.&lt;/li&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ent-&amp;gt;next = NULL&lt;/code&gt; line is moved up in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;link_alt_odb_entry()&lt;/code&gt;.
Then, the worker threads may iterate through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r-&amp;gt;objects-&amp;gt;odb&lt;/code&gt; without
possibly falling on an unmaped memory region. (That’s hacky, but
should work).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parse_object_or_die()&lt;/code&gt;&lt;/strong&gt;: again, this should not be a problem in our case,
if:
    &lt;ul&gt;
      &lt;li&gt;The object reading operations are properly protected internally.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepare_replace_object()&lt;/code&gt; is called at repositories’ initialization
(as before).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Submodule initialization functions&lt;/strong&gt; (at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodule&lt;/code&gt;): This is the
critical part! I re-investigated them and found out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_submodule_active()&lt;/code&gt;,
for example, has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repack_packed_git()&lt;/code&gt; in its call chain. This could clearly
generate data races with the workers. And as we are working with “indermediate
level” locks, I really don’t know yet how to protect these functions without
going lower or higher in our “protection layer”. On the other hand,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submodule_from_path()&lt;/code&gt; has the same problem and it is outside the critical
section… So maybe we can ignore those data races which are too improbable?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regarding the commits I already have, I plan to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submodule-config: don&apos;t add subrepo to alternates&lt;/code&gt; from the
series. It is no longer necessary here, so it might be sent separately.&lt;/li&gt;
  &lt;li&gt;Remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep: don&apos;t add submodules to the alternates list&lt;/code&gt; and hold it in
standby. It currently brings data races that must be solved if I’m going to
send it in the future.&lt;/li&gt;
  &lt;li&gt;Refactor the patch adding the object reading locks. I plan to protect only
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt; and not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_object_file_extended()&lt;/code&gt;. This won’t
work for the general case (which I’ll make explicit), but should work in our
case as we’ll be forcing eager initialization for alternates and replace maps
in all repos.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep: move driver pre-load out of critical section&lt;/code&gt; should be OK if we
have the object reading locks.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WIP: grep: remove racy call to repo_clear()&lt;/code&gt; must be properly finished.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s the plan! Well, I really hope I’m not being too flustered again, and
proposing bigger steps than what I can take…&lt;/p&gt;

&lt;h2 id=&quot;main-difficulties&quot;&gt;Main difficulties&lt;/h2&gt;

&lt;p&gt;Main difficulties this week were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Debugging data races:&lt;/strong&gt; I used a combination of GDB, ThreadSanitizer and
valgring (helgrind and memcheck). But sometimes the racy spot is to occasional
to be caught.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Investigating deep call chains&lt;/strong&gt;: To make a low-level “thread-protection
layer” is hard. I needed to go deep in git-grep call stacks to make sure some
functions were safe to be called unlocked. And a couple times I was still
unsure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also spent some time thinking how I should properly deal with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Lazy initializations:&lt;/strong&gt; They are great in big codebases as they mitigate the
need to keep track of all initializations in the beginning of an execution.
But unfortunatelly, they are difficult to handle when threaded, as two threads
can try to initialize a resource at the same time. (For example, take a look
at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepare_replace_object()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prepare_alt_odb()&lt;/code&gt;, which are called by
many functions.)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Static function-scope variables&lt;/strong&gt;: Some functions such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_to_hex()&lt;/code&gt;
return a static buffer. This is a good convenience for the callees and it
avoids memory leaks, but it makes the function thread-unsafe.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 20 Aug 2019 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/going-for-a-too-big-step</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/going-for-a-too-big-step</guid>
      </item>
    
      <item>
        <title>GSoC Week 12: Simplified version of parallel inflation</title>
        <description>&lt;h2 id=&quot;patchset-sent-with-some-limitations&quot;&gt;Patchset sent, with some limitations&lt;/h2&gt;

&lt;p&gt;Last week we had a &lt;em&gt;prototype&lt;/em&gt; version of the parallel inflation patchset
working without race conditions. Even so, it still had some major issues. For
example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use_pack()&lt;/code&gt; needed an aditional provisory mutex to properly work in parallel;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt; would produce considerable performance drops; and&lt;/li&gt;
  &lt;li&gt;the code was a bit unorganized with some probably redundant locks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These items would still take some time to fix. So my mentors and I thought it
would be better to send a simplified version, for now, with the already stable
improvements. And I could, then, keep working on a more complete version to be
sent latter. This is good because is more incremental and, also, we can get
community feedback sooner :)&lt;/p&gt;

&lt;p&gt;So, this week, I’ve been working on this simplified version. It already brings
good speedup to cached git-grep, but the optimization is disabled when
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; are used. A section was added to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Documentation/git-grep.txt&lt;/code&gt; to better explain these details. I also
&lt;a href=&quot;https://public-inbox.org/git/8c26abe9156e069ad4d19e9f0ce131cd1453f030.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;repeated the performance tests&lt;/a&gt;
I’ve been running, this time on an older machine. The final version can be seen
&lt;a href=&quot;https://public-inbox.org/git/cover.1565468806.git.matheus.bernardino@usp.br/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;grep-dont-add-submodules-to-alternates&quot;&gt;grep: don’t add submodules to alternates&lt;/h2&gt;

&lt;p&gt;While working at git-grep’s critical sections, I came to the following
commentary at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodules()&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builtin/grep.c&lt;/code&gt;):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*
* NEEDSWORK: This adds the submodule&apos;s object directory to the list of
* alternates for the single in-memory object store.  This has some bad
* consequences for memory (processed objects will never be freed) and
* performance (this increases the number of pack files git has to pay
* attention to, to the sum of the number of pack files in all the
* repositories processed so far).  This can be removed once the object
* store is no longer global and instead is a member of the repository
* object.
*/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since the object store is now a member of the struct repository, I thought it
should be possible to tackle this NEEDSWORK as the commentary suggests. I also
thought this modification could help me in the process of supporting threads
with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;, as it would simplify a bit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep_submodules()&lt;/code&gt;’s
critical section. So I worked on a patch to make git-grep stop adding submodules
to the list of alternates, as you can check
&lt;a href=&quot;https://github.com/matheustavares/git/commit/05536a503b3315d36ad13276af7728adf674ed51&quot;&gt;here&lt;/a&gt;.
The patch already works, but some refactoring is needed.&lt;/p&gt;

&lt;p&gt;I ran some tests on a “semi-artificial” repository (linux repo with Git as a
submodule), but the patched git-grep didn’t showed a significant time drop. I
wonder if I need a bigger repository and/or submodule to really see the
differences or if, unfortunatelly, this modification ended up not being as
effective…&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;My plan for this week is to keep working on a patch on top of the series I
sent earlier to allow threading with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--textconv&lt;/code&gt;.
For now, I’ve been focusing on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt;, as I think I know
more of its code.&lt;/p&gt;

&lt;p&gt;One way to proceed towards our goal would be to move the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obj_read_mutex&lt;/code&gt; down
from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_object_file_extended()&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt;. With this,
we could potentially avoid the race conditions between the threads’ calls to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_object_file_extended()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parse_object_or_die()&lt;/code&gt; (which calls
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oid_object_info_extended()&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Nevertheless, I recently discovered that, just by enabling threads when cached
(without my patchset), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--recurse-submodules&lt;/code&gt; already results in race
conditions. The problem seems to envolve the userdiff calls as well. I didn’t
get to investigate this enought yet, but that should be one of my next tasks.&lt;/p&gt;

&lt;p&gt;Finally, I also want to test the “don’t add submodules to alternates” patch,
somehow, to see if it is worthy. But I don’t know how yet.&lt;/p&gt;
</description>
        <pubDate>Tue, 13 Aug 2019 00:00:00 -0300</pubDate>
        <link>https://matheustavares.dev/posts/simplified-version-of-parallel-inflation</link>
        <guid isPermaLink="true">https://matheustavares.dev/posts/simplified-version-of-parallel-inflation</guid>
      </item>
    
  </channel>
</rss>
