http://hades.name/blog/tag/refs/Hades Blag blog posts with tag intersection refs2010-03-03T20:44:18ZEdwarddjango-atompubhttp://hades.name/blog/2010/01/28/git-your-friend-not-foe-vol-3-refs-and-index/Git Is Your Friend not a Foe Vol. 3: Refs and Index2010-03-03T20:44:18Z2010-01-28T14:08:59Z<p>Let’s take a walk along Git repository structure. The central square is Git
Object Database. Objects reference each other by 160-bit unique IDs with a
certain semantics (for example, commit-object references its parent commit(s)
and the tree that corresponds to project’s root directory; tree-object
references blob-objects that correspond to file content and tree-objects that
correspond to subdirectories; etc., see <a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial-2.html">gittutorial-2(7)</a> for details). For the sake of simplicity, let’s forget
about trees and blobs for now, and look at commits only.</p>
<div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-norefs.png" alt="Git with only commits" /></div>
<p>We now have a bunch of commits that know who were their parents. We can trace
history from any given commit back to the very beginning. But how do we know
what is the current state of things? What was the latest commit in the
history? To answer that let’s look at Git <em>refs</em> (short for references). They
are basically named references for Git commits. There are two major types of
refs: <em>tags</em> and <em>heads</em>. Tags are fixed references that mark a specific point
in history, for example <code>v2.6.29</code>. On the contrary, heads are
always moved to reflect the current position of project development. </p>
<div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-refs.png" alt="Git with refs" /></div>
<p>Now we know what is happening in the project. But to know what is happening
right here, right now there is a special reference called <span class="caps">HEAD</span>. It serves two
major purposes: it tells Git which commit to take files from when you checkout
and it tells Git where to put new commits when you commit. When you run
<code>git checkout <em>ref</em></code> it points <span class="caps">HEAD</span> to the <em>ref</em> you’ve designated
and extracts files from it. When you run <code>git commit</code> it creates a
new commit object, which becomes a child of current <span class="caps">HEAD</span>. Normally <span class="caps">HEAD</span> points
to one of the heads, so everything works out just fine. </p>
<div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-head.png" alt="Git with branch HEAD" /></div>
<p>But if you checkout a specific commit instead of a branch, your <span class="caps">HEAD</span> starts
pointing at this commit. This is referred to as <em>detached head</em> and you may be
told that <em>you are not on a branch</em> (git branch says “(no branch)”). This is
perfectly fine, but if you commit anything to it, your commits won’t have a
known ref, so if you checkout another branch, you can lose them. </p>
<div style="margin: auto; width: auto; text-align: center;"><img src="http://hades.name/media/git/git-detached.png" alt="Git with detached HEAD" /></div>
<p>Having said about committing, can’t help stopping by the process of committing itself.
You may already know that the Git’s “add” operation differs from almost every
other <span class="caps">VCS</span> in that you have to “add” not only files that are not yet known to
Git, but also files that you have just modified. This is because <strong>Git takes
content for next commit not from your working copy, but from a special
temporary area</strong>, called <em>index</em>. This allows finer control over what is going
to be committed. You can not only exclude some files from commit, you can
exclude even certain pieces of files from commit (try <code>git add
-i</code>). This helps developers stick to <em>atomic commits</em> principle.</p>
<p>And if you have inhuman ability of creating only perfect committs and need
stupid <span class="caps">VCS</span> only to obey your orders, then you can just use option “-a” for
git-commit. And I envy you.</p>
<p>Another special kind of refs are <em>remotes</em>. Whenever you run <code>git
fetch</code>, it asks the remote repository, what heads and tags does it have,
downloads missing objects (if any) and stores remote refs under refs/remotes
prefix. The remote heads are displayed if you run <code>git branch -r</code>.</p>
<p>Some of your branches (notably <em>master</em>) may be what is called <em>tracking</em>
branches. That means that a certain branch “tracks” its remote counterpart.
Physically that means that when you run <code>git pull</code> on that branch,
the corresponding remote branch gets automatically merged into your local
branch. Fairly recent versions of Git set up tracking automatically when you
checkout a remote branch (for example, <code>git checkout -b stable
origin/stable</code>). Note, however, that sometimes it’s better to <em>rebase</em>
instead of merge.</p>
<p>But that’s a whole new story…</p>
<p>Previous posts:</p>
<ul>
<li><a href="http://hades.name/blog/2010/01/17/git-your-friend-not-foe/">Volume
1, on the distributed <span class="caps">VCS</span> concepts</a></li>
<li><a href="http://hades.name/blog/2010/01/22/git-your-friend-not-foe-vol-2-branches/">Volume
2, on branches and merging</a></li>
</ul>
<p>Next post:</p>
<ul>
<li><a href="http://hades.name/blog/2010/03/03/git-your-friend-not-foe-vol-4-rebasing/">Volume
4, on cherry-picking and rebasing</a></li>
</ul>
<p><a href="http://hades.name/blog/tag/git/">All posts about Git</a></p>