<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Programblings]]></title>
  <link href="http://www.programblings.com/atom.xml" rel="self"/>
  <link href="http://www.programblings.com/"/>
  <updated>2013-06-17T12:55:27-04:00</updated>
  <id>http://www.programblings.com/</id>
  <author>
    <name><![CDATA[Mathieu Martin]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Do You Back Up Your DNS Records?]]></title>
    <link href="http://www.programblings.com/2012/07/23/do-you-back-up-your-dns-records/"/>
    <updated>2012-07-23T11:34:00-04:00</updated>
    <id>http://www.programblings.com/2012/07/23/do-you-back-up-your-dns-records</id>
    <content type="html"><![CDATA[<p>At the time of writing, <a href="http://www.zerigo.com">Zerigo DNS</a> is being hit by a DDOS
attack (<a href="https://twitter.com/zerigo/status/227262239407759360">reference starting here on Twitter</a>).</p>

<p>I was able to migrate our company&#8217;s services &#8211; <a href="http://www.socialgrapes.com">SocialGrapes</a> and
<a href="http://socialgrapeslab.com">SocialGrapesLAB</a> &#8211; to DNSimple pretty quickly,
mainly because I remembered most of our DNS settings. But still, I had no idea
about some of the finer details, like mail server settings, and didn&#8217;t immediately
remember to put back the records for our CDN.</p>

<p>So in the process of fixing all of this, I decided to add two simple tasks to my
<code>rake backup</code> task. They may be useful to you too:</p>

<!-- more -->


<p>Requirements:</p>

<ul>
<li>the Nokogiri Ruby gem</li>
<li>the dnsimple-ruby Ruby gem</li>
<li>curl</li>
</ul>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">namespace</span> <span class="ss">:backup</span> <span class="k">do</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">namespace</span> <span class="ss">:dns</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">task</span> <span class="ss">:zerigo</span> <span class="k">do</span>
</span><span class='line'>      <span class="nb">require</span> <span class="s1">&#39;nokogiri&#39;</span>
</span><span class='line'>      <span class="n">dir</span>   <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNS_BACKUP_DIR&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="s1">&#39;zerigo&#39;</span> <span class="p">)</span>
</span><span class='line'>      <span class="n">user</span>  <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;ZERIGO_USER&#39;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">key</span>   <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;ZERIGO_KEY&#39;</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>      <span class="sb">`mkdir -p </span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="sb">`</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span> <span class="o">=</span> <span class="sb">`curl --user </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb">:</span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> http://ns.zerigo.com/api/1.1/zones.xml`</span>
</span><span class='line'>      <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s1">&#39;_list.xml&#39;</span><span class="p">),</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="p">{</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="n">list</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="no">Nokogiri</span><span class="o">::</span><span class="no">XML</span><span class="p">(</span><span class="n">list</span><span class="p">)</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;zones zone&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">node</span><span class="o">|</span>
</span><span class='line'>        <span class="nb">id</span>      <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">text</span>
</span><span class='line'>        <span class="n">domain</span>  <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;domain&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">text</span>
</span><span class='line'>        <span class="n">output</span>  <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2">.xml&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2"> (</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">) =&gt; </span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>
</span><span class='line'>        <span class="sb">`curl --user </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb">:</span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> -o &quot;</span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="sb">&quot; http://ns.zerigo.com/api/1.1/zones/</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="sb">/hosts.xml`</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">task</span> <span class="ss">:dnsimple</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">dir</span>   <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNS_BACKUP_DIR&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="s1">&#39;dnsimple&#39;</span> <span class="p">)</span>
</span><span class='line'>      <span class="n">user</span>  <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNSIMPLE_USER&#39;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">key</span>   <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNSIMPLE_KEY&#39;</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>      <span class="sb">`mkdir -p </span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="sb">`</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span> <span class="o">=</span> <span class="sb">`dnsimple -u </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb"> -p </span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> list`</span>
</span><span class='line'>      <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s1">&#39;_list.txt&#39;</span><span class="p">),</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="p">{</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="n">list</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span><span class="o">.</span><span class="n">lines</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:strip</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">domain</span><span class="o">|</span>
</span><span class='line'>        <span class="k">next</span> <span class="k">if</span> <span class="n">domain</span> <span class="o">=~</span> <span class="sr">/Found .* domain/</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">output</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2">.txt&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2"> =&gt; </span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>
</span><span class='line'>        <span class="sb">`dnsimple -u </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb"> -p </span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> record:list </span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="sb"> &gt; &quot;</span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="sb">&quot;`</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>  <span class="n">desc</span> <span class="s2">&quot;backup dns records from all services&quot;</span>
</span><span class='line'>  <span class="n">task</span> <span class="ss">:dns</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;dns:zerigo&#39;</span><span class="p">,</span> <span class="s1">&#39;dns:dnsimple&#39;</span><span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">desc</span> <span class="s2">&quot;Run all backup tasks FROM=env (default production)&quot;</span>
</span><span class='line'><span class="n">task</span> <span class="ss">:backup</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;backup:dns&#39;</span><span class="p">,</span> <span class="s1">&#39;backup:database&#39;</span><span class="p">,</span> <span class="s1">&#39;backup:images&#39;</span><span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>


<p>To reuse this, you should install all dependencies, then set up the following
environment variables:</p>

<ul>
<li>DNSIMPLE_USER (your account&#8217;s email)</li>
<li>DNSIMPLE_KEY (not the API key, but the password, unfortunately)</li>
<li>ZERIGO_USER (your account&#8217;s email)</li>
<li>ZERIGO_KEY (your account&#8217;s api key. Turn on api access in Manage account / DNS / preferences)</li>
<li>optionally, DNS_BACKUP_DIR</li>
</ul>


<p>Obviously all of this is an almost trivial backup that will only help you
restore things manually when things go bad. You may want to replicate any new
record to a secondary service, but I chose not to.  I&#8217;m comfortable with this
situation, since <a href="http://socialgrapeslab.com">rating wines you love or dislike</a>
is not considered critical ;-)</p>

<p>So, do you back up your DNS records?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bach from the dead]]></title>
    <link href="http://www.programblings.com/2012/07/04/bach-from-the-dead/"/>
    <updated>2012-07-04T08:01:00-04:00</updated>
    <id>http://www.programblings.com/2012/07/04/bach-from-the-dead</id>
    <content type="html"><![CDATA[<p><img src="http://www.programblings.com/uploads/2012/bach_from_the_dead.jpg" alt="Bach from the dead" /></p>

<p>I think it&#8217;s pretty funny that the last article on my blog is 3 years old, and starts with &#8220;I haven’t been blogging much lately&#8221; :-)</p>

<!-- more -->


<p>A lot has happened since then. I&#8217;ve worked for more than a year for a now bust
startup (SmartHippo), and then went on to work for
<a href="http://www.socialgrapes.com">SocialGrapes</a>,
for more than 2 years. I&#8217;m still there, as the lead developer and CTO.</p>

<p>I could say we&#8217;re right in the
<a href="http://www.avc.com/a_vc/2012/03/the-startup-curve.html">trough of sorrow</a>.
But that&#8217;s not what this post is about.</p>

<p>This post is about coming back to blogging.
I miss rambling about the stuff I do day in and day out. Wordpress fatigue kept
eventually eroded my desire to blog.</p>

<p>This blog is now hosted with Octopress on S3, which I think is pretty neat :-)
I may post about my setup, but there&#8217;s quite a few blog posts in the wild
discussing hosting jekyll-based sites on S3.</p>

<p>I&#8217;ve got a ton to blog about, I just hope I can find enough time! I&#8217;ve started
working on git_remote_branch again, I created a JavaScript library that I
haven&#8217;t talked about anywhere (I didn&#8217;t have a good place :), I&#8217;ve
discovered a ton of new tools, and so on.</p>

<p>I&#8217;ll likely start with a series of posts about Heroku, though. After presenting
&#8220;Advanced Heroku&#8221; at the last Montreal.rb, I realized that a single blog post
about it all would be even more long and tedious than the presentation :-)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A new Ruby and Rails blog is born]]></title>
    <link href="http://www.programblings.com/2009/02/16/a-new-ruby-and-rails-blog-is-born/"/>
    <updated>2009-02-16T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2009/02/16/a-new-ruby-and-rails-blog-is-born</id>
    <content type="html"><![CDATA[<p>I haven&#8217;t been blogging much lately. I&#8217;ve been too busy with some vacation time and, of course, work.</p>




<p>This is going to change, but it&#8217;s not all going to happen on Programblings.</p>




<p>It&#8217;s been a long time coming, but <a href='http://giraffesoft.ca'>giraffesoft</a> finally has a blog. We&#8217;re going to kickstart our blog with a week of open source releases.</p>




<p>At giraffesoft we like DRY code. We all know that creating Rails plugins is barely more work than actually implementing the functionality inside of a specific application. For that reason, we create plugins all the time when working on projects.</p>




<p>So this week, we&#8217;re going to polish up a few of them &#8211; big and small &#8211; and officially introduce them to the world.</p>




<p>For now, please let me direct you to the brand-spanking new <a href='http://giraffesoft.ca/blog'>giraffesoft blog</a>.</p>




<p>If you&#8217;re too lazy to read the introductory post, here&#8217;s the punchlines:</p>




<ul>
<li><a href='http://feeds.giraffesoft.ca/giraffesoft-the-blog'>follow our RSS feed</a> or</li>

<li><a href='http://twitter.com/giraffesoft'>follow us on Twitter</a>.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rubinius for the Layman, Part 3 - Try Rubinius in 20 minutes]]></title>
    <link href="http://www.programblings.com/2008/11/25/rubinius-for-the-layman-part-3-try-rubinius-in-20-minutes/"/>
    <updated>2008-11-25T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/25/rubinius-for-the-layman-part-3-try-rubinius-in-20-minutes</id>
    <content type="html"><![CDATA[<p>I guess we&#8217;ve all heard <a href='http://blog.fallingsnow.net/2008/11/18/a-sad-day/'>last week&#8217;s sad news</a> about Engine Yard <a href='http://blog.engineyard.com/2008/11/17/rubinius-past-present-and-future'>diminishing the awesome support</a> they&#8217;ve given the Rubinius project. That&#8217;s personally how I see it: they&#8217;ve put the project on steroids for roughly a year, rather than &#8220;they&#8217;re now cutting back&#8221; x people.</p>




<p>As Brian Ford <a href='http://blog.brightredglow.com/2008/11/18/rubinius-is-a-community-project'>pointed out</a>, Rubinius is a community project. And Rubinius is not going away. A lot of people can&#8217;t wait to have a Ruby written more in Ruby than in C or C++. Koichi Sasada (lead developer on Ruby 1.9) even recently projected that Rubinius would eventually be the Ruby implementation of choice.</p>




<!-- more -->




<p>Rubinius&#8217; future is promising. I&#8217;d like to go from that positive note, and have YOU try Rubinius now. I promise that in 20 minutes, you&#8217;ll be running Rubinius and enjoying it. The longest parts of the process will be waiting (cloning, compiling), so it won&#8217;t even be difficult. Note: the article may look long, but it&#8217;s not. Half of it is code samples and the results returned.</p>




<p>So it&#8217;s been aeons since the last article of the RFTL series. But yes, this article is part of a series. You can look at the first 2 parts if you want. Some details<a href='#footnote_1'><sup>1</sup></a> won&#8217;t be up to date anymore, but it&#8217;ll help you get the gist of Rubinius if you&#8217;re not familiar with the project yet.</p>




<ul>
<li><a href="http://www.programblings.com/2008/04/01/rubinius-for-the-layman-part-1-rubies-all-the-way-down/">Rubinius for the Layman, Part 1: Rubies All the Way Down</a></li>

<li><a href="http://www.programblings.com/2008/04/15/rubinius-for-the-layman-part-2-how-rubinius-is-friendly/">Rubinius for the Layman, Part 2: How Rubinius is Friendly</a></li>

<li>Rubinius for the Layman, Part 3 - Try Rubinius in 20 minutes</li>
</ul>




<p>The 20 minutes timer starts now, for those who went ahead and read the past articles.</p>




<h1 id='install_rubinius'>Install Rubinius</h1>




<h2 id='prerequisites'>Prerequisites</h2>




<p>Prerequisites are probably already taken care of on most Ruby developers&#8217; machines:</p>




<ul>
<li>ruby 1.8, rubygems, rake and ParseTree (<code>sudo gem install rake ParseTree</code>)</li>

<li>git (no need to understand it, really, just having it installed)</li>

<li>general C++ building tools</li>
</ul>




<h3 id='dependencies_for_mac_users'>Dependencies for Mac users</h3>




<p>Leopard users should have all they need when Xcode is installed. Insert your Leopard upgrade DVD and from your terminal:</p>




<pre><code>open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg </code></pre>




<h3 id='dependencies_for_linux_users'>Dependencies for Linux users</h3>




<p>Linux users have to make sure the following packages are installed. Use your the equivalent command for your distro:</p>




<pre><code>sudo apt-get install gcc bison make pkg-config libtool git</code></pre>




<p>(where make == GNU make)</p>




<h2 id='get_the_rubinius_code'>Get the Rubinius code</h2>




<p>Right now the GitHub feature to download a tarball is disabled for big projects like Rubinius. They say the feature on the radar as one of the things to fix in the next few weeks. Which will be awesome.</p>




<p>For now we have have to clone the repo, which in this case takes a few minutes. Find yourself a comfortable directory and:</p>




<pre><code>git clone git://github.com/evanphx/rubinius.git
# go make coffee
cd rubinius</code></pre>




<h2 id='build_rubinius'>Build Rubinius</h2>




<p>Assuming you&#8217;ve installed all the dependencies, the following should work right off the bat. If it&#8217;s not the case, check out the <a href='#footnote_2'>notes on the subject</a>.</p>




<pre><code>rake build
# go get a http://www.brawndo.com/</code></pre>




<p>Later, when you want to recompile from a clean slate, just run <code>rake distclean</code>.</p>




<p>If you have not gotten a BRAWNDO, please <a href='#run_rubinius'>skip over the next paragraph</a>.</p>




<p>RUBINIUS, like BRAWNDO, is one of the CRAZIEST ideas of the LAST DECADE! Can you realize you&#8217;re ABOUT to try the Ruby IMPLEMENTATION that&#8217;s got the BEST Ruby code ratio AMONG THEM ALL! Isn&#8217;t that FREAKING AWESOME? You can also do some of the CRAZIEST INTROSPECTION with MethodContext, StaticScope and other classes like THAT!</p>




<h1 id='run_rubinius'>Run Rubinius</h1>




<p>The Rubinius executable is rbx in the &#8216;bin&#8217; subdirectory. It&#8217;s a bit different from MRI in that rbx starts an irb session if you don&#8217;t specify a file to run. So let&#8217;s do that:</p>




<pre><code>bin/rbx
# in irb
puts &quot;Don&#39;t you spring a hello world on me&quot;
#=&gt; Don&#39;t you spring a hello world on me</code></pre>




<p>Ok then. Well, technically you&#8217;ve now tried Rubinius in less than 20 minutes. Now if you keep reading, you&#8217;ll really taste some true Rubinius awesomeness.</p>




<h2 id='kickass_introspection'>Kick-ass introspection</h2>




<p>Let&#8217;s start slow by patching <code>Object</code> to help us quickly grok the new kinds of objects we may encounter:</p>




<pre><code>class Object
  # Return only the methods not present on basic objects
  def interesting_methods
    (self.methods - Object.new.methods).sort
  end
end
#=&gt; #&lt;CompiledMethod interesting_methods file=(irb)&gt;</code></pre>




<p>And now let&#8217;s create a basic little class that will help us start our exploration of a <code>MethodContext</code> instance.</p>




<pre><code>class C
  def initialize
    @inst = 42
  end
  def get_mc
    local_var = &#39;value&#39;
    MethodContext.current
  end
end
#=&gt; #&lt;CompiledMethod get_mc file=(irb)&gt;</code></pre>




<p>So with the help of an instance of the class <code>C</code>, let&#8217;s start poking gently at a <code>MethodContext</code>.</p>




<pre><code>c   = C.new
ctx = c.get_mc
#=&gt; #&lt;MethodContext:0xcc #&lt;C:0xca&gt;#get_mc (irb):7&gt;

ctx.interesting_methods
#=&gt; [&quot;__add_method__&quot;, &quot;_get_field&quot;, &quot;_set_field&quot;, &quot;activate&quot;, 
 &quot;active_path&quot;, &quot;alias_method&quot;, &quot;back_ref&quot;, &quot;block&quot;, &quot;class_variable_defined?&quot;,
 &quot;const_defined?&quot;, &quot;const_path_defined?&quot;, &quot;context_from_proc&quot;, &quot;context_stack&quot;, 
 &quot;copy&quot;, &quot;current_scope&quot;, &quot;describe&quot;, &quot;disable_long_return!&quot;, &quot;dynamic_locals&quot;, 
 &quot;file&quot;, &quot;fp&quot;, &quot;from_eval?&quot;, &quot;get_eval_local&quot;, &quot;ip&quot;, &quot;ip=&quot;, &quot;last_match&quot;, 
 &quot;last_match=&quot;, &quot;line&quot;, &quot;lines&quot;, &quot;locals&quot;, &quot;locals=&quot;, &quot;location&quot;, 
 &quot;make_independent&quot;, &quot;method=&quot;, &quot;method_module&quot;, &quot;method_scope&quot;, 
 &quot;method_scope=&quot;, &quot;name&quot;, &quot;normalized_name&quot;, &quot;nth_ref&quot;, &quot;position_info&quot;, 
 &quot;receiver&quot;, &quot;receiver=&quot;, &quot;reload_method&quot;, &quot;script_object&quot;, &quot;send_private?&quot;, 
 &quot;sender&quot;, &quot;set_eval_local&quot;, &quot;set_iseq&quot;, &quot;sp&quot;, &quot;stack_trace_starting_at&quot;]

ctx.name
#=&gt; :get_mc

ctx.describe
#=&gt; &quot;C\#get_mc&quot;

ctx.method_module
#=&gt; C</code></pre>




<p>Interesting, that reminds me of the monkey-patching discussion that often comes up in the Ruby community. Let&#8217;s try something else:</p>




<pre><code>module ModuleMC
  def module_mc
    MethodContext.current
  end
end
#=&gt; #&lt;CompiledMethod module_mc file=(irb)&gt;

C.include ModuleMC
#=&gt; [ModuleMC]

c.module_mc.method_module
#=&gt; #&lt;IncludedModule:0xd6&gt;

c.module_mc.method_module.name
#=&gt; &quot;ModuleMC&quot;</code></pre>




<p>Wouldn&#8217;t it be nice if we had that kind of introspection, when comes time to debug some mixin magic?</p>




<p>Now let&#8217;s go back our <code>MethodContext</code> object. Or rather, its <code>method</code> accessor, which gives us a <code>CompiledMethod</code> instance:</p>




<pre><code>m = ctx.method
#=&gt; #&lt;CompiledMethod get_mc file=(irb)&gt;

m.interesting_methods
#=&gt; [&quot;__ivars__&quot;, &quot;__ivars__=&quot;, &quot;activate&quot;, &quot;activate_as_script&quot;, 
&quot;as_script&quot;, &quot;child_methods&quot;, &quot;compile&quot;, &quot;decode&quot;, &quot;describe&quot;, 
&quot;exceptions&quot;, &quot;exceptions=&quot;, &quot;file&quot;, &quot;file=&quot;, &quot;first_ip_on_line&quot;, 
&quot;first_line&quot;, &quot;from_string&quot;, &quot;hints&quot;, &quot;hints=&quot;, &quot;inherit_scope&quot;, 
&quot;is_block?&quot;, &quot;iseq&quot;, &quot;iseq=&quot;, &quot;line_from_ip&quot;, &quot;lines&quot;, &quot;lines=&quot;, 
&quot;literals&quot;, &quot;literals=&quot;, &quot;local_count&quot;, &quot;local_count=&quot;, &quot;local_names&quot;, 
&quot;local_names=&quot;, &quot;locate_line&quot;, &quot;min_stack_size&quot;, &quot;name&quot;, &quot;name=&quot;, 
&quot;primitive&quot;, &quot;primitive=&quot;, &quot;private?&quot;, &quot;protected?&quot;, &quot;public?&quot;, 
&quot;required_args&quot;, &quot;required_args=&quot;, &quot;scope&quot;, &quot;scope=&quot;, &quot;send_sites&quot;, 
&quot;serial&quot;, &quot;serial=&quot;, &quot;splat&quot;, &quot;splat=&quot;, &quot;stack_size&quot;, &quot;stack_size=&quot;, 
&quot;total_args&quot;, &quot;total_args=&quot;]

m.describe
#=&gt; &quot;method get_mc: 0 arg(s), 0 required&quot;

m.local_names
#=&gt; #&lt;Tuple: :local_var&gt;

m.literals
#=&gt; #&lt;Tuple: &quot;value&quot;, :MethodContext, #&lt;SendSite:0xda 
#     name=current hits=0 misses=0&gt;&gt;

m.file
#=&gt; :&quot;(irb)&quot;</code></pre>




<p>The <code>local_names</code> method sounds extremely promising, but unfortunately for now, there&#8217;s no primitive for actually getting the local variable&#8217;s value, but it&#8217;s perfectly possible<a href='#footnote_3'><sup>3</sup></a>. It&#8217;s just not been done yet.</p>




<p>By the way, what is that? <code>#describe</code> summarizes the arguments? Let&#8217;s try something more interesting with it:</p>




<pre><code>def method_with_args(arg1, arg2=&#39;default&#39;, *args)
  MethodContext.current
end
#=&gt; #&lt;CompiledMethod method_with_args file=(irb)&gt;

ctx2 = method_with_args(42, &#39;towel&#39;, &quot;don&#39;t panic&quot;)
#=&gt; #&lt;MethodContext:0x16e main#method_with_args (irb):4&gt;

m2 = ctx2.method
#=&gt; #&lt;CompiledMethod method_with_args file=(irb)&gt;

m2.describe
#=&gt; &quot;method method_with_args: 2 arg(s), 1 required, splatted.&quot;

m2.local_names
#=&gt; #&lt;Tuple: :arg1, :arg2, :args&gt;

m2.literals
#=&gt; #&lt;Tuple: &quot;default&quot;, :MethodContext, #&lt;SendSite:0x16c 
#     name=current hits=1 misses=0&gt;&gt;</code></pre>




<p>Nice! Ok, now let&#8217;s come back to our <code>CompiledMethod</code> instance and check out it&#8217;s <code>scope</code> accessor.</p>




<pre><code>ss = m.scope
#=&gt; #&lt;StaticScope:0xea parent=#&lt;StaticScope:0xe8 parent=nil 
#     module=Object&gt; module=C&gt;

ss.interesting_methods
#=&gt; [&quot;initialize&quot;, &quot;module&quot;, &quot;parent&quot;, &quot;script&quot;, &quot;script=&quot;]

ss.parent
#=&gt; #&lt;StaticScope:0xe8 parent=nil module=Object&gt;</code></pre>




<p>So now we&#8217;ve essentially poked 2 levels deep: <code>ctx.method.scope</code>. Let&#8217;s rewind again and look at a our context&#8217;s <code>receiver</code> and <code>sender</code> accessors. To better understand both, let&#8217;s come back to our OO roots of 30 years back and start calling &#8216;method calls&#8217; &#8216;messages&#8217; instead.</p>




<p>sender (sends message &#8216;get_mc&#8217;) =&gt; receiver</p>




<p><code>sender</code> is then the caller of the method, and <code>receiver</code> is, the object receiving the message. Also known as <code>self</code>, during the execution of the method.</p>




<p>Let&#8217;s see that in action:</p>




<pre><code>r  = ctx.receiver
#=&gt; #&lt;C:0xca @inst=42&gt;

r == c
#=&gt; true</code></pre>




<p>So ctx.receiver is a reference to the instance we&#8217;d put in the variable <code>c</code>. From there of course we can do Ruby&#8217;s regular meta-poking around:</p>




<pre><code>r.instance_variable_get &#39;@inst&#39;
#=&gt; 42</code></pre>




<p>Now let&#8217;s look at the sender:</p>




<pre><code>s = ctx.sender
#=&gt; #&lt;BlockContext:0xf0 main#irb_binding (irb):1&gt;

s.class.ancestors
#=&gt; [BlockContext, MethodContext, Object, PP::ObjectMixin, Kernel]

s.interesting_methods - ctx.interesting_methods
#=&gt; [&quot;env&quot;, &quot;home&quot;]

s.home
#=&gt; #&lt;MethodContext:0xf6 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1&gt;

s.env
#=&gt; #&lt;BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456 
#     @post_send=0 @bonus=#&lt;Tuple: true&gt;&gt;</code></pre>




<p>When calling a method from IRB, we&#8217;re in a BlockContext instead of a MethodContext, but it&#8217;s still in the family.</p>




<pre><code>s = ctx.sender
#=&gt; #&lt;BlockContext:0xfe main#irb_binding (irb):1&gt;

s.class.ancestors
#=&gt; [BlockContext, MethodContext, Object, Kernel]</code></pre>




<p>Anything new we need to know about?</p>




<pre><code>s.interesting_methods - ctx.interesting_methods
#=&gt; [&quot;env&quot;, &quot;home&quot;]

s.home
#=&gt; #&lt;MethodContext:0x102 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1&gt;

s.env
#=&gt; #&lt;BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456
#     @post_send=0 @bonus=#&lt;Tuple: true&gt;&gt;</code></pre>




<p>All of this is strangely reminiscent of a stack trace. Before you go collecting all senders to explore the execution stack, let me point you to the convenient <code>context_stack</code>:</p>




<pre><code>ctx.context_stack.length
#=&gt; 27

puts *ctx.context_stack
# Too noisy to output here

puts *ctx.context_stack.map{ |s| s.describe }

#=&gt;
# C#get_mc
# Object#irb_binding {}
# Kernel(IRB::WorkSpace)#eval
# IRB::WorkSpace#evaluate
# IRB::Context#evaluate
# IRB::IrbRubinius#process_statements {}
# IRB::Irb(IRB::IrbRubinius)#signal_status
# IRB::IrbRubinius#process_statements {}
# RubyLex#each_top_level_statement {}
# Kernel(RubyLex)#catch {}
# ThrownValue.register
# Kernel(RubyLex)#catch
# RubyLex#each_top_level_statement
# IRB::IrbRubinius#process_statements
# IRB::Irb(IRB::IrbRubinius)#eval_input
# IRB.start {}
# Kernel(Module)#catch {}
# ThrownValue.register
# Kernel(Module)#catch
# IRB.start
# main.__script__
# CompiledMethod#activate_as_script
# CompiledMethod#as_script
# Compile.single_load
# Compile.unified_load
# Kernel(Object)#require
# Object#__script__
# #=&gt; nil</code></pre>




<p>I&#8217;m pretty sure there&#8217;s other areas specific to Rubinius that can be explored like that. Please share any insight in the comments.</p>




<h2 id='sexpressions'>S-Expressions</h2>




<p>Rubinius groks s-expressions out of the box (similar to standard Ruby with <a href='http://parsetree.rubyforge.org/'>ParseTree or ruby_parser</a>. <a href='http://gist.github.com/27156'>An example</a>).</p>




<pre><code>require &#39;pp&#39;
pp sx = &quot;
  class C
    def meth(arg)
      arg * 2
    end
  end&quot;.to_sexp

#=&gt;
# s(:class,
#  :C,
#  nil,
#  s(:scope,
#   s(:defn,
#    :meth,
#    s(:args, :arg),
#    s(:scope,
#     s(:block, s(:call, s(:lvar, :arg), :*, s(:arglist, s(:fixnum, 2))))))))

sx[0]
#=&gt; :class

sx[3][1][1]
#=&gt; :meth</code></pre>




<p>With something that reminiscent to Lisp, it&#8217;s probably better to explore recursively, though.</p>




<p>S-expressions are used by a lot of the Ruby <a href='http://devver.net/blog/2008/10/ruby-tools-roundup/'>code inspection tools</a> to understand your ugly Ruby code.</p>




<h2 id='gems'>Gems</h2>




<p>I won&#8217;t touch trying out gems for today. There seems to be little issues as the moment. They do install, but I&#8217;ve been having problems running them. Please leave a comment if you&#8217;ve had success with specific gems.</p>




<p>If you&#8217;re curious and want to try playing with gems, Rubygems is already installed.</p>




<pre><code>rbx gem install rails --no-rdoc --no-ri</code></pre>




<p>Pro tip: always skip the documentation when playing with gems Rubinius. The doc takes unusually long to compile.</p>




<h2 id='run_the_famous_test_suite'>Run the famous test suite</h2>




<p>The spec suite that&#8217;s been keeping all Ruby implementations honest was born from the Rubinius project. It&#8217;s been split into a separate project a while ago, since it&#8217;s now such an important and central piece of the Ruby ecosystem.</p>




<h3 id='update_the_specs'>Update the specs</h3>




<p>Since they are now in a different project, we first have to get the most recent version. Easy stuff:</p>




<pre><code>rake rubyspec:update</code></pre>




<h3 id='rbx_in_your_path'>rbx in your PATH</h3>




<p>Before you run the specs, you need to do one little thing. One of the specs expects a shell call to rbx to start Rubinius (as in, the executable must be in your path).</p>




<p>The simplest way to do that for now is just to temporarily add the directory to your path (right in your console, not in your .bash_profile).</p>




<pre><code>pwd
#=&gt; /path/to/project/rubinius
export PATH=$PATH:/path/to/project/rubinius/bin
rbx -v</code></pre>




<h3 id='run_the_specs'>Run the specs</h3>




<pre><code>rake spec
# Time for another BRAWNDO!</code></pre>




<p>Or rather, time to actually look at some of the specs you&#8217;re currently running. If you look in the spec directory, you&#8217;ll see that it&#8217;s pretty extensive, to say the least. To start with something familiar, navigate to spec/ruby/1.8, in subdirectories core or library. Open up a few of the specs in there and stare at them for a few minutes. Or better, improve a few of them and try them out on MRI, JRuby and of course, Rubinius.</p>




<h1 id='conclusion'>Conclusion</h1>




<p>Well, now I&#8217;ve tricked you into putting the Rubinius project on your hard drive. And you&#8217;re a Ruby developer. What are you waiting for?</p>




<ul>
<li><a href='http://github.com/evanphx/rubinius/tree/master/doc/contributing.txt'>Contribute</a></li>

<li><a href='http://github.com/evanphx/rubinius/tree/master/doc'>Documentation</a></li>

<li><a href='http://rubinius.lighthouseapp.com/projects/5089-rubinius/overview'>Tickets overview</a></li>
</ul>




<p>I think Rubinius will be an awesome runtime for our Ruby programs. It probably won&#8217;t be <em>only</em> Ruby in the close future, but the kernel of Ruby (base classes &amp; stuff) is mostly implemented in Ruby, and the compiler is also implemented in Ruby. This is awesome to help understand the workings of the language and to lower the barrier to contribution. Which is already pretty low.</p>




<p>Rubinius is here to stay and it&#8217;s gonna keep rocking.</p>




<h1 id='footnotes'>Footnotes</h1>


<ol>
  <li id='footnote_1'>
    Examples of details not up to date in the old articles are: the LOC numbers and the base language of the VM (used to be C, now C++).
  </li>
  <li id='footnote_2'>
    If the build craps out with a message you understand, cool. Try to install the dependency through apt-get or macports/fink, or search your hard drive to see if the tool&#8217;s just not in your PATH. Otherwise, here are a few related pointers.
    <ul>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/doc/getting_started.txt'>Getting Started</a>
      </li>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/INSTALL'>Installation</a>
      </li>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/doc/common_problems.txt'>Common Problems</a>
      </li>
      <li>
        If you can&#8217;t find an answer in the doc, don&#8217;t hesitate and ask on IRC in #rubinius (freenode.org). The crew&#8217;s very friendly.
      </li>
    </ul>
  </li>
  <li id='footnote_3'>
    For a quick discussion about getting local variable&#8217;s values out of a CompiledMethod, check the [IRC logs around 19:20][9].
  </li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git-config has autocomplete?]]></title>
    <link href="http://www.programblings.com/2008/11/21/git-config-has-autocomplete/"/>
    <updated>2008-11-21T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/21/git-config-has-autocomplete</id>
    <content type="html"><![CDATA[<p>Seen on a git 1.6.0.4 installation (dunno about previous versions), installed through MacPorts <a href='#footnote_1'><sup>1</sup></a> with the <a href='http://trac.macports.org/wiki/howto/bash-completion'>+bash_completion</a> option.</p>




<pre><code>$ git config #tab
apply.whitespace               core.compression        ...
branch.                        core.fileMode           
clean.requireForce             core.gitProxy           
color.branch                   core.ignoreStat         
color.branch.current           core.logAllRefUpdates   
...</code></pre>




<!-- more -->




<p>With sub-options too, on words ending with a dot:</p>




<pre><code>$ git config remote.origin. #tab
remote.origin.fetch               remote.origin.receivepack      ...
remote.origin.push                remote.origin.skipDefaultUpdate</code></pre>




<p>And as usual, calling git-config with a setting name without specifying a new value displays the current value.</p>




<pre><code>$ git config remote.origin.url
git://github.com/evanphx/rubinius.git</code></pre>




<p>Git&#8217;s getting easier by the day. Awesome!</p>


<p id='footnote_1'>
  1. A recent change from <a href='http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard/#comment-914'>a previous position</a>!
</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing ruby 1.9preview1 on OS X Leopard]]></title>
    <link href="http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard/"/>
    <updated>2008-11-18T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard</id>
    <content type="html"><![CDATA[<p>Tonight I&#8217;m trying conciseness.</p>




<p><em>Editor&#8217;s note: I failed.</em></p>




<p>I recently decided to test my <a href='http://grb.rubyforge.org/'>git_remote_branch gem</a> with Ruby 1.9, for the heck of it. Well, I was making sure it <a href='http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses/'>ran on a bunch of platforms</a>: Windows, Ruby 1.8.7 and with the most recent Git version (1.6.0.2, <a href='http://git.or.cz/#download'>get it</a>). So it seemed fitting to check it out under Ruby 1.9.</p>




<p>On Leopard, the only missing dependency to Ruby 1.9 is readline 5.2. This article will present the installation of both. And help heat up your apartment.</p>




<!-- more -->




<h3 id='linux_too'>Linux too</h3>




<p>These instructions will mostly work on Linux as well (tried on Ubuntu). There will be a few minor differences though.</p>




<ul>
<li>Make sure you download the original readline from the gnu site and patch it yourself;</li>

<li>Uninstall older versions of Ruby1.9;</li>

<li>Make sure you have the basic dev tools installed, like gcc and make;</li>

<li>Skip the part about installing Xcode :-)</li>
</ul>




<h2 id='prerequisites'>Prerequisites</h2>




<p>You first need to have the Apple developer tools installed on your mac. They&#8217;re available on your installation CD. Put it in, run the installer. It&#8217;s pretty straightforward.</p>




<pre><code># in your terminal
open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg </code></pre>




<p>If you don&#8217;t compile your own stuff often, you may have to set up your PATH variable in your ~/.bash_profile.</p>




<pre><code># file  ~/.bash_profile
export PATH=&quot;/usr/local/bin:$PATH&quot;</code></pre>




<p>Now, prepare a working directory to keep the source close to the corresponding executables.</p>




<pre><code># in your terminal
sudo mkdir -p /usr/local/src
sudo chgrp admin /usr/local/src
sudo chmod -R 775 /usr/local/src
cd /usr/local/src</code></pre>




<p>Once you&#8217;ve set yourself up, if you don&#8217;t care about the details, you can skip to the end for <a href='#cliffs_notes'>the Cliff&#8217;s notes</a>.</p>




<h2 id='installing_readline'>Installing readline</h2>




<p>This one&#8217;s not as straightforward as it could have been. The gzipped readline library available on the gnu site is 12 patches behind. It so happens that the 12th patch fixes a problem with compilation under OS X. So I applied all 12 to the code and repackaged it. The example uses that file, compiled by me.</p>




<p>You can also do do the patching by yourself if you so wish. Here&#8217;s where you can download the readline code:</p>




<ul>
<li>
<p><a href='ftp://ftp.gnu.org/gnu/readline/readline-5.2.tar.gz'>The main file</a></p>
</li>

<li>
<p><a href='ftp://ftp.gnu.org/gnu/readline/readline-5.2-patches'>The patches</a></p>
</li>
</ul>




<p>So let&#8217;s get on with the instructions to install readline from my patched package:</p>




<pre><code># in your terminal
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012

./configure --prefix=/usr/local
make
sudo make install
cd ..</code></pre>




<h2 id='build_ruby_19'>Build Ruby 1.9</h2>




<h3 id='build_options'>Build options</h3>




<p>Note that here you have a few options as to how you want to distinguish your 1.9 stack from your main 1.8 one.</p>




<p>In the following example, I build Ruby with the &#8216;1.9&#8217; suffix, which means all executables will be suffixed with 1.9: ruby1.9, gem1.9, irb1.9, rake1.9 and so on. This approach is ideal for casual use of two versions side by side. If you don&#8217;t care about the details, skip right over the next paragraph.</p>




<p>The industrial approach would be to put ruby in a non standard directory and only add it to your path when you want to use that version (or use the explicit path to invoke executables). To go industrial, you can simply use the <code>--prefix=/usr/local/ruby1.9</code> option and then drop the <code>--program-suffix</code> argument when you run configure for Ruby. This setup is ideal if you really want to have a bunch of versions living side by side (e.g. all 1.9 versions as well as 1.8.7 in addition to the current 1.8.6).</p>




<h3 id='actual_installation_of_ruby_19'>Actual installation of Ruby 1.9</h3>




<p>Pick the most recent version or Ruby 1.9 on the <a href='ftp://ftp.ruby-lang.org/pub/ruby/'>ftp server</a>. At the time of writing, 1.9.1-preview1 is the most recent.</p>




<p>So, still from /usr/local/src:</p>




<pre><code># in your terminal
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install</code></pre>




<p>Now you&#8217;re about to see some of the funniest looking progress indicators around. Ruby&#8217;s about making the programmer happy, and it delivers even in the details!</p>




<p>Note: the recent source packages of Ruby1.9 automatically include the documentation, as the end of the make install attests.</p>




<h2 id='try_ruby_19'>Try Ruby 1.9</h2>




<pre><code># in your terminal
ruby1.9 --version
gem1.9 --version
irb1.9</code></pre>




<p>Once inside the Ruby interactive shell,</p>




<pre><code># in irb1.9
RUBY_VERSION
#=&gt; &quot;1.9.1&quot;
stabby = -&gt;(msg=&#39;inside the stabby lambda&#39;) { puts msg }
stabby.call
# =&gt; &quot;inside the stabby lambda&quot;
stabby.call &#39;hello world&#39;
# =&gt; &quot;hello world&quot;</code></pre>




<p>Yep, Ruby 1.9 introduces the very cool stabby lambda syntax. Ruby 1.8&#8217;s lambdas couldn&#8217;t have optional parameters (unless you fiddled with *args). 1.9&#8217;s stabby lambdas can, with a syntax as clean as a simple method definition, as you just experimented.</p>




<p>Now install the gems you use everyday (or kindly make available to your peers) and help make them 1.9 compatible.</p>




<p>For the sake of the stabby lambda!</p>




<p>That&#8217;s it! (Except for those who skipped to the <a href='#cliffs_notes'>Cliff&#8217;s Notes</a>).</p>




<h2 id='cliffs_notes'>Cliff&#8217;s Notes</h2>




<pre><code># Install patched readline
cd /usr/local/src
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012
./configure --prefix=/usr/local
make
sudo make install
cd ..

# Install Ruby1.9
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install

# Try Ruby 1.9
ruby1.9 --version
gem1.9 --version
irb1.9

# in irb1.9
RUBY_VERSION
stabby = -&gt;(msg=&#39;inside the stabby lambda&#39;) { puts msg }
stabby.call
stabby.call &#39;hello world&#39;</code></pre>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git_remote_branch is github-agnostic]]></title>
    <link href="http://www.programblings.com/2008/11/17/git_remote_branch-is-github-agnostic/"/>
    <updated>2008-11-17T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/17/git_remote_branch-is-github-agnostic</id>
    <content type="html"><![CDATA[<p><a href="http://joshknowles.com">Josh Knowles</a> recently suggested that maybe I could merge grb’s functionality to the github gem.</p>

<p>Both gems being command-line tools that help you use Git in a friendlier manner, the question makes a lot of sense. It makes so much sense in fact, that I decided to blog about it. A post about it will scale much better to answer other users who may potentially ask the same question.</p>

<p>So here’s a slightly edited excerpt from the answer I gave him. And yes, I also ramble in email.</p>

<!-- more -->


<blockquote><p>I’ve seen what Scott added to the github gem. Pretty cool stuff indeed. I think the idea of merging with the github gem has merit. I definitely can see a future where we start having too many distinct command-line tools that help deal with Git’s sometimes obscure or numerous commands.</p>

<p>However I’m not sure I’d like to merge grb into the gh gem, despite the additional awareness it would get. Here’s why.</p>

<p>In my mind, the github gem should be mostly features about GitHub itself, like managing pull requests (the way GitHub does them). It’s starting to accumulate features that probably aren’t GitHub-specific, which I don’t mind, of course. But grb’s features really are GitHub-agnostic. I’ve started working on it before I even started using GitHub, in fact :-)</p>

<p>Reinforcing the previous point, I wouldn’t want someone who doesn’t use GitHub to not realize the features of grb are available to him because they’re included in a gem called ‘github’ ;-)</p>

<p>Also, one of the goals of git_remote_branch is to explicitly teach the underlying git commands. I do this by always spewing out the underlying commands in red, and by having the explain command. I’m pretty sure an unsuspecting user would wonder what hit him if a few of the github commands started spewing out red text in his console ;-) Having explain for a few commands (ported from grb) and not for the rest of the github gem’s commands would be weird, too.</p>

<p>There’s also a few other architectural decisions of grb that may not fit with github’s, like having aliases. Once again, grb being a teaching tool, I want to offer a bunch of aliases for forgetful people like me. So far I don’t see anything like aliases in github and I’m not sure how the authors of github-gem would react to a pull request polluting it with a bunch of aliases ;-)</p>

<p>Last but not least, the github gem already has a track command, which conflicts with grb’s. github’s is used to track a new remote repo in your local repo while grb’s is to track another branch from your current remote repo.</p></blockquote>

<p>So git_remote_branch is GitHub-agnostic. You can use it with any Git hosting solution: GitHub, your own <a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">Gitosis</a> / gitweb / <a href="http://gitorious.org/projects/gitorious">Gitorious installation</a>, <a href="http://gitorious.org">Gitorious.org</a> hosting, Rubyforge or any other.</p>

<p>Better, grb supports working with all of them at the same time. All grb commands support an optional origin argument.</p>

<p><a href="http://grb.rubyforge.org">Learn more about git_remote_branch</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git_remote_branch 0.3 - Awesomeness for the masses]]></title>
    <link href="http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses/"/>
    <updated>2008-11-14T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses</id>
    <content type="html"><![CDATA[<h2 id="awesomeness_for_the_masses">Awesomeness for the masses</h2>




<p>git_remote_branch 0.3 has been released!</p>




<p>Previous releases were pretty much only usable by rubyists on OS X. </p>




<p><a title="Works on my machine logo" href="http://www.codinghorror.com/blog/archives/000818.html"><img src="http://www.programblings.com/uploads/2008/06/works-on-my-machine.png" alt="Works on my machine logo" /></a></p>




<p>No more. This release is mostly focused on making sure git_remote_branch works on a broader range of platforms. A few actual features squeaked in, but nothing big like introducing new commands.</p>




<!-- more -->




<p>If you don&#8217;t care about the details just type the following at your command-line.</p>




<pre><code>sudo gem install git_remote_branch
</code></pre>




<p>And check the help</p>




<pre><code>grb --help
</code></pre>




<p>If you encounter installation problems, refer to <a href="http://grb.rubyforge.org">the readme</a>.</p>




<h3 id="platforms">Platforms</h3>




<p>git_remote_branch 0.3 has been tested with the following configurations:</p>




<ul>
<li>OS X Leopard / Ruby 1.8.6 / Git 1.5.4.3 and 1.6.0.2</li>
<li>OS X Leopard / Ruby 1.9.1 / Git 1.5.4.3 and 1.6.0.2</li>
<li>Ubuntu Intrepid Ibex / Ruby 1.8.7 / Git 1.5.6.3</li>
<li>Windows XP / Ruby 1.8.6 / Git 1.6.0.2 (the msys version)</li>
</ul>




<h3 id="features">Features</h3>




<h4 id="better_track">Better track</h4>




<p>Track now works even if you already have a local branch of the same name. It uses git config instead of branch &#8212;track in that case. The subtlety can be observed by running (from a git repository):</p>




<pre><code>grb explain track master
grb explain track non_existent_branch
</code></pre>




<h4 id="force_the_use_of_a_specific_git_executable">Force the use of a specific git executable</h4>




<p>Set the environment variable GRB_GIT to point to it and grb will use this one for all its operations.</p>




<h2 id="documentation_">Documentation </h2>




<p>I&#8217;ve also worked quite a bit on the actual documentation. I used to be ashamed at the quality and availability of the documentation of git_remote_branch. At last I&#8217;ll be able to sleep at night :-)</p>




<h3 id="git_remote_branch_in_a_nutshell">git_remote_branch in a nutshell</h3>




<p>I&#8217;ve rewritten the intro of the readme to be (hopefully) a bit clearer.</p>




<blockquote>
  <p>git_remote_branch is a simple command-line tool that makes it very easy to manipulate branches published in shared repositories.</p>
  
  <p>It achieves this goal by sticking to a few principles:</p>
  <ul>
    <li>keep grb&#8217;s commands extremely regular (they all look alike)</li>
    <li>support aliases for commands</li>
    <li>print all commands it runs on your behalf in red, so you eventually learn them</li>
  </ul>
  <p>Another nice thing about git_remote_branch is that it can simply explain a command (print out all the corresponding git commands) instead of running them on your behalf.</p>
  
  <p>Note: git_remote_branch assumes that the local and 
  remote branches have the same name. Multiple remote 
  repositories (or origins) are supported.</p>
</blockquote>




<h3 id="documentation_availability">Documentation availability</h3>




<p>The main readme is now available on the main <a href="http://grb.rubyforge.org">grb page on rubyforge</a>.</p>




<h3 id="documentation_quality">Documentation quality</h3>




<p>I&#8217;ve added clearer information on getting grb to run in different kinds of situation, due to helpful feedback from <a href="http://github.com/axelson">Axelson</a> and <a href="http://github.com/grempe">Glenn Rempe</a>.</p>




<p>I&#8217;ve also added some information for playing with the code for git_remote_branch (test dependencies and so on). See the end of <a href="http://grb.rubyforge.org">the readme</a>.</p>




<p>Finally, I&#8217;ve updated the links section quite a bit:</p>




<table>
  <tr>
    <th>Documentation</th>
    <td><a href="http://grb.rubyforge.org">http://grb.rubyforge.org</a></td>
  </tr>
  <tr>
    <th>News</th>
    <td><a href="http://www.programblings.com/category/git/git\_remote\_branch/">/category/git/git_remote_branch/</a></td>
  </tr>
  <tr>
    <th>Bug tracker</th>
    <td><a href="http://git-remote-branch.lighthouseapp.com/projects/19198-git\_remote\_branch/overview">Lighthouse</a></td>
  </tr>
  <tr>
    <th>Code</th>
    <td><a href="http://github.com/webmat/git_remote_branch">http://github.com/webmat/git_remote_branch</a></td>
  </tr>
  <tr>
    <th>Mailing list</th>
    <td><a href="http://groups.google.com/group/git_remote_branch">http://groups.google.com/group/git_remote_branch</a></td>
  </tr>
</table>




<h2 id="dare">Dare</h2>




<p>I dare you to find a platform on which git_remote_branch doesn&#8217;t work :-)</p>




<p>If you do, please send me feedback through GitHub or via email. I&#8217;m using gmail and, as usual, I go by the handle of webmat.</p>




<h3 id="last_note_the_git_remote_branch_gem_on_github">Last note: the git_remote_branch gem on GitHub</h3>




<p>Excerpt from the readme:</p>




<blockquote>
  <p>Note that the only stable version of the gem you should trust is the one from <strong>Rubyforge</strong>. The GitHub gem is a development gem. The GitHub gem WILL be rebuilt with the same version number, and other horrible things like that. If you use the GitHub version of git_remote_branch, children will die!</p>
</blockquote>




<p>You&#8217;ve been warned.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing gems with command-line interfaces on Ubuntu 8.10]]></title>
    <link href="http://www.programblings.com/2008/11/04/installing-gems-with-command-line-interfaces-on-ubuntu-810/"/>
    <updated>2008-11-04T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/04/installing-gems-with-command-line-interfaces-on-ubuntu-810</id>
    <content type="html"><![CDATA[<p>To install any ruby gem which has a command-line interface on Ubuntu 8.10, you have to add a path to your PATH environment variable. In your .bashrc file, add the following line:</p>

<pre>export PATH=$PATH:/var/lib/gems/1.8/bin</pre>


<p>Also worth noting is the fact that the default ruby interpreter on 8.10 is back to the 1.8 branch: it&#8217;s 1.8.7 (1.9 was the default on 8.04 iirc). 1.9  also be installed right besides 1.8.</p>

<pre>$ ruby --version
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
$ ruby1.9 --version
ruby 1.9.0 (2008-06-20 revision 17482) [i486-linux]</pre>


<p>Neither comes installed by default, however. You must install them explicitly.</p>

<pre>sudo aptitude install ruby irb rubygems</pre>


<p>While I&#8217;m at it, why not mention that rubygems 1.2.0 is installed by default. It doesn&#8217;t want to update to 1.3.0 with the usual &#8220;gem update &#8211;system&#8221; command. Since it&#8217;s not my main machine I didn&#8217;t investigate further, but the suggestion is to use apt-get or aptitude. The repos don&#8217;t seem to be up to date with 1.3.0, but rather with a version named something like 1.3.0really1.2.0.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Two Shoulda best practices]]></title>
    <link href="http://www.programblings.com/2008/10/31/two-shoulda-best-practices/"/>
    <updated>2008-10-31T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/31/two-shoulda-best-practices</id>
    <content type="html"><![CDATA[<h2 id="in_praise_of_shoulda_macros">In praise of Shoulda macros</h2>


<p>Shoulda contexts let you to share setup code between different tests. This is for me one of Shoulda’s most attractive features.</p>

<p>When you combine this with the technique of defining your own macros to encapsulate assertions or setups that come up often, you end up with seriously DRY and readable tests.</p>

<!-- more -->


<p>I see a few different kinds of Shoulda macros:</p>

<h3 id="assertion_macros">Assertion macros</h3>


<p>Assertions macros often begin with should_. They encapsulate one or a few assertions.</p>

<p>For ActiveRecord models:</p>

<pre><code>should_require_attributes :name, :phone_number
</code></pre>


<p>They may even accept a block and do assertions on its execution, like <a href="http://www.programblings.com/2008/10/27/this-should_raise-an-exception/">should_raise</a>:</p>

<pre><code>should_raise(LoadError, :message =&gt; /vespene/) do
  require "more vespene gas"
end
</code></pre>


<p>To learn more about assertion macros, you can take a look at <a href="http://technicalpickles.com/posts/shoulda-macros-allows-you-to-embrace-your-inner-slacker">Shoulda macros allows you to embrace your inner slacker</a> by Josh Nichols. Inner slacker? I’m right there!</p>

<h3 id="setup_macros">Setup macros</h3>


<p>This kind of macro encapsulates a setup that comes up often in your test suite. One inspired by Restful Authentication’s login_as helper method could be used like this:</p>

<pre><code>logged_in_as :mat do
  # Shoulda tests
end
</code></pre>


<p>These kinds of macros accept a block that defines more Shoulda tests, rather than a block of code testing your app per se.</p>

<h3 id="turnkey_macros">Turnkey macros</h3>


<p>Turnkey macros are beefed up assertion macros. The main difference is their extent. They contain many contexts and a lot of should blocks. They usually accept substantial options hashes or are configured with a setup block. Like should_be_restful in the following example, inspired by the Shoulda documentation:</p>

<pre><code>logged_in_as :stranger do
  should_be_restful do |resource|
    resource.create.params   = { :subject =&gt; "test", :body =&gt; "message" }
    resource.denied.actions  = [:edit, :update, :destroy]
    resource.denied.redirect = "login_url"
    resource.denied.flash    = /only the owner can/i
  end
end
</code></pre>


<h2 id="two_shoulda_best_practices_around_setup_macros">Two Shoulda best practices around setup macros</h2>


<p>This article is specifically about setup macros.</p>

<p>Here’s the implementation of a pretty generic Shoulda macro I could define in my test_helper<a href="#footnote_star">*</a>. This is an implementation of the macro I mentioned at the beginning:</p>

<pre><code># Sets the current person in the session from the person fixtures.
def self.logged_in_as(person, &amp;block)
  context "logged in as #{person}" do
    setup do
      @request.session[:person] = people(person).id
    end

    yield
  end
end
</code></pre>


<p>Which can then be used like this in any controller test:</p>

<pre><code>logged_in_as :mat do
  # tests for users
end

logged_in_as :admin do
  # tests for admin
end
</code></pre>


<p>Setup macros have a very subtle catch, however. Here’s a modified version of the first example above:</p>

<pre><code>logged_in_as :mat do
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>The setup block you see here is never going to be executed. Why?</p>

<p>If we were to replace the logged_in_as macro by the actual code it contains, here’s what it would look like:</p>

<pre><code>context "logged in as #{person}" do
  setup do
    @request.session[:person] = people(person).id
  end
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>Does that make sense? Not so sure.</p>

<p>Shoulda doesn’t like to have multiple setup blocks for a given context. That part <em>does</em> make sense.</p>

<h2 id="best_practice_1_always_describe_the_situation_with_a_context">Best practice #1: Always describe the situation with a context.</h2>


<p>You should always describe the situation in which your test takes place (what your setup is doing) with a context.</p>

<pre><code>logged_in_as :mat do
  context "with last login set to now" do
    setup do
      @request.session[:last_login] = Time.now
    end
    # Some tests
  end
end
</code></pre>


<p>Fair enough. We blame it on the user of the macro :-)</p>

<p>Since we’re using Ruby, most of us are probably in agreement with Matz’ “Make the programmer happy” motto.</p>

<p>So can we also solve the problem from the other end? Create a setup macro that supports a direct inner setup block? Of course we can, this is <strong>Ru</strong>by, not <strong>V</strong>B.</p>

<h2 id="best_practice_2_create_setup_macros_that_support_a_second_setup_block">Best practice #2: Create setup macros that support a second setup block</h2>


<p>A setup is grafted to a context that describes it. As the creator of the macro, I don’t know what crazy setup blocks programmers will put inside their macro. So I simply create a mute context:</p>

<pre><code># Sets the current person in the session from the person fixtures.
def self.logged_in_as(person, &amp;block)
  context "logged in as #{person}" do
    setup do
      @request.session[:person] = people(person).id
    end

    context '' do
      yield
    end
  end
end
</code></pre>


<p>Now my macro supports the following test without a hitch:</p>

<pre><code>logged_in_as :mat do
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>And of course, programmers who stick to best practice #1 can still write a cleaner test without a problem. The awesomeness of contexts lies in the fact that they can be nested:</p>

<pre><code>logged_in_as :mat do
  context "with last login set to now" do
    setup do
      @request.session[:last_login] = Time.now
    end
    # Some tests
  end
end
</code></pre>


<h2 id="conclusion">Conclusion</h2>


<p>Best practice #1 is simple. A setup block should be described by its encompassing context. It’s a question of readability. Nesting a setup block immediately inside a Shoulda macro is a dubious practice.</p>

<p>Best practice #2 is a more pragmatic solution to the problem. Ok, nesting a block right inside a macro isn’t always the best idea.</p>

<p>But when you don’t have the macro right under your nose, it may take you a while before you think about looking at said macro. I don’t know about you, but I have a tendency to have a great deal of confidence in macros that work well across my test suite.</p>

<p>So after you’ve spent an hour questioning Shoulda (or your sanity, or whether you should have become a gardener instead of a software developer) because your setup block isn’t executing, best practice #2 starts to make sense.</p>

<p>It may or may not be necessary in all your setup macros. I find it’s especially useful for macros that are generic enough to be used across your test suite. Or most of all, in setup macros you will share with the world.</p>

<p>Best practice #2 makes setup macros bulletproof to the problem of multiple setups.</p>

<p>Now go refactor your setup macros!</p>

<p>To learn more about Shoulda, check out <a href="http://thoughtbot.com/projects/shoulda">Thoughtbot’s comprehensive documentation</a>.</p>

<p id="footnote_star">* A note on where to define Shoulda macros. Shoulda 2 can now auto load macros that are in the right location. This will help you keep your test_helper cleaner. Read more about it succinctly in <a href="http://technicalpickles.com/posts/shoulda-can-automatically-load-custom-macros">Shoulda can automatically load custom macros</a> by Josh Nichols or in the <a href="http://giantrobots.thoughtbot.com/2008/9/30/shoulda-2-0">Shoulda 2.0 release post</a>.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[This should_raise an exception]]></title>
    <link href="http://www.programblings.com/2008/10/27/this-should_raise-an-exception/"/>
    <updated>2008-10-27T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/27/this-should_raise-an-exception</id>
    <content type="html"><![CDATA[<p>If you use Shoulda and, like me, you hate Test::Unit’s assert_raise(), I may have something of interest for you.</p>

<h2 id="why_the_hate">Why the hate?</h2>


<p>Well, assert_raise accepts an <code>*args</code> list of exception types.</p>

<p>If you don’t pass any, you get some nonsense because an empty array doesn’t jive with the exception raised by your block. Useful. So if you don’t care what exception is raised, assert_raise isn’t gonna help you.</p>

<p>Also, assert_raise doesn’t let you specify what kind of exception message you’re expecting. I actually don’t mind that a given assertion should verify exactly one thing. On the other hand I have to jump through hoops to capture the exception if I want to assert on the error message.</p>

<!-- more -->




<h2 id="a_shoulda_macro_to_the_rescue">A shoulda macro to the rescue</h2>


<p>As usual, Shoulda is there to help us keep our test code DRY and intuitive. I’ve concocted a useful macro called should_raise. <a href="http://gist.github.com/20019">Here’s the gist</a>:</p>

<p>It must be called with the block you expect to raise an exception, of course. You can also specify two optional arguments, the exception type and the message.</p>

<h3 id="kindof_or_instanceof">:kind_of or :instance_of</h3>


<p>If not specified, an assertion is made that an exception was raised, but with no restriction on the type of the exception.</p>

<p>If you specify :kind_of, the assertion will be that much more precise. It will check that the exception raised was of the type specified, or a descendant.</p>

<p>If you specify :instance_of, the assertion is now that the exception raised was <em>exactly</em> of the type specified.</p>

<p>A shorthand is also available, where the type of the exception is supplied directly, like should_raise(LoadError), in which case the assertion is the same as with :instance_of.</p>

<p>In all of these cases, exactly one assertion is generated, whether or not :type is specified.</p>

<h3 id="message">:message</h3>


<p>If :message is specified, a second assertion will be added in order to make sure the error message matches the parameter. This can either be a string or a regex. The assertion is simply an assert_match.</p>

<p>If not specified, no assertion is generated for the message.</p>

<h2 id="examples">Examples</h2>


<pre><code><strong>should_raise do
  require "more vespene gas"
end
# 1 assertion

should_raise(LoadError) do
  require "more vespene gas"
end
# 1 more restrictive assertion

should_raise(:instance_of =&gt; LoadError) do
  require "more vespene gas"
end
# 1 assertion, the same as should_raise(LoadError)

should_raise(:kind_of =&gt; ScriptError) do
  require "more vespene gas"
end
# 1 assertion, slightly less strict than with :instance_of (note: LoadError &lt; ScriptError)

should_raise(:message =&gt; "no such file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:message =&gt; /vespene/) do
  require "more vespene gas"
end
# 2 assertions

should_raise(LoadError, :message =&gt; "such file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:kind_of =&gt; LoadError, :message =&gt; "file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:instance_of =&gt; LoadError, :message =&gt; "to load") do
  require "more vespene gas"
end
# 2 assertions
</strong></code></pre>


<h2 id="conclusion">Conclusion</h2>


<p>As you can tell, I’m eagerly awaiting <a href="http://www.starcraft2.com/">Starcraft II</a>.</p>

<p>No, I meant: check out the code on <a href="http://gist.github.com/20019">gist 20019</a>. I’ve included a reasonable suite of unit tests in a comment at the end.</p>

<p>Feel free to use it in any way you like. Just make sure you don’t sue me.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git global ignores]]></title>
    <link href="http://www.programblings.com/2008/10/22/git-global-ignores/"/>
    <updated>2008-10-22T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/22/git-global-ignores</id>
    <content type="html"><![CDATA[<p>I don’t know about you, but for me, using git is so low-friction that I use it basically for everything where I may need a powerful undo button. In other words, I don’t use it only for team software development projects.</p>

<p>For example, I’ve frequently used it in the past to keep track of the modifications I make to an article I work on for few days. God knows <a href="http://www.programblings.com/2008/04/01/rubinius-for-the-layman-part-1-rubies-all-the-way-down/">I</a> <a href="http://www.programblings.com/2008/04/15/rubinius-for-the-layman-part-2-how-rubinius-is-friendly/">write</a> <a href="http://www.programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git/">a</a> <a href="http://www.programblings.com/2008/06/23/git-remote-branches/">lot</a> <a href="http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git/">of</a> <a href="http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch/">these</a>. There’s a reason I called this blog Prog<strong>ramblings</strong> ;-)</p>

<p>To be honest, I’m using git as I write even this short article.</p>

<!-- more -->


<p>I also use it for trivial one evening coding projects. As soon as I spend more than an hour on code, whatever it is, I’ll usually create a local git repo for it.</p>

<p>One of the annoying things I realized when creating repositories more and more often, is that I always ended up ignoring the same files. Over and over again. Boring.</p>

<p>Fortunately for me, git can be configured to take into consideration a global ignore file. Heck, I can even create a system-wide ignore file if I want (check out git config’s doc for more info).</p>

<h2 id="configure_your_personal_ignore_file">Configure your personal ignore file</h2>


<p>I like to stick to conventions so I call my file .gitignore, and I put it in my home directory. But that’s up to you, really.</p>

<pre><code>git config --global core.excludesfile ~/.gitignore
</code></pre>


<p>Note that there’s one little gotcha to be aware of. If you prefer to edit the .gitconfig file directly (or if you use a weird shell), git expects an absolute path. In the example above, bash converted the ~ shorthand to my home directory.</p>

<p>Now I just add ignore globs to it like any other project level (directory level, really) git ignore file.</p>

<pre><code>echo .DS_Store &gt;&gt; ~/.gitignore
</code></pre>


<p id="you8217ll_still_have_to_ignore">Once I&#8217;ve ignored all my favorite useless files, I can get cracking and never worry about them again.</p>




<h2>I still have to ignore files</h2>


<p>When I create a new repository on which people may actually contribute, I’ll still create a proper ignore file, however. Otherwise I’d convey the message that I consider contributors as slaves who only deserve the boring work of creating ignore files. Since I’m pure of heart, that’s not how I roll.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Discovering great tools - qgit]]></title>
    <link href="http://www.programblings.com/2008/09/19/discovering-great-tools-qgit/"/>
    <updated>2008-09-19T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/09/19/discovering-great-tools-qgit</id>
    <content type="html"><![CDATA[<p>I can&#8217;t believe I hadn&#8217;t taken the time to try out <a href="http://digilander.libero.it/mcostalba/">qgit</a> yet. Check this out:</p>

<figure style="text-align:center">
  <a href="http://www.programblings.com/uploads/2008/09/qgit.png"><img  style="width:500px; height:358px;"
    title="qgit" src="http://www.programblings.com/uploads/2008/09/qgit.png" alt="Screenshot of the main qgit screen"/></a>
  <p>Screenshot of the main qgit screen</p>
</figure>


<p>Install qgit from source on Leopard with <a href="http://rails.wincent.com/wiki/Installing_QGit_2.0rc1_on_Mac_OS_X_Tiger">these instructions</a>.</p>

<p>Warning: installing the Qt 4.3 prerequisite takes an eternity or two (instructions for that are included as well).</p>

<p>Also note that you should make sure to use the newest versions of the downloads: the instructions point to an old 2.0rc1 release of qgit.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Time to git collaborating with git_remote_branch]]></title>
    <link href="http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch/"/>
    <updated>2008-08-06T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch</id>
    <content type="html"><![CDATA[<h2>git_remote_branch 0.2.6 is out!</h2>


<p>I&#8217;ve just released a new and improved version of git_remote_branch. Code named 0.2.6!</p>

<p>Ok, I admit. I haven&#8217;t really begun using code names.</p>

<p>I&#8217;m promoting the project from a pre-alpha to an alpha release. There&#8217;s still a lot to do, but the stability and &#8220;testedness&#8221; have improved greatly. Following are both sides of the maturity story.</p>

<!-- more -->




<h3>The project is maturing</h3>


<ul>
    <li>grb got its first contributor, <a href="http://github.com/kch">Caio Chassot</a></li>
    <li>I added a lot of tests, both unit and functional
<ul>
    <li> there might even be <a href="http://github.com/webmat/git_remote_branch/tree/master/test/helpers/shoulda_functional_helpers.rb#L40">interesting</a> <a href="http://github.com/webmat/git_remote_branch/tree/master/vendor/capture_fu.rb">stuff</a> to see in there for those who need to test command-line tools</li>
</ul>
</li>
    <li> the gem can now be installed directly from RubyForge</li>
    <li> git_remote_branch now has a <a href="http://groups.google.com/group/git_remote_branch">Google Group</a></li>
</ul>


<h3>The project is still immature</h3>


<ul>
    <li>it swears a lot</li>
    <li>no rubyforge page, despite the project being on rubyforge (at <a href="http://rubyforge.org/projects/grb/">rubyforge.org/projects/grb</a>)</li>
    <li>no real documentation other than running grb help</li>
    <li>very little in code documentation. On the other hand the code is spectacularly clean and readable, so that&#8217;s completely unnecessary. Just kidding.</li>
</ul>


<h3>What&#8217;s new in 0.2.6?</h3>


<p>Three new actual features</p>

<ul>
    <li>the &#8216;rename&#8217; command, contributed by Caio Chassot</li>
    <li>the &#8216;publish&#8217; command</li>
    <li>the −−silent option to completely mute grb output as well as every git command run by grb on your behalf</li>
</ul>


<p>And other stuff</p>

<ul>
    <li>the grb bin file now works when symlinked (also thanks to Caio Chassot)</li>
    <li>lots of unit and functional tests</li>
    <li>bug fixes</li>
    <li>more flexibility for running grb outside of a git repository (e.g. for &#8216;explain&#8217; or &#8216;help&#8217;)</li>
    <li>now officially under the MIT license</li>
    <li>refactored a bunch of rake tasks</li>
</ul>


<h2>Git the new version</h2>


<p>To install the newest version of the gem, simply run</p>

<pre><strong>sudo gem install git_remote_branch</strong></pre>


<p>If you really want to be on the bleeding edge you can also get it on GitHub. Note however that in &#8216;bleeding edge&#8217; the word &#8216;bleeding&#8217; is still the most important one at that point.</p>

<pre><strong>git clone git://github.com/webmat/git_remote_branch.git
cd git_remote_branch
rake install</strong></pre>


<p>The &#8216;install&#8217; task will run the tests before installing so you&#8217;ll need Shoulda, mocha, redgreen and ruby-debug for that approach.</p>

<h2>Not familiar with git_remote_branch?</h2>


<h3>What it is</h3>


<p>The basic idea for git_remote_branch is to trivialize the interaction with remote branches. The first goal is to make the commands for the simple situations easy.</p>

<p>The secondary goal, is to help you learn the commands by seeing them displayed in a beautiful shade of red each time you use grb, along with git&#8217;s output.</p>

<p>git_remote_branch lets you</p>

<ul>
    <li><strong>create</strong> local-remote branche pairs, and tracks the remote branch automatically (for automatic merges when you git pull)</li>
    <li><strong>publish</strong> a local branch as a remote branch, very similar to create</li>
    <li><strong>delete</strong> local-remote branch pairs</li>
    <li><strong>track</strong> a remote-only branch</li>
    <li><strong>rename</strong> a local-remote branch pair</li>
    <li><strong>explain</strong> by simply spitting out the necessary commands to do any of the above</li>
</ul>


<h3>How to use it</h3>


<h4>explain</h4>


<p>If you simply want to use grb as a cheatsheet (and run nothing on your behalf), you can use the explain command:</p>

<pre><strong>$ grb explain create
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push origin current_branch:refs/heads/branch_to_create
git fetch origin
git branch −−track branch_to_create origin/branch_to_create
git checkout branch_to_create</span></strong></pre>


<p>or</p>

<pre><strong>$ grb explain create my_branch my_origin
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push my_origin current_branch:refs/heads/my_branch
git fetch my_origin
git branch −−track my_branch my_origin/my_branch
git checkout my_branch</span></strong></pre>


<p>Notice that you can specify any normally expected parameter you&#8217;d normally include and &#8216;explain&#8217; will use them in the list of commands it suggests.</p>

<p>Even better, if you&#8217;re in your repository, the current branch is going to be taken into account:</p>

<pre><strong>(master) $ grb explain create my_branch my_origin
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push my_origin master:refs/heads/my_branch
git fetch my_origin
git branch −−track my_branch my_origin/my_branch
git checkout my_branch</span></strong></pre>


<p>Of course, &#8216;explain&#8217; works for all commands: create, publish, delete, track and rename.</p>

<h4>The main commands</h4>


<p>I&#8217;m not going to painstakingly give an example for each command. I&#8217;ll only give two, to show how git&#8217;s responses are displayed when running grb without &#8216;explain&#8217;:</p>

<pre><strong>(master)$ grb create test_branch
git_remote_branch version 0.2.6

<span style="color: #ff0000;">git push origin master:refs/heads/test_branch</span>
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:webmat/git_remote_branch.git
 * [new branch]      master -&gt; test_branch

<span style="color: #ff0000;">git fetch origin</span>

<span style="color: #ff0000;">git branch −−track test_branch origin/test_branch</span>

<span style="color: #ff0000;">git checkout test_branch</span>
Switched to branch "test_branch"

(test_branch)$ grb delete test_branch
git_remote_branch version 0.2.6

<span style="color: #ff0000;">git push origin :refs/heads/test_branch</span>
To git@github.com:webmat/git_remote_branch.git
 - [deleted]         test_branch

<span style="color: #ff0000;">git checkout master</span>
Switched to branch "master"

<span style="color: #ff0000;">git branch -d test_branch</span>

(master) $ </strong></pre>


<p>Yes my friends, I have just boldly used grb on my real repository for your viewing pleasure.</p>

<p>But worry not, no repository was hurt during the writing of this article.</p>

<h2>Feedback</h2>


<p>For any feedback you&#8217;re of course welcome to</p>

<ul>
    <li>comment on this article</li>
    <li>post in <a href="http://groups.google.com/group/git_remote_branch">the google group</a></li>
</ul>


<h2>Thanks</h2>


<ul>
    <li>To Caio Chassot for the code contribution</li>
    <li> To the Thin team for a good inspiration on how to help manage gem creation and deployment with rake;</li>
    <li> Feedback from <a href="http://jamesgolick.com">James Golick</a> in day to day collaboration as well as all the people that commented on the <a href="http://www.programblings.com/2008/06/23/git-remote-branches/">initial announcement of git_remote_branch</a>;</li>
    <li> To Chris Wanstrath (defunkt) from the GitHub team for <a href="http://github.com/blog/98-git-remote-branch">pimping of the initial announcement</a> of grb on the GitHub blog.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Setting up a long term fork with Git]]></title>
    <link href="http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git/"/>
    <updated>2008-07-21T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git</id>
    <content type="html"><![CDATA[<h2>The context</h2>


<p>Recently at GiraffeSoft we started a new project, based on another existing project we already had going. We could call this a long term fork. Let me give you a little bit more context on the situation.</p>

<ul>
    <li>These projects will both keep being actively developed in the future;</li>
    <li>They will have some fundamental differences that will not be reconciled;</li>
    <li>They will however keep many similarities and we expect that they will benefit from the exchange of some specific patches, as development on both moves forward.</li>
</ul>


<p>In days past, this problem could have been solved reasonably well by cloning the central repository and then exchanging patches and applying them manually.</p>

<p>As you&#8217;ve guessed already, we&#8217;ve decided to try using Git to help manage this long term relationship.</p>

<!-- more -->


<p>I must warn you however. It&#8217;s the first time we attempt keeping a long term fork like that. We&#8217;re not sure whether it&#8217;s going to be worth the trouble and whether the diverging of the two projects will eventually prevent us from efficiently benefiting from using Git to manage the exchange of patches. We&#8217;re not sure whether this is the best way to accomplish this either.</p>

<p>On one hand, all this trouble may or may not be worth the effort. On the other hand, all of this sounds like ultra elite Git-fu. Hence our decision to explore this approach.</p>

<p>Another less technical reasons was also at play in our decision. We wanted to have one wiki per project on GitHub :-)</p>

<h2>What we&#8217;re going to do</h2>


<p>So at first, we have a remote repository for the initial project. There are of course an arbitrary number of client side clones of the repository (what Subversion calls working directories). None of them will be affected in any way.</p>

<p>The first thing I will do is clone the initial project to a new client side repository. I&#8217;ll set this up in such a way that it won&#8217;t use the initial project as its default origin. On the other hand I&#8217;ll make sure it has one branch that interacts with the initial project for future patch exchanges.</p>

<p>Then from that client-side repository, I&#8217;ll initialize a new remote repository, which will serve as the default remote repository for the new project.</p>

<p>What we&#8217;ll end up with is 2 remote repositories which will have a lot in common but won&#8217;t be linked to one another in any way. It won&#8217;t be a GitHub fork, for instance.</p>

<p>There will be exactly one client side repository that knows about the two central repos and that can exchange commits between them. All other new client-side clones of the new project will be plain old regular Git clones.</p>

<p>It would be easy to set up more client side repositories to be aware of both repositories, but to me it doesn&#8217;t really seem necessary.</p>

<h3>Article too long?</h3>


<p>As with my previous articles about Git, I&#8217;ll provide detailed instructions for you to follow along on dummy repositories (if you&#8217;re interested). When you return to this article to attempt something similar, you may want to skip to the <a href="#executive-summary">executive summary</a> section, where I list strictly the important operations without all the rambling.</p>

<h2>The instructions with the rambling</h2>


<h3>Setting up a dummy initial project</h3>


<p>Find yourself a comfortable directory and run these few commands to initiate a dummy client-side repository and its corresponding dummy remote:</p>

<pre><strong>mkdir test; cd $_
mkdir initial_project initial_wd
GIT_DIR=initial_project/ git init

# Creating a dummy repo
cd initial_wd
git init
echo foo &gt; file.txt
git add .
git commit -a -m "initial commit"
echo bar &gt;&gt; file.txt
git commit -a -m "modification"

# Setting up what's gonna be the central repo for our initial app
git remote add origin ../initial_project/
git push origin master

git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<p>The last 2 config commands configure your master branch to automatically track remote master when issuing the command &#8216;git pull&#8217;. In other words, it&#8217;s equivalent to running the command &#8216;git branch −−track master origin/master&#8217;, with the only difference being that &#8216;branch −−track&#8217; is primarily intended to create a new local branch, whereas here we already have our local branch.</p>

<p>We can now check for the expected behavior:</p>

<pre><strong>#   mat@mm initial_wd (master)$ git pull
#   Already up-to-date.</strong></pre>


<p>Note also that here I simplify the instructions for following along by creating a dummy remote repository that&#8217;s in fact only in another local directory. If for example you wanted to use GitHub, your Git remote command would simply look like:</p>

<pre><strong>git remote add origin git@github.com:username/initial_project.git</strong></pre>


<h3>The actual fork</h3>


<pre><strong># Create a directory to host the new remote repository
cd ..
mkdir project2
GIT_DIR=project2/ git init</strong></pre>


<p>Now we will use Git clone with the -o option. This lets us give the initial project another name than the default &#8216;origin&#8217;. We&#8217;ll want to use the name &#8216;origin&#8217; for the new repository we&#8217;ll create to actually track the new project. I decided to name it the initial project&#8217;s origin &#8216;ip_origin&#8217;.</p>

<pre><strong># Specify origin name, then the path to the shared repo
# and finally a directory name for the local working directory.
git clone -o ip_origin initial_project wd</strong></pre>


<h4>Setting up the relationship with the initial repository</h4>


<p>We first create a branch specifically to track the initial project&#8217;s master branch. Then we set it up to track the initial project.</p>

<pre><strong>cd wd
git branch ip_master
git config branch.ip_master.remote ip_origin
git config branch.ip_master.merge refs/heads/master</strong></pre>


<h4>Setting up the relationship with the new project&#8217;s repository</h4>


<pre><strong>git remote add origin ../project2
git push origin master

git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<h4>Let&#8217;s pretend some new development happened</h4>


<pre><strong>echo 'shareable modification' &gt; shareable_file.txt
git add shareable_file.txt
git commit -m "shareable modification"

echo "specific to new project" &gt; not_shareable.txt
git add not_shareable.txt
git commit -m "specific to new project"</strong></pre>


<p>So I have now begun working on the new project and I already have one commit that could benefit the initial project as well. The progress looks a little like this:</p>

<p><img src="http://www.programblings.com/uploads/2008/07/ltf-gitk-new-development.png" alt="A look at gitk’s representation of the new development" height="61" width="468" /></p>

<p>So I switch to the branch that manages the relationship with the initial project and I pick the commit before the last one in master.</p>

<pre><strong>git checkout ip_master
git cherry-pick master^</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/07/ltf-gitk-common-modification-now-in-ip_master.png" alt="Gitk, after cherry-picking one commit" height="71" width="396" /></p>

<p>Everything&#8217;s dandy so far, except for the subtle fact that I have brought us all to the edge of a cliff.</p>

<p>If I tried to push to the initial repository right now, I&#8217;d be in for a nasty surprise:</p>

<pre><strong>#   mat@mm wd (ip_master)$ git push
#   Counting objects: 7, done.
#   Compressing objects: 100% (4/4), done.
#   Writing objects: 100% (6/6), 564 bytes, done.
#   Total 6 (delta 1), reused 0 (delta 0)
#   Unpacking objects: 100% (6/6), done.
#   To /Users/mat/blog/long-term-fork/test/initial_project
#      7178a89..3ca0240  <font color="#ff0000">master</font> <font color="#6666ff">-&gt; master</font></strong></pre>


<p>Oops! By default, &#8216;git push&#8217; syncs up all branches of the same name with the current branch&#8217;s origin. So that would push the <em>new project</em>&#8217;s master branch on our <em>initial</em> project&#8217;s shared master.</p>

<p>This is obviously not what we want. We only want ip_master to be pushed to the initial project&#8217;s master.</p>

<p>Trying to remember to always explicitly run &#8216;git push ip_origin ip_master:master&#8217; wouldn&#8217;t do it for me. To keep the analogy, that would be akin to doing a cartwheel on the edge of said cliff: a lot of fun until you make a mistake. So obviously we&#8217;d like a simple &#8216;git push&#8217; to do the right thing.</p>

<p>So here&#8217;s how we configure it:</p>

<pre><strong>git config remote.ip_origin.push refs/heads/ip_master:master</strong></pre>


<p>Now we can safely issue the &#8216;git push&#8217; command from ip_master and have Git push ip_master to ip_origin/master.</p>

<pre><strong>git push
#   Counting objects: 4, done.
#   Compressing objects: 100% (2/2), done.
#   Writing objects: 100% (3/3), 310 bytes, done.
#   Total 3 (delta 0), reused 0 (delta 0)
#   Unpacking objects: 100% (3/3), done.
#   To /Users/mat/blog/long-term-fork/test/initial_project
#      027a48f..9db6c3f  <font color="#6666ff">ip_master -&gt; master</font></strong></pre>


<p>There&#8217;s now only one remaining annoyance we&#8217;re not yet protected against. If new branches are created in the initial project&#8217;s central repository, a &#8216;git pull&#8217; when standing in the ip_master branch would pull them all in our new project&#8217;s working directory. I consider this one only an annoyance, since I could just decide not to pay attention to them. On the other hand they will be distracting and may also clash with the branches I create for the development on my new project. So we want to avoid that behavior as well.</p>

<p>To better understand the current Git configuration, let&#8217;s have a look at .git/config:</p>

<pre><strong>  ...
  [remote "ip_origin"]
    url = /Users/mat/blog/long-term-fork/test/initial_project
    <font color="#6666ff">fetch = +refs/heads/*:refs/remotes/ip_origin/*</font>
  [branch "master"]
    remote = origin
    merge = refs/heads/master
  [branch "ip_master"]
    remote = ip_origin
    merge = refs/heads/master
  [remote "origin"]
    url = ../project2
    <font color="#6666ff">fetch = +refs/heads/*:refs/remotes/origin/*</font></strong></pre>


<p>So in both &#8216;remote&#8217; sections I can see that fetch is configured to bring everything locally (the * wildcards).</p>

<p>So here&#8217;s how I limit what gets pulled when I pull from the initial project&#8217;s repository.</p>

<pre><strong>git config remote.ip_origin.fetch +refs/heads/master:refs/remotes/ip_origin/master</strong></pre>


<p>The part before the colon is the name of the interesting branch on the remote server. The part after the colon is your local Git repo&#8217;s internal branch, used to track the remote branch (not to be confused with our user branch ip_master).</p>

<p>Setting up remote branches on both projects, pulling, pushing and exchanging more commits is left as an exercise to the reader.</p>

<h2>Conclusion</h2>


<p>So that&#8217;s the gist of it, my friends. I am basically set up to work on my new project like I would in a more typical situation. I also have a special branch set up to interact with the initial project. With this branch I&#8217;ll be able to do two things:</p>

<ul>
    <li>Pull new developments from the initial project and then cherry-pick only the shareable commits into the new project&#8217;s other branches.</li>
    <li>Cherry-pick in the other direction to bring certain commits from the new project into this branch and then push them up to the initial project.</li>
</ul>


<p>For this approach to be useful however, we&#8217;ll have to make sure we create as concise commits as possible. Gone are the days of committing a whole afternoon in one meaningless commit containing 12 different modifications.</p>

<p>Of course coding sprees of a couple hours are not out of the question. Features like &#8216;git add −−patch&#8217; are a great help when comes time to extract meaningful commits out of the result of a few hours of intense coding. For a good introduction to −−patch (and a few other powerful features), be sure to read Ryan Tomayko&#8217;s <a href="http://tomayko.com/writings/the-thing-about-git">The Thing about Git</a>.</p>

<h2 id="executive-summary">The executive summary</h2>


<p>So let&#8217;s reiterate strictly the interesting bits necessary to set up a long term fork when starting a new project from an existing one.</p>

<p>We already have:</p>

<ul>
    <li>the initial project&#8217;s repository at url git@github.com:username/initial_project.git</li>
    <li>the new project&#8217;s empty repository, also created at git@github.com:username/new_project.git</li>
</ul>


<pre><strong># Create new local clone for the new project
git clone -o ip_origin git@github.com:username/initial_project.git new_project
cd new_project

# Set up a standard track between initial master and local ip_master
git config branch.ip_master.remote ip_origin
git config branch.ip_master.merge refs/heads/master

# Automatically push the right branch
<font color="#6666ff">git config remote.ip_origin.push refs/heads/ip_master:master</font>
# Don't bring in the other shared branches from initial project
<font color="#6666ff">git config remote.ip_origin.fetch +refs/heads/master:refs/remotes/ip_origin/master</font>

# Push new local repo it to new shared repo
git remote add origin git@github.com:username/new_project.git
git push origin master

# Configure standard track of master with new local repo
git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<p>That&#8217;s it! We now only have to cherry-pick like there&#8217;s no tomorrow.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to load gems only when your tests are not run from TextMate]]></title>
    <link href="http://www.programblings.com/2008/07/10/how-to-load-gems-only-when-your-tests-are-not-run-from-textmate/"/>
    <updated>2008-07-10T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/07/10/how-to-load-gems-only-when-your-tests-are-not-run-from-textmate</id>
    <content type="html"><![CDATA[<p>Working with new people often influences the way you work. The influences can range from picking up simple tricks to seeing fundamental facts about your craft in a new light.This week when <a href="http://jamesgolick.com/2008/7/7/mat-martin-joins-giraffesoft">I began working with James</a> I saw him run his tests directly from TextMate. Of course I knew it was possible to run Ruby from TM, including tests.For some inexplicable reason however I had never bothered to try it. This trick is very convenient for two reasons: TextMate cleans up the backtraces and resolves each level of the trace to a clickable link to your code file. So I decided to include this trick in my workflow.I encountered two problems with this however. Two gems I usually use in my tests don&#8217;t play well with running tests from TextMate.</p>

<!-- more -->




<h2>redgreen</h2>


<p>The redgreen gem highlights the <font color="#008000"><strong>.</strong></font> <strong><font color="#ff0000">F</font></strong> and <font color="#ff9900"><strong>E</strong></font> (among other bits) in your test runs with green, red and yellow. When running my whole test suite it&#8217;s something I want to have. It&#8217;s not only visually pleasing, but it also lets me see at a glance whether any problems were encountered.When run from TextMate, tests using redgreen are displayed without having the console coloring stripped out, which gives something like this:</p>

<p>
<img src="http://www.programblings.com/uploads/2008/07/tests_with_redgreen_in_tm.png" alt="The result of running tests from TextMate, when using redgreen" height="223" width="564" />
</p>


<p>Riiiight.For the record, here&#8217;s the nice result when run at the console:</p>

<p><img src="http://www.programblings.com/uploads/2008/07/tests_with_redgreen_in_console.png" alt="Running tests with redgreen, from the console" height="208" width="409" /></p>


<h2>quietbacktrace</h2>


<p>The other gem I can&#8217;t do without is James Golick and Dan Croak&#8217;s <a href="http://jamesgolick.com/2007/12/3/noisy-backtraces-got-you-down">quietbacktrace</a>. This gem lets you specify filters and silencers to clean up those huuuuuge Rails or Merb backtraces.Filters let you remove useless parts of a given line in the backtrace, such as the path leading to your gems. Silencers let you completely remove some lines from the backtrace, such as all the lines referring to what happened inside Rails, leading to your error. The most popular filters and silencers are already provided with quietbacktrace, as you&#8217;ll see below.So the result, of course is that messing with backtraces breaks TextMate&#8217;s ability to link a backtrace line with the corresponding file.</p>

<h2>A simple snippet to fix this</h2>


<p>Since I didn&#8217;t really want to do away with these tools, I included a bit of a hacky snippet in my test_helper.rb file to detect whether a test run was happening in TextMate or at the console.If you find yourself in the same fix as me, feel free to use the following.Among your requires:</p>

<pre><strong>IN_TM = !ENV['TM_DIRECTORY'].nil?
unless IN_TM
  require 'redgreen'
  require 'quietbacktrace'end</strong></pre>


<p>And then:</p>

<pre><strong>class Test::Unit::TestCase
  unless IN_TM
    self.backtrace_silencers &lt;&lt; :rails_vendor
    self.backtrace_filters   &lt;&lt; :rails_root
  end
  #...
end</strong></pre>


<p>Now I can have my testing niceties when running my tests from the console and they don&#8217;t break the TextMate integration :-)</p>

<h2> Trying this out for the first time?</h2>


<p>If like me you just decided to try this out for the first time, the shortcuts are easy to remember. Command-R runs any Ruby file (in this case, the whole test file) and Command-Shift-R runs the single test the cursor is in.There&#8217;s a little hiccup in sight, however. If you&#8217;re using Rails 2+, you have to apply a very small fix to TextMate before you&#8217;ll be able to run your tests. Read more about the fix on <a href="http://macournoyer.wordpress.com/2007/12/15/getting-textmate-ready-for-rails-20/">Marc-André Cournoyer&#8217;s blog</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GiraffeSoft.push( Karabunga.pop( self ))]]></title>
    <link href="http://www.programblings.com/2008/07/07/giraffesoft-push-karabunga-pop-self/"/>
    <updated>2008-07-07T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/07/07/giraffesoft-push-karabunga-pop-self</id>
    <content type="html"><![CDATA[<p>A wise man once suggested that one of the steps in teaching yourself programming involved working with people better than you. (See <a href="http://norvig.com/21-days.html">Teach Yourself Programming in Ten Years</a>)</p>

<p>Even though I feel I&#8217;m a pretty competent software developer, I&#8217;m very excited to join another developer for which I have a truly profound respect. I&#8217;ve only recently made the career move of working on the web full time, and this is a great opportunity for me to kickstart this phase of my career by working with a Rails /  REST / jQuery guru.</p>

<p>Starting today, I&#8217;m working for <a href="http://giraffesoft.ca/">GiraffeSoft</a>, with <a href="http://jamesgolick.com/">James Golick</a>. We&#8217;ve wanted to work together for a while, and the stars have finally aligned to <a href="http://jamesgolick.com/2008/7/7/mat-martin-joins-giraffesoft">make this possible</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git remote branches]]></title>
    <link href="http://www.programblings.com/2008/06/23/git-remote-branches/"/>
    <updated>2008-06-23T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/06/23/git-remote-branches</id>
    <content type="html"><![CDATA[<p>I&#8217;m ready to bet that setting up and deleting remote branches is something you do rarely enough that you always find yourself looking up the documentation. Or maybe it&#8217;s just me.</p>

<p>Due to its roots, Git supports a wide array of usage scenarios for interacting with remote repositories, and we love it that way. It&#8217;s a big factor in the flexibility and power of the tool.</p>

<p>However in simple scenarios, there&#8217;s still a bunch of commands you must run to accomplish simple tasks. I believe the commands for the simple scenario can be simpler.</p>

<p>Last January, <a href="http://blog.carlmercier.com/2008/01/25/no-nonsense-git-part-1-git-remote-branch/">Carl Mercier created git-remote-branch</a>. I&#8217;ve found this script very useful and, with his permission, I&#8217;ve decided to keep moving it forward and add a few features to it.</p>

<!-- more -->




<h2>git_remote_branch</h2>


<p>The first purpose of git_remote_branch is to encapsulate all the commands that need to be run to interact with remote branches in simple scenarios.</p>

<p>Its second purpose is to be a learning tool. git_remote_branch does two things to help you learn these commands:</p>

<ul>
    <li> It clearly displays the commands it runs on your behalf, in a beautiful shade of red;</li>
    <li> It has an &#8216;explain&#8217; meta-command that will simply display the list of commands instead of running them for you.</li>
</ul>


<h3>Examples</h3>


<h4>Help</h4>


<p>Let&#8217;s start with the simplest of all:</p>

<pre><strong>$ grb</strong></pre>


<p>or</p>

<pre><strong>$ grb help
git_remote_branch version 0.2.2

  Usage:

  grb create branch_name [origin_server]

  grb delete branch_name [origin_server]

  grb track branch_name [origin_server]

  If origin_server is not specified, the name 'origin' is assumed (git's default)

  The explain meta-command: you can also prepend any command with the keyword 'explain'.
  Instead of executing the command, git_remote_branch will simply output the list of commands
  you need to run to accomplish that goal.
  Example:
    grb explain create
    grb explain create my_branch github

  All commands also have aliases:
  create: create, new
  delete: delete, destroy, kill, remove
  track: track, follow, grab, fetch</strong></pre>


<p>As you can see, the syntax for all commands is very regular: action, branch_name and optionally, origin_server.</p>

<p>To facilitate learning even more, aliases are also provided. So to take an example,</p>

<pre><strong>$ grb track his_branch</strong></pre>


<p>and</p>

<pre><strong>$ grb fetch his_branch</strong></pre>


<p>are perfectly equivalent.</p>

<h4>create</h4>


<p>Create lets you create a new branch both remotely and locally. Note that it&#8217;s not made to share an existing branch (that feature&#8217;s coming).</p>

<p>So what it does is to push your current branch as a new remote branch, then create it locally and track it, for easier pulling afterwards.</p>

<pre><strong>$ grb create some_branch
git_remote_branch version 0.2.2

<span style="color: #ff0000;">git push origin master:refs/heads/some_branch</span>
Total 0 (delta 0), reused 0 (delta 0)
To /path/to/repo/
* [new branch]      master -&gt; some_branch

<span style="color: #ff0000;">git fetch origin</span>

<span style="color: #ff0000;">git branch −−track some_branch origin/some_branch</span>

<span style="color: #ff0000;">git checkout some_branch</span>
Switched to branch "some_branch"</strong></pre>


<h4>delete</h4>


<p>Presenting features with names that are too self-evident is boring. Let&#8217;s get to the point, already.</p>

<pre><strong>$ grb delete some_branch
git_remote_branch version 0.2.2

<span style="color: #ff0000;">git push origin :refs/heads/some_branch</span>
To /path/to/repo/
- [deleted]         some_branch

<span style="color: #ff0000;">git checkout master</span>
Switched to branch "master"

<span style="color: #ff0000;">git branch -d some_branch</span></strong></pre>


<h4>track</h4>


<p>Track lets you easily track the changes that are made to an existing remote branch you&#8217;re not tracking already. Each time you pull from the remote repository, the local branch will be automatically merged with the remote branch.</p>

<pre><strong>$ grb track his_branch
git_remote_branch version 0.2.2

<span style="color: #ff0000;">git fetch origin</span>
From /path/to/repo/
* [new branch]      his_branch -&gt; origin/his_branch

<span style="color: #ff0000;">git branch −−track his_branch origin/his_branch</span></strong></pre>


<h4>explain</h4>


<p>Explain will spew out all commands necessary to accomplish one of the previous actions. There are two ways of using it. The simplest will give you dummy commands:</p>

<pre><strong>$ grb explain create
git_remote_branch version 0.2.2

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push origin master:refs/heads/branch_to_create
git fetch origin
git branch −−track branch_to_create origin/branch_to_create
git checkout branch_to_create</span></strong></pre>


<p>Or you can have steps that are tailor-made for what you want to accomplish.</p>

<pre><strong>$ grb explain create my_branch github_origin
git_remote_branch version 0.2.2

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push github_origin master:refs/heads/my_branch
git fetch github_origin
git branch −−track my_branch github_origin/my_branch
git checkout my_branch</span></strong></pre>


<h3>get git_remote_branch</h3>


<p>(Hey, this title has a nice ring to it)</p>

<pre><strong>sudo gem install webmat-git_remote_branch −−source=http://gems.github.com</strong></pre>


<p>Now with rubygems 1.2.0 out (don&#8217;t do it with a prior version), you can also add GitHub as a permanent source for your gems:</p>

<pre><strong>sudo gem sources -a </strong><strong>http://gems.github.com</strong></pre>


<p>Now and ever after, you will be able to get anything from GitHub with a simple</p>

<pre><strong>sudo gem install webmat-git_remote_branch</strong></pre>


<p>If in your eagerness you&#8217;ve added github as a source before running</p>

<pre><strong>sudo gem update −−system</strong></pre>


<p>Please refer to <a href="http://chalain.livejournal.com/71260.html">What to do when gems.github.com breaks gems FOREVAR</a></p>

<h3>Look ma, no tests!</h3>


<p>Uhhhh, yeah, I know&#8230;</p>

<p>This tool is still extremely early in its life and - dare I say it - it&#8217;s only hand-tested for now. I&#8217;ve been using it personally for a while and it&#8217;s working very well for me, if that means anything :-)</p>

<p>So this is still a quick script, only now it has lipstick.</p>

<p><a title="Works on my machine logo" href="http://www.codinghorror.com/blog/archives/000818.html"><img src="http://www.programblings.com/uploads/2008/06/works-on-my-machine.png" alt="Works on my machine logo" /></a></p>

<p>This software should be considered an early version of a pre-alpha. You&#8217;ve been warned!</p>

<p>If this makes you queasy, there&#8217;s always the &#8216;explain&#8217; command that can act as your cheat sheet without actually having grb run the commands on your behalf.</p>

<p>For the extra queasy, well you can find the commands very easily without running grb. Just point your favorite editor to lib/git_remote_branch.rb. All commands are there, at the beginning of the file.</p>

<p>For the brave, try it out and tell me what you think. Improvements, bug reports and contributions are all welcome.</p>

<p>And remember, in case of an emergency, you can always refer to my <a href="http://www.programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git/">illustrated guide to recovering lost commits with Git</a> ;-)</p>

<p>Here&#8217;s what&#8217;s to come:</p>

<ul>
    <li>lots of tests</li>
    <li>a &#8216;remotize&#8217; functionality (for existing local branches)</li>
    <li>a much better resilience to use in faulty situations (e.g. deleting something that&#8217;s not present locally or remotely)</li>
    <li>the possibility to specify different branch names locally vs remotely</li>
    <li>slap an open source licence on it all</li>
    <li>and so much more!</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[I somehow feel I'm going to love what this guy writes...]]></title>
    <link href="http://www.programblings.com/2008/06/20/i-somehow-feel-im-going-to-love-what-this-guy-writes/"/>
    <updated>2008-06-20T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/06/20/i-somehow-feel-im-going-to-love-what-this-guy-writes</id>
    <content type="html"><![CDATA[<p>I&#8217;m kind of jealous. This guy put out 2 freaking good blog posts in 3 days. These are apparently his first 2 blog posts ever, too :-)</p>

<blockquote>You&#8217;ll never find a group who wears their ignorance of technology more proudly than the average business person. “I&#8217;m not a computer guy,” they&#8217;ll say with a big smile on their face. Well gee, the personal computer is only the most significant invention to come along in the past 100 years.</blockquote>


<p>By <a href="http://tales-of-an-it-director.blogspot.com/2008/06/modsocialskills-modrationality.html">Tales of an IT Director</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The illustrated guide to recovering lost commits with Git]]></title>
    <link href="http://www.programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git/"/>
    <updated>2008-06-07T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git</id>
    <content type="html"><![CDATA[<p> Git is one hell of a powertool.</p>

<p>Like with any such tool, as soon as you get to know it enough, you start pushing the boundaries. Git gives you a lot of control over your repository:</p>

<ul>
    <li>trivial branching and merging (even with long lived branches);</li>
    <li>rebasing as a cleaner alternative to merging;</li>
    <li>stashing aside your changes for a quick fix elsewhere;</li>
    <li><a href="http://tomayko.com/writings/the-thing-about-git">extracting logical, distinct commits from a multi-hours coding spree</a>;</li>
</ul>


<p>The list goes on&#8230;</p>

<p>More traditional version control systems don&#8217;t give you as much power as Git by any stretch of the mind. They are like taking a walk in the woods with your parents, at age 14.</p>

<p>You&#8217;re probably gonna see and do neat stuff, but you sure ain&#8217;t gonna get lost or anything.</p>

<!-- more -->


<p>Using Git on the other hand is more akin to being handed a cool motocross to go play alone in the woods&#8230; Also at age 14.</p>

<p><a href="http://www.programblings.com/uploads/2008/06/insane_motocross_shit.jpg" title="Insane motocross shit"><img src="http://www.programblings.com/uploads/2008/06/insane_motocross_shit.jpg" alt="Insane motocross shit" height="336" width="426" /></a></p>

<p>We all know what&#8217;s bound to happen, right?</p>

<p>You&#8217;ll smash into a tree.</p>

<p>The source control equivalent to slamming into a tree is losing commits. Getting all of Git&#8217;s power and flexibility at once can be somewhat dangerous.  You&#8217;ll find it so easy and helpful to branch and merge that you&#8217;ll start doing it way more often. On the other hand &#8211; especially in the beginning &#8211; you&#8217;ll misunderstand or plainly miss some important warnings, and make errors. Or you may just end up in weird merging situations you never thought of, and don&#8217;t necessarily understand. These situations can often result in losing commits or whole branches.</p>

<p>My goal with this article is to make sure you understand the situation you&#8217;re really in: you have <em>temporarily</em> lost commits or branches.</p>

<h3>Disclaimer</h3>


<p>This article assumes a basic knowledge of how git works, e.g. committing, branching and merging.</p>

<h3>My first time</h3>


<p>The first time I lost a commit was a good while ago. I can&#8217;t remember the details, but basically I got bit by the fact that under the covers, Git uses hard links liberally. Which means that copy / pasting your code directory as a recovery solution isn&#8217;t going to save your ass <img src="http://www.programblings.com/uploads/2008/06/ass.jpg" style="vertical-align: middle" alt="A nice poney" /> when you attempt a potentially damaging operation you don&#8217;t fully understand.</p>

<p>Note that compressing your code directory will, though.</p>

<p>So there I was, after attempting an operation I didn&#8217;t really understand. I knew I had failed what I attempted and I knew I had lost my last commit. Ironically, I still had Gitk open, displaying that very commit. As long as I didn&#8217;t refresh the Gitk view with F5 I could see the lost commit.</p>

<p>Here&#8217;s a fun fact: under OSX (not sure about Linux) you cannot select and copy text from Gitk&#8217;s interface, except for the SHA1 field [1]. I knew Git probably had a way to recover from that&#8230; But you know, I just wanted to get back to work and NOT search documentation and blog posts endlessly.</p>

<p>So I took screenshots, passed them real quick through <a href="http://jocr.sourceforge.net/">GOCR</a>, just to see how far it would get.</p>

<p>The result: GOCR doesn&#8217;t like the font Monaco :-)</p>

<h2>How to (really) recover lost commits with Git</h2>


<p>Recently I lost a commit again. This time however, Gitk was not up to date. I knew I&#8217;d just lost something I wouldn&#8217;t necessarily remember in its entirety. It was a commit an hour old, touching many files. And I have a crappy memory.</p>

<p>This time I had to do it the right way. I found out it&#8217;s really easy (once you figure it out), but I found no really clear explanation anywhere. So here goes.</p>

<h3>Initial setup</h3>


<p>If you wanna follow along &#8211; and I strongly recommend it &#8211; here&#8217;s the boring few steps to create a dummy repo and bring it up to speed with for the rest of this article. We&#8217;re going to beat the hell out of this repo and it&#8217;s going to be fun.</p>

<p>So just paste the following into a console:</p>

<pre><strong>mkdir recovery;cd recovery
git init
touch file
git add file
git commit -m "First commit"
echo "Hello World" &gt; file
git add .
git commit -m "Greetings"git branch cool_branch
git checkout cool_branch
echo "What up world?" &gt; cool_file
git add .
git commit -m "Now that was cool"
git checkout master
echo "What does that mean?" &gt;&gt; file</strong></pre>


<p>Ok, let&#8217;s look at where we&#8217;re at:</p>

<pre><strong>gitk ––all &amp;</strong></pre>


<p>The ––all option lets you see all branches at the same time, as well as your stashes.</p>

<p>Click here to enlarge your picture!!1</p>

<p><a href="http://www.programblings.com/uploads/2008/06/initial_setup.png" title="Initial setup - Recovering git commits"><img src="http://www.programblings.com/uploads/2008/06/initial_setup.png" alt="Initial setup - Recovering git commits" height="272" width="353" /></a></p>

<p>We can see the cool_branch as well as some yet uncommitted changes over the master branch.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">ls -l</font>
total 16
-rw-r--r--  1 mathieu  staff    15B  7 Jun 18:19 cool_file
-rw-r--r--  1 mathieu  staff    33B  7 Jun 18:19 file</strong></pre>


<p>Got my 2 files, I&#8217;m good to go.</p>

<h3>Let&#8217;s make a mistake</h3>


<p>Let&#8217;s say I decide I want to bring in these cool changes in master. I&#8217;ll do it with a rebase. I know there&#8217;s no big risk of conflicts so that&#8217;s a no-brainer.</p>

<table width="100%">
<tr>
<td width="50%">
<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git rebase cool_branch</font>
file: needs update</strong></pre>
</td>
<td width="50%">
<p class="center" style="margin: 0pt"><img src="http://www.programblings.com/uploads/2008/06/my_ugly_mug.jpg" alt="My ugly mug" height="41" width="41" /></p>
</td>
</tr>
</table>


<p>Now if you look carefully you&#8217;ll notice I wasn&#8217;t paying attention when Git gave me a feeble complaint about &#8216;file&#8217;.</p>

<p>Everything&#8217;s well, so I think &#8220;Ok, I don&#8217;t need cool_branch anymore&#8221;.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git branch -d cool_branch</font>
error: The branch 'cool_branch' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D cool_branch'.</strong></pre>


<p>Huh? Whatever you say, Linus. Let&#8217;s get on with it.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git branch -D cool_branch</font>
Deleted branch cool_branch.</strong></pre>


<p>Ahh, it feels good to be a Git ninja. Now let&#8217;s see where we&#8217;re at and refresh Gitk with F5.</p>

<p><a href="http://www.programblings.com/uploads/2008/06/gitk_oh_shit.png" title="Gitk - oh shit moment"><img src="http://www.programblings.com/uploads/2008/06/gitk_oh_shit.png" alt="Gitk - oh shit moment" height="271" width="353" /></a></p>

<p>Oops, my cool commit is gone! That thing can&#8217;t be right. Let&#8217;s panic:</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">ls</font>
file

mathieu@ml recovery (master)$ <font color="#6666ff">git status</font>
# On branch master
# Changed but not updated:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#
#    modified:   file
#
no changes added to commit (use "git add" and/or "git commit -a")

mathieu@ml recovery (master)$ <font color="#6666ff">git diff</font>
diff --git a/file b/file
index 557db03..f2a8bf3 100644
--- a/file
+++ b/file
@@ -1 +1,2 @@
 Hello World
<font color="#008000">+What does that mean?</font></strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/oh_shit.jpg" alt="Oh shit face" height="83" width="61" />
Oh sh!t</p>

<p>So the &#8216;file: needs update&#8217; message back there meant that the rebase didn&#8217;t happen, because I had pending changes.</p>

<p>Helpful.</p>

<h2>Recovering a lost commit</h2>


<p>Since I don&#8217;t think my uncommitted work is complete, I&#8217;ll just stash it instead of committing it. Then I&#8217;ll hunt down my lost work.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git stash save "Questioning the universe"</font>
Saved working directory and index state "On master: Questioning the universe" HEAD is now at 6da726f... Greetings</strong></pre>


<p>In the name of paranoïa, let&#8217;s make sure this got in right:</p>

<p><a href="http://www.programblings.com/uploads/2008/06/gitk_check_out_that_stash.png" title="In a paranoïa moment, we make sure the stash is saved correctly"><img src="http://www.programblings.com/uploads/2008/06/gitk_check_out_that_stash.png" alt="In a paranoïa moment, we make sure the stash is saved correctly" height="285" width="364" /></a></p>

<p>Ok, let&#8217;s get on with our rescue mission:</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git fsck −−lost-found</font>
dangling commit 93b0c51cfea8c731aa385109b8e99d19b38a55be</strong></pre>


<p>That sounds right, exactly one commit in the lost and found.</p>

<p>Let&#8217;s just make sure:</p>

<pre><strong>mathieu@ml recovery (master)$ </strong><font color="#6666ff"><strong>git show 93b0c51cfea8c731aa385109b8e99d19b38a55be | mate</strong></font></pre>


<p><a href="http://www.programblings.com/uploads/2008/06/show_lost_found.png" title="We see in textmate that this is our lost commit"><img src="http://www.programblings.com/uploads/2008/06/show_lost_found.png" alt="We see in textmate that this is our lost commit" height="168" width="266" /></a></p>

<p>Bingo!</p>

<h3>Different ways to recover the commit</h3>


<p>There are a few different ways to recover that commit. Obviously we can just copy and paste that snippet, but in the case of a bigger commit, that approach will just amount to a lot of error-prone busywork.</p>

<p>I&#8217;ll reclaim my Git ninja status and try it a few different ways.</p>

<h4>Recover it with rebase</h4>


<p>Let&#8217;s just replay this change on top of master:</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git rebase 93b0c51cfea8c731aa385109b8e99d19b38a55be</font>
First, rewinding head to replay your work on top of it...
HEAD is now at 93b0c51... Now that was cool
Fast-forwarded master to 93b0c51cfea8c731aa385109b8e99d19b38a55be.</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_recovered_with_rebase.png" alt="Commit recovered with rebase" /></p>

<p>Neat! Now I feel like a ninja worthy of the title again.</p>

<p>So let&#8217;s rewind one commit and try it another way.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git reset --hard head^</font>
HEAD is now at 6da726f... Greetings</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_rewinding_to_lost_commit.png" alt="Rewinding to a state where we’ve lost our commit" /></p>

<p>Ok, the commit&#8217;s gone.</p>

<p>(Don&#8217;t tell anyone but my inner ninja is feeling queasy again.)</p>

<h4>Recover it with merge</h4>


<p>There are cases where rebase is not powerful enough. For example when you expect to face a lot of conflicts. In this case merge is a better solution:</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git merge 93b0c51cfea8c731aa385109b8e99d19b38a55be</font>
Updating 6da726f..93b0c51
Fast forward
 cool_file |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 cool_file</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_recovered_with_merge.png" alt="Commit recovered with merge" /></p>

<p>Too easy&#8230; Rewind!</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git reset --hard head^</font>
HEAD is now at 6da726f... Greetings</strong></pre>


<h4>Recover it with cherry-pick</h4>


<p>If  instead you had a few commits one after another but you just want to pick the last one, rebase and merge won&#8217;t do. They would bring the whole branch back in master. That&#8217;s a situation for cherry-pick.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git cherry-pick 93b0c51cfea8c731aa385109b8e99d19b38a55be</font>
Finished one cherry-pick.
Created commit f443703: Now that was cool
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 cool_file</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_recovered_with_cherry_pick.png" alt="Commit recovered with cherry-pick" /></p>

<p>Insane!</p>

<p>This only leaves one open question: WHO&#8217;S YOUR DADDY NOW, GIT?</p>

<p>Now that we&#8217;ve established the answer to that question, let&#8217;s get back to work!</p>

<h3>Let&#8217;s make a second mistake</h3>


<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git stash clear</font></strong></pre>


<p>Or was it Git stash apply?</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gitk_accidental_stash_clear.png" alt="Oops! Accidentally lost the stash" /></p>

<p>Oh jeez, there we go again&#8230;</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git fsck −−lost-found</font>
dangling commit 24e3752f7a73ae98b361ce1c260e1f285d653447
dangling commit 93b0c51cfea8c731aa385109b8e99d19b38a55be</strong></pre>


<p>Ok, we still see the one we lost earlier, 93b0c51&#8230; Let&#8217;s look at the other one.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git show 24e3752f7a73ae98b361ce1c260e1f285d653447</font>
commit 24e3752f7a73ae98b361ce1c260e1f285d653447
Merge: 6da726f... c90f079...
Author: Mathieu Martin &lt;webmat@gmail.com&gt;
Date:   Sat Jun 7 16:02:57 2008 -0400

On master: Questioning the universe

diff --cc file
index 557db03,557db03..f2a8bf3
--- a/file
+++ b/file
@@@ -1,1 -1,1 +1,2 @@@
Hello World
<font color="#008000">++What does that mean?</font></strong></pre>


<p>Spot on. Let&#8217;s try something wild, while we&#8217;re here.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git checkout 24e3752f7a73ae98b361ce1c260e1f285d653447</font>
Note: moving to "24e3752f7a73ae98b361ce1c260e1f285d653447" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b &lt;new_branch_name&gt;
HEAD is now at 24e3752... On master: Questioning the universe

mathieu@ml recovery (24e3752...)$</strong></pre>


<p>As you may have noticed, my console always indicates which branch I&#8217;m in, so far [2]. But now I seem to be in some kind of twilight zone, which Gitk confirms.</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gitk_accidental_stash_clear.png" alt="Oops! Accidentally lost the stash" /></p>

<p>Let&#8217;s follow Git&#8217;s suggestion and make that a branch.</p>

<pre><strong>mathieu@ml recovery (24e3752...)$ <font color="#6666ff">git checkout -b recovery</font>
Switched to a new branch "recovery"

mathieu@ml recovery (recovery)$</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_stash_recovered_as_a_branch.png" alt="Stash recovered as a branch" /></p>

<p>Looks weird, like stashed items always do, but at least we have our commit.</p>

<p>After fiddling around with what&#8217;s been recovered from the stash, I recommend NOT keeping it as a commit.</p>

<p>If you try to replay the change in the recovery branch over master&#8217;s most recent commit, you lose the &#8220;Questioning the universe&#8221; commit. Probably because a stash is a weird kind of commit, or maybe because of a bug. I don&#8217;t know.</p>

<p><font color="#ff0000">(Don&#8217;t follow this one in your console) </font></p>

<pre><strong>mathieu@ml recovery (recovery)$ <font color="#000000">git rebase master  #I said don't do this one</font>
First, rewinding head to replay your work on top of it...
HEAD is now at 93b0c51... Now that was cool
Nothing to do.</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/gitk_rebasing_over_master_doesnt_work.png" alt="Rebasing the recovered stash over master doesn’t work" /></p>

<p>If instead I checkout master and then rebase its last change over the &#8216;recovery&#8217; branch it seems to work.</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gitk_recovered_stash_back_in_master.png" alt="Recovered stash back in master" /></p>

<p>However since I just saw a commit disappear when rebasing the other way around, I get the feeling that this isn&#8217;t a normal commit and it may come back to haunt me later.</p>

<h4>Recover it by applying a diff</h4>


<p>Let&#8217;s just apply the diff to master. I&#8217;ll do as if it actually was a substantial commit, involving lots of modifications on lots of files, and apply it automatically with &#8216;git apply&#8217;.</p>

<p>First let&#8217;s visualize where we&#8217;re at, again:</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gitk_stash_recovered_as_a_branch.png" alt="Stash recovered as a branch" /></p>

<p>A diff against master is not what we want since master includes a new (very cool) commit.</p>

<p>Instead we just want to see the changes introduced by the current commit. To do this we can compare it with the common ancestor between the master and recovery branches. So let&#8217;s start by finding it&#8217;s ID.</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gik_find_common_ancestor.png" alt="Finding the ID of the common ancestor" /></p>

<pre><strong>mathieu@ml recovery (recovery)$ <font color="#6666ff">git diff 6da726f37683c83947d54314cd32ca1ee9d490e0</font>
diff --git a/file b/file
index 557db03..f2a8bf3 100644
--- a/file
+++ b/file
@@ -1 +1,2 @@
Hello World
<font color="#008000">+What does that mean?</font></strong></pre>


<p>Looks good. Now we throw that diff upstairs.</p>

<pre><font color="#6666ff"><strong>git diff 6da726f37683c83947d54314cd32ca1ee9d490e0 &gt; ../recovery.diff</strong></font></pre>


<p>Then get apply it to our master branch.</p>

<pre><strong>mathieu@ml recovery (recovery)$ <font color="#6666ff">git checkout master</font>
Switched to branch "master"

mathieu@ml recovery (master)$ <font color="#6666ff">git apply ../recovery.diff</font></strong></pre>


<p>And we finally confirm that everything&#8217;s under control.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git status</font>
# On branch master
# Changed but not updated:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#
#    modified:   file
#
no changes added to commit (use "git add" and/or "git commit -a")

mathieu@ml recovery (master)$ <font color="#6666ff">git diff</font>
diff --git a/file b/file
index 557db03..f2a8bf3 100644
--- a/file
+++ b/file
@@ -1 +1,2 @@
Hello World
<font color="#008000">+What does that mean?</font></strong></pre>


<p>This change was first stashed rather than committed because I felt it was not complete. Applying it with Git apply only introduces it as an unstaged change, which works perfectly for this situation. Now I can keep banging at the code until I feel this actually deserves to be committed.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">echo "I don't know" &gt;&gt; file</font>

mathieu@ml recovery (master)$ <font color="#6666ff">git commit -a -m "Conversation of staggering depth"</font>
Created commit 65a4794: Conversation of staggering depth
 1 files changed, 2 insertions(+), 0 deletions(-)</strong></pre>


<h3>Cleaning up the crud</h3>


<p>Ok, so now I still have this weird looking recovery branch.</p>

<p><img src="http://www.programblings.com/uploads/2008/06/gitk_useless_recovery_branch.png" alt="Now we want to get rid of this weird recovery branch" /></p>

<p>Since it&#8217;s now useless we can get rid of it.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git branch -d recovery</font>
error: The branch 'recovery' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D recovery'.</strong></pre>


<p>Aha! This time everything&#8217;s committed correctly, so I know I can delete it for real. Git is complaining because that commit was not included through its normal merge or rebase commands. So it warns me that I may be about to lose something. However I know I got everything through the diff I made and re-applied.</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git branch -D recovery</font>
Deleted branch recovery.</strong></pre>


<p>Now that I&#8217;m aware that commits are reachable even if they&#8217;re not in a branch anymore, I wonder about my repo&#8217;s size.</p>

<p><img src="http://www.programblings.com/uploads/2008/06/repo_size_fat.png" alt="Repository size with a few dangling commits: 224kb" /></p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git gc</font>
Counting objects: 22, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (22/22), done.
Total 22 (delta 7), reused 0 (delta 0)

mathieu@ml recovery (master)$ <font color="#6666ff">git prune</font></strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/06/repo_size_slim.png" alt="Repo size after cleaning up the crud: 152kb" /></p>

<p>Fair enough. I would expect the unused commits to now be unreachable, but strangely enough:</p>

<pre><strong>mathieu@ml recovery (master)$ <font color="#6666ff">git fsck −−lost-found</font>
dangling commit 49ed65cdea22443af3f1fd400754fe1517421b24
dangling commit 4b1bf4792cba929e88114379d7d5e86a2dc9990f
dangling commit 6cdf88318109dede7bd3c1a75be76c7255708ded
dangling commit 715a6b2cfe797383216d0f9b04fe8f50e90e779f
dangling commit f443703e5060d9f3b4d97504bda5f97e5a0b31e8</strong></pre>


<p>If anyone finds out what that&#8217;s all about, please let me know!</p>

<p>Maybe Git&#8217;s just refusing to do any work unless it&#8217;s going to actually save a considerable amount of space? I have no idea.</p>

<h2>Conclusion</h2>


<p>Once you know how to recover from bad mistakes, you&#8217;ll find that Git is not only a very powerful tool, but also a very forgiving one. As opposed to a motocross.</p>

<p>The following commands will help you figure you way out of most bad situations:</p>

<ul>
    <li>git show</li>
    <li>git fsck −−lost-found</li>
    <li>git diff</li>
</ul>


<p>And these ones will actually get out of these bad situations:</p>

<ul>
    <li>git rebase</li>
    <li>git cherry-pick</li>
    <li>git merge</li>
    <li>git apply</li>
</ul>


<p>As I think I demonstrated, Git gives you the ability to recover from most bad mistakes. The fact that any single commit can be cherry-picked, checked out, rebased or merged makes it really easy to recover from hairy situations.</p>

<p>The only case where you might actually lose information is when something has not been committed or stashed yet, which I think is perfectly reasonable.</p>

<p>So if you take only one thing away from this article, let it be this. Git is much safer than a motocross.</p>

<h3>Footnotes</h3>


<p>[1] At the time I didn&#8217;t know that just having the SHA1 id was enough to save me.</p>

<p>[2] See how to configure your console in the same manner and also get auto-completion for Git <a href="http://jfcouture.com/2007/12/18/various-tips-for-setting-up-git-improve-gitk-look-and-get-bash-completion/" title="Various Tips For Setting Up Git: Improve Gitk Look And Get Bash Completion">here</a>.</p>
]]></content>
  </entry>
  
</feed>
