<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The object store — dulwich 0.9.0 documentation</title> <link rel="stylesheet" href="../_static/nature.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../', VERSION: '0.9.0', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../_static/jquery.js"></script> <script type="text/javascript" src="../_static/underscore.js"></script> <script type="text/javascript" src="../_static/doctools.js"></script> <link rel="top" title="dulwich 0.9.0 documentation" href="../index.html" /> <link rel="up" title="Tutorial" href="index.html" /> <link rel="next" title="Remote repositories" href="remote.html" /> <link rel="prev" title="The repository" href="repo.html" /> </head> <body> <div class="related"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../genindex.html" title="General Index" accesskey="I">index</a></li> <li class="right" > <a href="remote.html" title="Remote repositories" accesskey="N">next</a> |</li> <li class="right" > <a href="repo.html" title="The repository" accesskey="P">previous</a> |</li> <li><a href="../index.html">dulwich 0.9.0 documentation</a> »</li> <li><a href="index.html" accesskey="U">Tutorial</a> »</li> </ul> </div> <div class="document"> <div class="documentwrapper"> <div class="bodywrapper"> <div class="body"> <div class="section" id="the-object-store"> <span id="tutorial-object-store"></span><h1>The object store<a class="headerlink" href="#the-object-store" title="Permalink to this headline">¶</a></h1> <p>The objects are stored in the <tt class="docutils literal"><span class="pre">object</span> <span class="pre">store</span></tt> of the repository.</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.repo</span> <span class="kn">import</span> <span class="n">Repo</span> <span class="gp">>>> </span><span class="n">repo</span> <span class="o">=</span> <span class="n">Repo</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="s">"myrepo"</span><span class="p">,</span> <span class="n">mkdir</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> </pre></div> </div> <div class="section" id="initial-commit"> <h2>Initial commit<a class="headerlink" href="#initial-commit" title="Permalink to this headline">¶</a></h2> <p>When you use Git, you generally add or modify content. As our repository is empty for now, we’ll start by adding a new file:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.objects</span> <span class="kn">import</span> <span class="n">Blob</span> <span class="gp">>>> </span><span class="n">blob</span> <span class="o">=</span> <span class="n">Blob</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="s">"My file content</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">blob</span><span class="o">.</span><span class="n">id</span> <span class="go">'c55063a4d5d37aa1af2b2dad3a70aa34dae54dc6'</span> </pre></div> </div> <p>Of course you could create a blob from an existing file using <tt class="docutils literal"><span class="pre">from_file</span></tt> instead.</p> <p>As said in the introduction, file content is separed from file name. Let’s give this content a name:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.objects</span> <span class="kn">import</span> <span class="n">Tree</span> <span class="gp">>>> </span><span class="n">tree</span> <span class="o">=</span> <span class="n">Tree</span><span class="p">()</span> <span class="gp">>>> </span><span class="n">tree</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s">"spam"</span><span class="p">,</span> <span class="mo">0100644</span><span class="p">,</span> <span class="n">blob</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> </pre></div> </div> <p>Note that “0100644” is the octal form for a regular file with common permissions. You can hardcode them or you can use the <tt class="docutils literal"><span class="pre">stat</span></tt> module.</p> <p>The tree state of our repository still needs to be placed in time. That’s the job of the commit:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.objects</span> <span class="kn">import</span> <span class="n">Commit</span><span class="p">,</span> <span class="n">parse_timezone</span> <span class="gp">>>> </span><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span> <span class="gp">>>> </span><span class="n">commit</span> <span class="o">=</span> <span class="n">Commit</span><span class="p">()</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">tree</span> <span class="o">=</span> <span class="n">tree</span><span class="o">.</span><span class="n">id</span> <span class="gp">>>> </span><span class="n">author</span> <span class="o">=</span> <span class="s">"Your Name <your.email@example.com>"</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">committer</span> <span class="o">=</span> <span class="n">author</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">commit_time</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">author_time</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="p">())</span> <span class="gp">>>> </span><span class="n">tz</span> <span class="o">=</span> <span class="n">parse_timezone</span><span class="p">(</span><span class="s">'-0200'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">commit_timezone</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">author_timezone</span> <span class="o">=</span> <span class="n">tz</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">encoding</span> <span class="o">=</span> <span class="s">"UTF-8"</span> <span class="gp">>>> </span><span class="n">commit</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="s">"Initial commit"</span> </pre></div> </div> <p>Note that the initial commit has no parents.</p> <p>At this point, the repository is still empty because all operations happen in memory. Let’s “commit” it.</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">object_store</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">object_store</span> <span class="gp">>>> </span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">blob</span><span class="p">)</span> </pre></div> </div> <p>Now the ”.git/objects” folder contains a first SHA-1 file. Let’s continue saving the changes:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span> </pre></div> </div> <p>Now the physical repository contains three objects but still has no branch. Let’s create the master branch like Git would:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">refs</span><span class="p">[</span><span class="s">'refs/heads/master'</span><span class="p">]</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">id</span> </pre></div> </div> <p>The master branch now has a commit where to start. When we commit to master, we are also moving HEAD, which is Git’s currently checked out branch:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">head</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">refs</span><span class="p">[</span><span class="s">'HEAD'</span><span class="p">]</span> <span class="gp">>>> </span><span class="n">head</span> <span class="o">==</span> <span class="n">commit</span><span class="o">.</span><span class="n">id</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">head</span> <span class="o">==</span> <span class="n">repo</span><span class="o">.</span><span class="n">refs</span><span class="p">[</span><span class="s">'refs/heads/master'</span><span class="p">]</span> <span class="go">True</span> </pre></div> </div> <p>How did that work? As it turns out, HEAD is a special kind of ref called a symbolic ref, and it points at master. Most functions on the refs container work transparently with symbolic refs, but we can also take a peek inside HEAD:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">refs</span><span class="o">.</span><span class="n">read_ref</span><span class="p">(</span><span class="s">'HEAD'</span><span class="p">)</span> <span class="go">'ref: refs/heads/master'</span> </pre></div> </div> <p>Normally, you won’t need to use read_ref. If you want to change what ref HEAD points to, in order to check out another branch, just use set_symbolic_ref.</p> <p>Now our repository is officially tracking a branch named “master” referring to a single commit.</p> </div> <div class="section" id="playing-again-with-git"> <h2>Playing again with Git<a class="headerlink" href="#playing-again-with-git" title="Permalink to this headline">¶</a></h2> <p>At this point you can come back to the shell, go into the “myrepo” folder and type <tt class="docutils literal"><span class="pre">git</span> <span class="pre">status</span></tt> to let Git confirm that this is a regular repository on branch “master”.</p> <p>Git will tell you that the file “spam” is deleted, which is normal because Git is comparing the repository state with the current working copy. And we have absolutely no working copy using Dulwich because we don’t need it at all!</p> <p>You can checkout the last state using <tt class="docutils literal"><span class="pre">git</span> <span class="pre">checkout</span> <span class="pre">-f</span></tt>. The force flag will prevent Git from complaining that there are uncommitted changes in the working copy.</p> <p>The file <tt class="docutils literal"><span class="pre">spam</span></tt> appears and with no surprise contains the same bytes as the blob:</p> <div class="highlight-python"><pre>$ cat spam My file content</pre> </div> </div> <div class="section" id="changing-a-file-and-committing-it"> <h2>Changing a File and Committing it<a class="headerlink" href="#changing-a-file-and-committing-it" title="Permalink to this headline">¶</a></h2> <p>Now we have a first commit, the next one will show a difference.</p> <p>As seen in the introduction, it’s about making a path in a tree point to a new blob. The old blob will remain to compute the diff. The tree is altered and the new commit’task is to point to this new version.</p> <p>Let’s first build the blob:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.objects</span> <span class="kn">import</span> <span class="n">Blob</span> <span class="gp">>>> </span><span class="n">spam</span> <span class="o">=</span> <span class="n">Blob</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="s">"My new file content</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">spam</span><span class="o">.</span><span class="n">id</span> <span class="go">'16ee2682887a962f854ebd25a61db16ef4efe49f'</span> </pre></div> </div> <p>An alternative is to alter the previously constructed blob object:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">blob</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s">"My new file content</span><span class="se">\n</span><span class="s">"</span> <span class="gp">>>> </span><span class="n">blob</span><span class="o">.</span><span class="n">id</span> <span class="go">'16ee2682887a962f854ebd25a61db16ef4efe49f'</span> </pre></div> </div> <p>In any case, update the blob id known as “spam”. You also have the opportunity of changing its mode:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">tree</span><span class="p">[</span><span class="s">"spam"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mo">0100644</span><span class="p">,</span> <span class="n">spam</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> </pre></div> </div> <p>Now let’s record the change:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.objects</span> <span class="kn">import</span> <span class="n">Commit</span> <span class="gp">>>> </span><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span> <span class="gp">>>> </span><span class="n">c2</span> <span class="o">=</span> <span class="n">Commit</span><span class="p">()</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">tree</span> <span class="o">=</span> <span class="n">tree</span><span class="o">.</span><span class="n">id</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">parents</span> <span class="o">=</span> <span class="p">[</span><span class="n">commit</span><span class="o">.</span><span class="n">id</span><span class="p">]</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="n">c2</span><span class="o">.</span><span class="n">committer</span> <span class="o">=</span> <span class="s">"John Doe <john@example.com>"</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">commit_time</span> <span class="o">=</span> <span class="n">c2</span><span class="o">.</span><span class="n">author_time</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="p">())</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">commit_timezone</span> <span class="o">=</span> <span class="n">c2</span><span class="o">.</span><span class="n">author_timezone</span> <span class="o">=</span> <span class="mi">0</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">encoding</span> <span class="o">=</span> <span class="s">"UTF-8"</span> <span class="gp">>>> </span><span class="n">c2</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="s">'Changing "spam"'</span> </pre></div> </div> <p>In this new commit we record the changed tree id, and most important, the previous commit as the parent. Parents are actually a list because a commit may happen to have several parents after merging branches.</p> <p>Let’s put the objects in the object store:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">spam</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">object_store</span><span class="o">.</span><span class="n">add_object</span><span class="p">(</span><span class="n">c2</span><span class="p">)</span> </pre></div> </div> <p>You can already ask git to introspect this commit using <tt class="docutils literal"><span class="pre">git</span> <span class="pre">show</span></tt> and the value of <tt class="docutils literal"><span class="pre">c2.id</span></tt> as an argument. You’ll see the difference will the previous blob recorded as “spam”.</p> <p>The diff between the previous head and the new one can be printed using write_tree_diff:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">dulwich.patch</span> <span class="kn">import</span> <span class="n">write_tree_diff</span> <span class="gp">>>> </span><span class="kn">import</span> <span class="nn">sys</span> <span class="gp">>>> </span><span class="n">write_tree_diff</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">,</span> <span class="n">repo</span><span class="o">.</span><span class="n">object_store</span><span class="p">,</span> <span class="n">commit</span><span class="o">.</span><span class="n">tree</span><span class="p">,</span> <span class="n">tree</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="go">diff --git a/spam b/spam</span> <span class="go">index c55063a..16ee268 100644</span> <span class="go">--- a/spam</span> <span class="go">+++ b/spam</span> <span class="go">@@ -1,1 +1,1 @@</span> <span class="go">-My file content</span> <span class="go">+My new file content</span> </pre></div> </div> <p>You won’t see it using git log because the head is still the previous commit. It’s easy to remedy:</p> <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">repo</span><span class="o">.</span><span class="n">refs</span><span class="p">[</span><span class="s">'refs/heads/master'</span><span class="p">]</span> <span class="o">=</span> <span class="n">c2</span><span class="o">.</span><span class="n">id</span> </pre></div> </div> <p>Now all git tools will work as expected.</p> </div> </div> </div> </div> </div> <div class="sphinxsidebar"> <div class="sphinxsidebarwrapper"> <h3><a href="../index.html">Table Of Contents</a></h3> <ul> <li><a class="reference internal" href="#">The object store</a><ul> <li><a class="reference internal" href="#initial-commit">Initial commit</a></li> <li><a class="reference internal" href="#playing-again-with-git">Playing again with Git</a></li> <li><a class="reference internal" href="#changing-a-file-and-committing-it">Changing a File and Committing it</a></li> </ul> </li> </ul> <h4>Previous topic</h4> <p class="topless"><a href="repo.html" title="previous chapter">The repository</a></p> <h4>Next topic</h4> <p class="topless"><a href="remote.html" title="next chapter">Remote repositories</a></p> <h3>This Page</h3> <ul class="this-page-menu"> <li><a href="../_sources/tutorial/object-store.txt" rel="nofollow">Show Source</a></li> </ul> <div id="searchbox" style="display: none"> <h3>Quick search</h3> <form class="search" action="../search.html" method="get"> <input type="text" name="q" /> <input type="submit" value="Go" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> <p class="searchtip" style="font-size: 90%"> Enter search terms or a module, class or function name. </p> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <div class="clearer"></div> </div> <div class="related"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../genindex.html" title="General Index" >index</a></li> <li class="right" > <a href="remote.html" title="Remote repositories" >next</a> |</li> <li class="right" > <a href="repo.html" title="The repository" >previous</a> |</li> <li><a href="../index.html">dulwich 0.9.0 documentation</a> »</li> <li><a href="index.html" >Tutorial</a> »</li> </ul> </div> <div class="footer"> © Copyright 2011, Jelmer Vernooij. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. </div> </body> </html>