<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>This is my blog. It’s not finished yet.

  var _gaq = _gaq || [];
  _gaq.push([‘_setAccount’, ‘UA-696376-5’]);
  _gaq.push([‘_trackPageview’]);

  (function() {
    var ga = document.createElement(‘script’); ga.type = ‘text/javascript’; ga.async = true;
    ga.src = (‘https:’ == document.location.protocol ? ‘https://ssl’ : ‘http://www’) + ‘.google-analytics.com/ga.js’;
    var s = document.getElementsByTagName(‘script’)[0]; s.parentNode.insertBefore(ga, s);
  })();</description><title>As Yet Untitled</title><generator>Tumblr (3.0; @benstraub)</generator><link>http://ben.straubnet.net/</link><item><title>Dear Microsoft: It's About Time</title><description>&lt;p&gt;Mr. Sinofsky, I’d like to thank you. I’ve been waiting for this for a long time.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lrmk6vEOVy1qc2qlx.jpg" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Win32 is an old warhorse. In its heyday, it was dependable, useful, and let us as developers do whatever we needed. But the world has moved on, and while development got easier and better everywhere else, Win32 stayed the same.&lt;/p&gt;

&lt;p&gt;For good reason, mind you. &lt;a href="http://blogs.msdn.com/b/oldnewthing/" target="_blank"&gt;Keeping backwards compatibility is &lt;em&gt;hard&lt;/em&gt;&lt;/a&gt;, especially when you’re trying to release new features at the same time. And it’s not just technically hard — I’m sure people inside Microsoft have been itching to start over for a long time now.&lt;/p&gt;

&lt;p&gt;Apple did this 10 years ago. I’m sure there was much wailing and gnashing of teeth when OSX and Cocoa were released. Apple gave their users a great platform, and their developers a new way of making things for it that was better. A hardware-accelerated UI layer. Bundles. A visual style to follow. A programming model that was designed from the ground up to support a new kind of application.&lt;/p&gt;

&lt;p&gt;Now Microsoft is doing it, and many of the themes are the same. I hope it goes as well for them, because I want to write Metro apps, and the only way I can do that is if Windows 8 sells like hotcakes.&lt;/p&gt;</description><link>http://ben.straubnet.net/post/10280437640</link><guid>http://ben.straubnet.net/post/10280437640</guid><pubDate>Fri, 16 Sep 2011 10:05:48 -0700</pubDate></item><item><title>Native Win32 for fun and profit</title><description>&lt;p&gt;All the cool kids these days are playing with awesome dynamic languages, or on cool frameworks. I’m stuck with C++ at work, but every now and then I get to do something cool with it.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lg01w6rPK81qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;That’s the Wacom &lt;a href="http://graphicssoft.about.com/od/hardware/ig/Wacom-Intuos4/Intuos4-Radial-Menu.htm" target="_blank"&gt;radial menu&lt;/a&gt;, which is implemented as a fully alpha-blended window in native Win32. Something like this is dead simple in WPF, but with native code it’s a bit trickier. I used WTL, GDI+, and a handy, little-known Windows feature to get it done, and I’m going to share my secrets with you, dear reader.&lt;/p&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;

&lt;h3&gt;WTL&lt;/h3&gt;

&lt;p&gt;Windowing frameworks are thick on the ground, and I’ve been mostly dissatisfied with the abilities of the Win32-wrapping category. However, they make something like this reusable, so what the heck.&lt;/p&gt;

&lt;p&gt;You can grab WTL at &lt;a href="http://wtl.sourceforge.net/" target="_blank"&gt;the project home on SourceForge&lt;/a&gt;. For this project, I’m just taking the files in the &lt;code&gt;include&lt;/code&gt; directory and putting them under &lt;code&gt;wtl&lt;/code&gt; in my project directory, so I don’t get the Windows SDK versions instead.&lt;/p&gt;

&lt;p&gt;I’ve found this to be the best way to include the WTL headers:&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
#define _SECURE_ATL 1
#define _WTL_NO_AUTOMATIC_NAMESPACE
#define _ATL_NO_AUTOMATIC_NAMESPACE

// These are required to be included first
#include "atlbase.h"
#include "atlwin.h"
#include "wtl/atlapp.h"

#include "wtl/atlgdi.h"   // For WTL::CDC
#include "wtl/atlframe.h" // For WTL::CFrameWindowImpl
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Those defines specify that the ATL and WTL classes should stay safely ensconced in their own namespaces. This means you have to reference them as &lt;code&gt;WTL::CFrameWndImpl&lt;/code&gt;, but it keeps the global namespace clean, which is a major failing of &lt;code&gt;windows.h&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;GDI+&lt;/h3&gt;

&lt;p&gt;GDI+ is an immediate-mode drawing API that has shipped with Windows since XP, so I can use it without needing to ship yet another redistributable installer. Here’s all you need to do:&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
#pragma comment(lib, "gdiplus.lib")
#include &lt;gdiplus.h&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While GDI+ is written in C++ and uses classes, it’s initialization isn’t RAII-friendly, so I wrote a little wrapper class:&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
class ScopedGdiplusInitializer
{
public:
    ScopedGdiplusInitializer()
    {
        Gdiplus::GdiplusStartupInput gdisi;
        Gdiplus::GdiplusStartup(&amp;mGdiplusToken, &amp;gdisi, NULL);
    }
    ~ScopedGdiplusInitializer()
    {
        Gdiplus::GdiplusShutdown(mGdiplusToken);
    }
private:
    ULONG_PTR mGdiplusToken;
};
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now I can write my main function like this:&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
int main()
{
    ScopedGdiplusInitializer gdiplusinit;

    // ...
}
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Boost&lt;/h3&gt;

&lt;p&gt;The production code for this feature uses boost (specifically &lt;code&gt;shared_ptr&lt;/code&gt;), but in the interest of simplicity I’ve left it out. If you use boost, or your compiler supports the new &lt;code&gt;std::shared_ptr&lt;/code&gt; introduced with TR1, I &lt;em&gt;highly&lt;/em&gt; recommend you use that instead of raw pointers whenever possible.&lt;/p&gt;

&lt;h2&gt;A window class&lt;/h2&gt;

&lt;p&gt;Here’s where it all comes together. Meet me after the code, and I’ll explain more fully.&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
class AlphaWindow 
    : public WTL::CFrameWindowImpl&lt; AlphaWindow, ATL::CWindow,
        ATL::CWinTraits&lt; WS_POPUP, WS_EX_LAYERED &gt; &gt;
{
public:
    DECLARE_FRAME_WND_CLASS(_T("WTLAlphaWindow"), 0);

    virtual ~AlphaWindow()
    {
        if (IsWindow())
        {
            SendMessage(WM_CLOSE);
        }
    }

    void UpdateWithBitmap(Gdiplus::Bitmap *bmp_I, POINT *windowLocation_I = NULL)
    {
        // Create a memory DC
        HDC screenDC = ::GetDC(NULL);
        WTL::CDC memDC;
        memDC.CreateCompatibleDC(screenDC);
        ::ReleaseDC(NULL, screenDC);

        // Copy the input bitmap and select it into the memory DC
        WTL::CBitmap localBmp;
        {
            bmp_I-&gt;GetHBITMAP(Gdiplus::Color(0,0,0,0), &amp;localBmp.m_hBitmap);
        }
        HBITMAP oldBmp = memDC.SelectBitmap(localBmp);

        // Update the display
        POINT p = {0};
        SIZE s = {bmp_I-&gt;GetWidth(), bmp_I-&gt;GetHeight()};
        BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
        {
            ::UpdateLayeredWindow(m_hWnd, NULL, windowLocation_I, &amp;s, memDC, 
                &amp;p, RGB(0,255,255), &amp;bf, ULW_ALPHA);
        }
        ShowWindow(SW_SHOWNORMAL);

        // Cleanup
        memDC.SelectBitmap(oldBmp);
    }
};
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Layered Windows&lt;/h3&gt;

&lt;p&gt;The magic ingredients for this class are the &lt;code&gt;WS_EX_*&lt;/code&gt; styles and the &lt;code&gt;UpdateLayeredWindow&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;First, the styles. These are specified on line 3, as part of the base class. That’s just how you declare your window’s styles in WTL. There are two:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;code&gt;WS_POPUP&lt;/code&gt; means this is a square window with no decorations around the outside. No title bar, no close button, nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WS_EX_LAYERED&lt;/code&gt; tells Windows that &lt;a href="http://msdn.microsoft.com/en-us/library/ms997507.aspx" target="_blank"&gt;this window is different&lt;/a&gt;, and that it can do per-pixel alpha blending with other windows. This was available in Windows 2000, but starting with Vista the window’s face could be cached and composited by the GPU, which made it much more useful.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The call to &lt;code&gt;UpdateLayeredWindow&lt;/code&gt; on line 35 is what tells Windows what the contents of the display are. There’s some clunky interop code here, since the GDI+ &lt;code&gt;Bitmap&lt;/code&gt; object can’t be used directly with the GDI-oriented layered window API. I’m sure there’s a better way, but in my case the overhead of copying my smallish &lt;code&gt;Bitmap&lt;/code&gt; into another smallish &lt;code&gt;HBITMAP&lt;/code&gt; wasn’t a problem.&lt;/p&gt;

&lt;p&gt;WTL complains rather loudly if a window object is destroyed before the HWND it’s wrapping is closed, so the destructor on line 7 takes care of that.&lt;/p&gt;

&lt;h3&gt;Pretty Pictures&lt;/h3&gt;

&lt;p&gt;That &lt;code&gt;UpdatedLayeredWindow&lt;/code&gt; call is wrapped in a method that takes a GDI+ bitmap, so now all we need to do is provide it with one. GDI+ makes this pretty easy, especially when compared to GDI code:&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
using namespace Gdiplus;
Bitmap bmp(400,400);  // Create a bitmap buffer
Graphics g(&amp;bmp);     // Context for drawing on the bitmap
g.Clear(Color::Black);
// ...
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;All together now&lt;/h2&gt;

&lt;p&gt;Here’s the &lt;code&gt;main&lt;/code&gt; function of my little test program.&lt;/p&gt;

&lt;div class="code"&gt;&lt;pre class="brush: cpp"&gt;
int main()
{
    ScopedGdiplusInitializer init;

    {
        // Create the display window
        AlphaWindow wnd;
        wnd.Create();
        wnd.SetWindowPos(NULL, 200,200, 0,0, SWP_NOSIZE | SWP_NOREPOSITION);

        // Create a backbuffer
        Gdiplus::Bitmap bmp(400,400);

        // Clear the background of the buffer to translucent black
        Gdiplus::Graphics g(&amp;bmp);
        g.Clear(Gdiplus::Color(100,0,0,0));

        // This tells GDI+ to anti-alias when it draws shapes
        g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);

        // Draw two semi-transparent ellipses
        Gdiplus::Pen redPen(Gdiplus::Color(100,255,0,0), 10.);
        Gdiplus::Pen bluePen(Gdiplus::Color(100,0,0,255), 10.);
        g.DrawEllipse(&amp;redPen, 50,50, 200,300);
        g.DrawLine(&amp;bluePen, 175,10, 175,390);
        g.DrawEllipse(&amp;redPen, 100,50, 200,300);

        // Update the window's display
        wnd.UpdateWithBitmap(&amp;bmp);

        // Wait to exit
        getchar();
    }
}
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I know, programmer demos of this are always ugly. Maybe one day I’ll write about how to store a PNG as a resource, and load it in for use with this. For now, you get an ugly screenshot:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lg0ej6FXNR1qc2qlx.png" alt=""/&gt;&lt;/p&gt;</description><link>http://ben.straubnet.net/post/3074077580</link><guid>http://ben.straubnet.net/post/3074077580</guid><pubDate>Wed, 02 Feb 2011 13:45:00 -0800</pubDate></item><item><title>Git: Grafting repositories</title><description>&lt;p&gt;We recently evaluated replacements for our &lt;a href="http://www.highprogrammer.com/alan/windev/sourcesafe.html" target="_blank"&gt;VSS&lt;/a&gt;-workalike source control system at work. We have about 14 years of history in our current database, though, and it seems like a good idea to preserve that.&lt;/p&gt;

&lt;p&gt;The problem is that all that history takes time to import, and shutting all development down for a week while we get the data into the new system was just not an option. I knew there had to be a way to get this done right, and it turns out git can do exactly what we want.&lt;/p&gt;

&lt;h2&gt;Moving to git&lt;/h2&gt;

&lt;p&gt;The first step is to fetch a clean snapshot of the current source tree and stuff that into a git repo as the root commit. All the engineers can then start working from that repository with no effective downtime.&lt;/p&gt;

&lt;p&gt;I’m going to handwave the data conversion, but suffice it to say we’d need a &lt;code&gt;fast-import&lt;/code&gt; script. The interesting bit is how to get all of this historical data back into git.&lt;/p&gt;

&lt;h2&gt;Pull it in&lt;/h2&gt;

&lt;p&gt;So now our “new” repository has some work done on it, and it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70ewsiCBG1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;And we’ve imported all the old history into an “old” repository, which looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70exzfVLr1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Now what we want to do is change the first commit in the “nuevo” repo (“New commit #1”) so that its parent is the last commit in the “old” repo (“Old #3”). Time for some voodoo:&lt;/p&gt;

&lt;pre&gt;    git fetch ../old master:ancient_history&lt;/pre&gt;

&lt;p&gt;Git lets you fetch from any other git repository, whether this repo is related to it or not! Brilliant! This leaves us with this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70fcr3atc1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Note how we renamed the old &lt;code&gt;master&lt;/code&gt; branch to &lt;code&gt;ancient_history&lt;/code&gt;. If we hadn’t, git would have tried to merge the two, and probably given up in disgust.&lt;/p&gt;

&lt;p&gt;Now we still have a problem. The two trees aren’t connected, and in fact a &lt;code&gt;git pull&lt;/code&gt; won’t even get the &lt;code&gt;ancient_history&lt;/code&gt; branch at all. We need a way to make a connection between the two.&lt;/p&gt;

&lt;h2&gt;Grafts&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: I know there must be an easier way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Git has a facility called a &lt;em&gt;graft&lt;/em&gt;, which basically fakes up a parent link between two commits. To make one, just insert a line into the &lt;code&gt;.git/info/grafts&lt;/code&gt; file in this format:&lt;/p&gt;

&lt;pre&gt;    [ref] [parent]&lt;/pre&gt;

&lt;p&gt;Both of these need to be the full hash of the commits in question. So let’s find them:&lt;/p&gt;

&lt;pre&gt;
    $ git rev-list master | tail -n 1
    d7737bffdad86dc05bbade271a9c16f8f912d3c6

    $ git rev-parse ancient_history
    463d0401a3f34bd381c456c6166e514564289ab2

    $ echo d7737bffdad86dc05bbade271a9c16f8f912d3c6 \
           463d0401a3f34bd381c456c6166e514564289ab2 \
           &gt; .git/info/grafts
&lt;/pre&gt;

&lt;p&gt;There. Now our history looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70frps6eF1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Perfect! What could go wrong?&lt;/p&gt;

&lt;h2&gt;What went wrong&lt;/h2&gt;

&lt;p&gt;Cloning this repo results in this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70fufOjlK1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Woops. It turns out that grafts only take effect for the local repository. We can fix this with judicious application of &lt;code&gt;fast-import&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git fast-export --all &gt; ../export

$ mkdir ../nuevo-complete

$ cd ../nuevo-complete

$ git init

$ git fast-import &lt; ../export
git-fast-import statistics: [...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l70g23RRcP1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;This effectively converts our “fake” history link into a real one. All the engineers will have to re-clone from this new repository, since the hashes will all be different, but that’s a small price to pay for no downtime and a complete history.&lt;/p&gt;</description><link>http://ben.straubnet.net/post/939181602</link><guid>http://ben.straubnet.net/post/939181602</guid><pubDate>Wed, 11 Aug 2010 16:07:49 -0700</pubDate></item><item><title>When I see something as a nerd, I always try to see the...</title><description>&lt;iframe width="400" height="232" src="http://www.youtube.com/embed/rEUxlwb2uFI?wmode=transparent&amp;autohide=1&amp;egm=0&amp;hd=1&amp;iv_load_policy=3&amp;modestbranding=1&amp;rel=0&amp;showinfo=0&amp;showsearch=0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;When I see something as a nerd, I always try to see the algorithm behind it, but this resists all of that. I can’t imagine the level of talent it takes to make something like this.&lt;/p&gt;</description><link>http://ben.straubnet.net/post/938282883</link><guid>http://ben.straubnet.net/post/938282883</guid><pubDate>Wed, 11 Aug 2010 12:27:10 -0700</pubDate></item><item><title>/^1?$|^(11+?)\1+$/ tests for primeness!</title><description>&lt;a href="http://www.noulakaz.net/weblog/2007/03/18/a-regular-expression-to-check-for-prime-numbers/"&gt;/^1?$|^(11+?)\1+$/ tests for primeness!&lt;/a&gt;: &lt;p&gt;Ugly and beautiful at the same time. Beaugliful?&lt;/p&gt;</description><link>http://ben.straubnet.net/post/837514636</link><guid>http://ben.straubnet.net/post/837514636</guid><pubDate>Tue, 20 Jul 2010 12:50:57 -0700</pubDate></item><item><title>Git for other purposes</title><description>&lt;p&gt;Git is usually used to manage source code, though it’s described by its creator as a &lt;a href="http://www.google.com/search?q=stupid+content+tracker" target="_blank"&gt;stupid information tracker&lt;/a&gt;. When my team was looking to rework our &lt;abbr title="configuration management"&gt;CM&lt;/abbr&gt; system, I was able to apply my spare-time dabbling with git.&lt;/p&gt;

&lt;p&gt;CM is a software engineering discipline all its own, and a large company can easily have several people whose full-time job it is to manage software configurations. CM basically boils down to taking several independent components and combining them into something consumable.&lt;/p&gt;

&lt;p&gt;In our case, we have an executable produced by one team, a set of manuals that comes from another team, some kernel-mode drivers that are on their own timeline because of WHQL, and some other odds and ends. The goal of the new system was to allow things that change together to be kept in the same place, and simply refer to fixed versions of other things. For instance, version 9 of our driver might need to pull in version “2010-06-10” of the manuals.&lt;/p&gt;

&lt;p&gt;We currently use a &lt;abbr title="Visual SourceSafe"&gt;VSS&lt;/abbr&gt;-workalike to manage these things, but that has some problems. Our tool can’t manage file renames or reorganization, so we’re stuck with a directory that has every historical name for a file, and the directories have no sanity. It’s a mess.&lt;/p&gt;

&lt;p&gt;The problems we have with our current tool simply don’t exist with git. You can move files around and rename them with impunity, since a git commit is just a bunch of path/object mappings (rather than a listing of files, each with its own history). So I hacked together a set of scripts that would take built binaries, commit, tag, and push them to a central repository for safekeeping. Each component comes with a script that knows how to pull other components in. The whole thing uses git tags to manage component versions.&lt;/p&gt;

&lt;p&gt;One thing we had to manage properly was nightly builds. The central repo is only used for actually-released versions of the software; pushing all the nightly builds to it would be a waste of time. However, we wanted the automated nightly to be able to use the CM machinery to create an installable package. This is a bit tricky, and at first glance seems silly: why would you commit something into a version control system if you only want &lt;em&gt;some&lt;/em&gt; of the versions to actually be stored?&lt;/p&gt;

&lt;p&gt;It’s not so bad. The trick is to &lt;code&gt;git reset --hard origin/master&lt;/code&gt; before the script copies in the new versions of the files. Here’s what a fresh clone of a component looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l4l5ftEwcD1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;This is a component with three real versions stored on the server. Now we’ll wait four days, and see what happens to our local repository:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l4l5lnncF51qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Pretty messy. There are four throwaway builds stored in there. We haven’t pushed any of these, so all of those commits only exist on this machine. Now we’ll do a real build:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l4l5ouC0Ip1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;And now we need to give the server both the commit on &lt;code&gt;master&lt;/code&gt; as well as the new tag:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git push origin master
  Counting objects: 5, done.
  Writing objects: 100% (3/3), 233 bytes, done.
  Total 3 (delta 0), reused 0 (delta 0)
  Unpacking objects: 100% (3/3), done.
  To &lt;remote&gt;
     ad9c250..725bf06  master -&gt; master
$ git push origin v4
Total 0 (delta 0), reused 0 (delta 0)
To &lt;remote&gt;
 * [new tag]         v4 -&gt; v4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now our gitk window looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l4l62mwCiC1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;And a fresh clone looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_l4l64n09uL1qc2qlx.png" alt=""/&gt;&lt;/p&gt;

&lt;p&gt;Success: none of the nightly builds were stored in the central repository. Git is a pretty nice source control system, but it does a pretty decent job at configuration management as well.&lt;/p&gt;</description><link>http://ben.straubnet.net/post/735737032</link><guid>http://ben.straubnet.net/post/735737032</guid><pubDate>Fri, 25 Jun 2010 13:59:14 -0700</pubDate></item><item><title>This weekend’s food project: strawberry freezer jam!</title><description>&lt;img src="http://27.media.tumblr.com/tumblr_l48wmapYuv1qctwlzo1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;This weekend’s food project: strawberry freezer jam!&lt;/p&gt;</description><link>http://ben.straubnet.net/post/713861175</link><guid>http://ben.straubnet.net/post/713861175</guid><pubDate>Fri, 18 Jun 2010 22:00:03 -0700</pubDate></item><item><title>This is my daughter.</title><description>&lt;img src="http://28.media.tumblr.com/tumblr_l48ibwnD4W1qctwlzo1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;This is my daughter.&lt;/p&gt;</description><link>http://ben.straubnet.net/post/713036778</link><guid>http://ben.straubnet.net/post/713036778</guid><pubDate>Fri, 18 Jun 2010 16:52:44 -0700</pubDate></item></channel></rss>

