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&#8217;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&#8217;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&#8217;s forget about trees and blobs for now, and look at commits&nbsp;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&#8217;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&nbsp;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&#8217;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&nbsp;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 &#8220;(no branch)&#8221;). This is perfectly fine, but if you commit anything to it, your commits won&#8217;t have a known ref, so if you checkout another branch, you can lose&nbsp;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&#8217;t help stopping by the process of committing itself. You may already know that the Git&#8217;s &#8220;add&#8221; operation differs from almost every other <span class="caps">VCS</span> in that you have to &#8220;add&#8221; 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>&nbsp;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 &#8220;-a&#8221; for git-commit. And I envy&nbsp;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 &#8220;tracks&#8221; 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&#8217;s better to <em>rebase</em> instead of&nbsp;merge.</p> <p>But that&#8217;s a whole new&nbsp;story&#8230;</p> <p>Previous&nbsp;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>&nbsp;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&nbsp;merging</a></li> </ul> <p>Next&nbsp;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&nbsp;rebasing</a></li> </ul> <p><a href="http://hades.name/blog/tag/git/">All posts about&nbsp;Git</a></p>