<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title>apenwarr - Business is Programming</title>
    <description>apenwarr - Business is Programming - NITLog</description>
    <link>http://alumnit.ca/~apenwarr/log/</link>
    <language>en-ca</language>
    <generator>NITLog</generator>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <item>
      <title>2008-08-27: More Artemy Lebedev</title>
      <pubDate>Tue, 19 Aug 2008 18:38:35 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#27</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#27</guid>
      <description>&lt;b&gt;More Artemy Lebedev&lt;/b&gt;
&lt;p&gt;
Art Lebedev writes about his concept of a &lt;a
href=&quot;http://www.artlebedev.com/mandership/148/&quot;&gt;Unit of Sense&lt;/a&gt;:
something &lt;i&gt;new&lt;/i&gt; which you create and which requires intelligence to do.
&lt;p&gt;
He claims that the average &quot;good designer&quot; produces 1-2 units of sense per
month.  An excellent designer, maybe four.  And an artistic director, at
least 6.  He also claims that a fair way to pay designers is to multiply
their produced units of sense by a fixed dollar value.
&lt;p&gt;
&lt;i&gt;&quot;Things like good ideas, interesting concepts and fresh techniques are
units of sense. A one-hundred-page brandbook may also be considered a unit
of sense - not on a per-page basis, but as a whole.&quot;&lt;/i&gt;
&lt;p&gt;
The concept is really interesting, as it offers a way to quantify
&lt;i&gt;designer&lt;/i&gt; output, something that's notoriously hard to measure. 
Unfortunately, his description is itself a little hard to quantify.
&lt;p&gt;
Obviously this is hard to apply to anything &lt;i&gt;other&lt;/i&gt; than designers, as
the majority of work that most people do is perfectly valid work, but simply
isn't creative.  I guess they should still get paid, though.
&lt;p&gt;
One way to think of it is like this: as a programmer, perhaps the interest
level you have in your job is a function of your natural unit of sense
creativity level, as compared to your creativity level at &lt;i&gt;this&lt;/i&gt; job. 
Or maybe your job satisfaction is indicated by your creativity level, not
the other way around.
      </description>
    </item>
    <item>
      <title>2008-08-25: Art Lebedev on the proper formatting of punctuation</title>
      <pubDate>Tue, 19 Aug 2008 14:23:51 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#25</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#25</guid>
      <description>&lt;b&gt;Art Lebedev on the proper formatting of punctuation&lt;/b&gt;
&lt;p&gt;
This guy continues to blow my mind.  Some &lt;a
href=&quot;http://www.artlebedev.com/mandership/143/&quot;&gt;tips on formatting
punctuation&lt;/a&gt; in a visually appealing way.  Check out the section on how
to center things horizontally.  And naturally there's a bonus section on
the proper formatting of smileys as punctuation.
&lt;p&gt;
Reading this stuff is a good way to remind myself why I'm a crappy visual
designer.
&lt;p&gt;
And also via Art Lebedev: &lt;a
href=&quot;http://www.artlebedev.com/mandership/144/&quot;&gt;Leonardo da Vinci invented
stinkbombs&lt;/a&gt;.
&lt;p&gt;
He also has a brilliantly simple way of &lt;a
href=&quot;http://www.artlebedev.com/mandership/149/&quot;&gt;expressing the success of a
design in terms of its requirements&lt;/a&gt;.  &quot;Design is not something to
discuss ... the only thing that can be discussed is whether the task has or
has not been achieved.&quot;
&lt;p&gt;
Plus there's an article on &lt;a
href=&quot;http://www.artlebedev.com/mandership/150/&quot;&gt;designing well by designing
badly on purpose&lt;/a&gt;.  This method is ingenious, since it lets you imagine
your users as super-intelligent enemies and then work to defeat them. 
Considering how hard it is to really believe how helpless users can be,
&lt;i&gt;over&lt;/i&gt;estimating them could be much easier.
&lt;p&gt;
      </description>
    </item>
    <item>
      <title>2008-08-23: CSS Still Sucks</title>
      <pubDate>Tue, 19 Aug 2008 13:57:28 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#23</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#23</guid>
      <description>&lt;b&gt;CSS Still Sucks&lt;/b&gt;
&lt;p&gt;
Here's a nicely &lt;a
href=&quot;http://geeklondon.com/blog/view/float_like_a_wasp&quot;&gt;disgust-filled
article about various problems with CSS&lt;/a&gt;.  He seems bewildered by how
something so bad could have been invented, but it's really very simple.  The
people who invented and then standardized CSS &lt;i&gt;had never used it&lt;/i&gt;. 
After all, they invented it before any web browser supported it.
&lt;p&gt;
The best languages are invented by the people who are using them to do real
work, &lt;i&gt;while&lt;/i&gt; they use them to do real work.
&lt;p&gt;
I said &lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/25.html&quot;&gt;something
similar, with examples&lt;/a&gt; back in 2004.      </description>
    </item>
    <item>
      <title>2008-08-22: gitbuilder</title>
      <pubDate>Fri, 22 Aug 2008 23:28:37 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#22</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#22</guid>
      <description>&lt;b&gt;gitbuilder&lt;/b&gt;
&lt;p&gt;
Well, it seems to be my week for small, handy tools.  As a followup to &lt;a
href=&quot;http://alumnit.ca/~apenwarr/log/?m=200808#21&quot;&gt;cron2rss&lt;/a&gt; from
a few days ago, I now present to you: &lt;a
href=&quot;http://github.com/apenwarr/gitbuilder/wikis&quot;&gt;gitbuilder&lt;/a&gt;.  It's an
autobuilder tool for your favourite git-based project, with built-in
bisection support.
&lt;p&gt;
I've been working on this for a while, but I finally decided to get it
production-ready a few days ago after I spent several hours tracking down a
problem... that turned out to already be caught by our unit tests.  Except
nobody had run the unit tests recently.  Oops.  Well, now I'll run them
&lt;i&gt;for&lt;/i&gt; you, thank you very much.
&lt;p&gt;
Check out a sample of the results at the &lt;a
href=&quot;http://www.versabanq.com/demo/vxautobuilder/&quot;&gt;Versaplex
autobuilder&lt;/a&gt; page.
&lt;p&gt;
&lt;b&gt;Side note&lt;/b&gt;
&lt;p&gt;
&lt;a href=&quot;http://github.com/&quot;&gt;GitHub.com&lt;/a&gt; is way more addictive than I
thought.  It's what SourceForge and Google Code &lt;i&gt;should&lt;/i&gt; have been: a
really easy way for people to publish, fork, and merge source code, with a
few extra hyperlinks thrown in here and there for good measure.  The key
thing is the non-global namespace, so you can just dump stuff there and give
it to people whenever you want; it's like an extension of your local ~/src
directory.  Thanks to &lt;a href=&quot;http://wlach.livejournal.com/&quot;&gt;wlach&lt;/a&gt; for
convincing me to try it.
      </description>
    </item>
    <item>
      <title>2008-08-21: cron2rss</title>
      <pubDate>Mon, 18 Aug 2008 19:09:04 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#21</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#21</guid>
      <description>&lt;b&gt;cron2rss&lt;/b&gt;
&lt;p&gt;
At work we have a lot of servers, and sometimes they have problems.  Even
though *I* mostly just handle development servers, not production ones, it's
still kind of a pain to keep track of them all and it's always embarrassing
to find out from a co-worker that one of them has stopped working.
&lt;p&gt;
So I use a bunch of cron jobs to do a bunch of daily tasks and make sure
things are flowing smoothly, but this isn't really all that optimal.  The
problem is that you don't want cron emails when tasks *work* (some of them
are running every ten minutes!). But you *do* want emails when they don't
work. On the other hand, you don't need an email every *ten minutes* when
something breaks.  And moreover, you really want to be notified when the
server the task was supposed to run on has crashed and the job doesn't run
at all.
&lt;p&gt;
Sadly, cron itself doesn't do a very good job of this, particularly that
last part, where it's completely useless.
&lt;p&gt;
So I spent a few hours today whipping up &lt;a
href=&quot;http://github.com/apenwarr/cron2rss&quot;&gt;cron2rss&lt;/a&gt;.  It reads, saves,
and eventually expires the stdout/stderr output from multiple cron jobs on
multiple computers, then turns the result into two RSS feeds: one with
everything, and one with only the failures.  *And* it auto-inserts entries
into the feed whenever it's been too long since one of the tasks has
produced a log message.  The RSS service can also be run on more than one
computer at a time, so that if one of your RSS feeds dies, the others can
still tell you about a failure.
&lt;p&gt;
I leave you with this food for thought:&lt;pre&gt;
   0,10,20,30,40,50 *  * * *   ~/cron2rss/add test-website wget -O/dev/null http://versabanq.com
&lt;/pre&gt;
&lt;p&gt;
How do you set up something like that if you don't have my tool?  What
would you do if your test was more complicated?  What if you had 50 servers
instead of 1?
      </description>
    </item>
    <item>
      <title>2008-08-19: Dog on Treadmill</title>
      <pubDate>Sun, 17 Aug 2008 17:29:46 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#19</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#19</guid>
      <description>&lt;b&gt;Dog on Treadmill&lt;/b&gt;
&lt;p&gt;
Yes.
&lt;p&gt;
&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/Zx9e3FmAF0k&amp;hl=en&amp;fs=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/Zx9e3FmAF0k&amp;hl=en&amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
      </description>
    </item>
    <item>
      <title>2008-08-17: Being an entrepreneur</title>
      <pubDate>Sun, 17 Aug 2008 16:40:27 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#17</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#17</guid>
      <description>&lt;b&gt;Being an entrepreneur&lt;/b&gt;
&lt;p&gt;
&lt;ul&gt;&lt;i&gt;Being an entrepreneur doesn't mean you're smart.  A smart guy will
figure out how to make a bunch of money while taking on much less risk. 
Corollary to this, there are a lot of dumb entrepreneurs out there.&lt;/i&gt;
&lt;p&gt;
-- &lt;a href=&quot;http://teddziuba.com/2008/08/an-article-about-startups-that.html&quot;&gt;Ted Dziuba, the uncov guy&lt;/a&gt;&lt;/ul&gt;
&lt;p&gt;
It's like he can read my mind, then swears a lot.
      </description>
    </item>
    <item>
      <title>2008-08-08: ROE</title>
      <pubDate>Tue, 05 Aug 2008 20:18:36 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#08</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#08</guid>
      <description>&lt;b&gt;ROE&lt;/b&gt;
&lt;p&gt;
Havoc Pennington has an excellent article on &lt;a
href=&quot;http://log.ometer.com/2008-08.html#3&quot;&gt;Return on Equity (ROE)&lt;/a&gt;.
      </description>
    </item>
    <item>
      <title>2008-08-06: ACPI reprise</title>
      <pubDate>Tue, 05 Aug 2008 17:12:36 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#06</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#06</guid>
      <description>&lt;b&gt;ACPI reprise&lt;/b&gt;
&lt;p&gt;
Wow, my Linux disk-related rant seems to have been &lt;a
href=&quot;http://linuxhaters.blogspot.com/2008/08/rants-and-laughs.html&quot;&gt;featured
on Linux Hater&lt;/a&gt;.  I am strangely pleased, although for the record, I
hate all computers and all operating systems, not just Linux.
&lt;p&gt;
Now, I've been advised that another hot topic right now is some kind of
ridiculous conspiracy theory about a laptop vendor who &quot;deliberately&quot; made
Linux's ACPI implementation not work on their system, while Windows works
fine.  Without going to the unnecessary effort of looking up the article or
checking any facts, I can tell you that I already &lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/167.html&quot;&gt;thoroughly
debunked all Linux-ACPI conspiracy theories&lt;/a&gt; a couple of years ago.  You
may find it either horrifying or funny.
      </description>
    </item>
    <item>
      <title>2008-08-05: Bug trackers don't work</title>
      <pubDate>Tue, 05 Aug 2008 16:18:26 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#05</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#05</guid>
      <description>&lt;b&gt;Bug trackers don't work&lt;/b&gt;
&lt;p&gt;
Weird.  The LinuxHater guy &lt;a
href=&quot;http://linuxhaters.blogspot.com/2008/08/one-bug-report-to-rule-them-all.html&quot;&gt;wrote
an article saying that wide-open bug trackers don't work&lt;/a&gt;, and said a
bunch of things that I had been planning to say.  I also made some &lt;a
href=&quot;http://alumnit.ca/~apenwarr/log/?m=200806#28&quot;&gt;related comments
earlier&lt;/a&gt;.  Here are a few more:
&lt;p&gt;
Lately, there's been some discussion about distributions like Ubuntu just
closing out massive numbers of bugs with comments like &quot;Please try it in the
new version and reopen if the bug still exists.&quot; Naturally, users are
offended by this: I played your game!  I filed a bug like you asked!  I
included reproducible test steps!  I even included a patch in some of them! 
Couldn't you &lt;i&gt;at least&lt;/i&gt; do me the basic service of running through my
reproduction steps &lt;i&gt;before&lt;/i&gt; closing the bug?
&lt;p&gt;
The answer is: no, actually, they can't.  There are way more users than
developers and testers, and those developers are assembling and tracking
bugs for &lt;i&gt;all the software that will run on your entire computer&lt;/i&gt;.  It
is just too much work to do properly.
&lt;p&gt;
Not that this justifies the crappiness; it just explains it.  My point is
you can't just say, &quot;They shouldn't have closed my bug!&quot; as if it were a
solution, because it's not.  Developers also can't say, &quot;Please just reopen
this bug if it still exists!&quot; as if it's a solution, because it's not
either.
&lt;p&gt;
So far, nobody has offered a solution that would actually work.
      </description>
    </item>
    <item>
      <title>2008-08-01: ext2resize sucks, but apparently so do I, and also a lot of other things too</title>
      <pubDate>Fri, 01 Aug 2008 22:44:28 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200808#01</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200808#01</guid>
      <description>&lt;b&gt;ext2resize sucks, but apparently so do I, and also a lot of other things too&lt;/b&gt;
&lt;p&gt;
This has not been a happy week for my desktop workstation.  It started off
good: two brand new SATA 750 GB disks to replace my old 80 GB one.  What a
difference!  Plus, this was finally the inspiration I needed to get
organized and install Linux as my base system and Windows XP in VMware,
instead of the other way around.
&lt;p&gt;
So the first thing I did was take out my 80 GB disk and put it aside for
later, in order to avoid screwing up, which is what people tend to do during
such activities.  I booted a Debian Etch CD and proceeded to set up my two
disks in a RAID-1 mirror, just like I had planned.
&lt;p&gt;
This is where I stop to complain about Debian Etch's installer.  What the
heck were you people thinking?  Steal Ubuntu's, already!  And the default
mode is to install with LVM but *not* with a RAID device backing it?  And in
order to just set up a RAID on two identical disks, you have to go through
like 25 steps in your awful installer UI?  This is really, really
disgusting.
&lt;p&gt;
&lt;a href=&quot;http://www.advogato.org/person/apenwarr/diary/17.html&quot;&gt;pphaneuf's
rule for flaming&lt;/a&gt; is that you should shut up and not complain unless you
at least know a better way to do it.  And better still, you should have
&lt;i&gt;done&lt;/i&gt; it better. Well, I have.  &lt;a
href=&quot;http://nitix.com/&quot;&gt;Nitix&lt;/a&gt;'s disk configuration stuff is fully
automatic and pretty much foolproof.  Sometimes it can be a little tricky to
wipe out a disk that already has stuff on it.  But that was on purpose. 
Other than that, it's just plain easy, and your disk gets configured with
RAID and LVM layers included even if there's only one disk, because that
makes things a heck of a lot more consistent, let alone making it really
easy to add a RAID later.
&lt;p&gt;
Anyway, I got through the painful disk installer UI after a few tries (you
have to reboot if you get it wrong!  Genius!), and installed my system, and
rebooted, and all seemed okay, for a while.
&lt;p&gt;
That's when I installed Firefox 3 and my system suddenly became prone to
huge &lt;a
href=&quot;http://shaver.off.net/diary/2008/05/25/fsyncers-and-curveballs/&quot;&gt;disk
grinding delays&lt;/a&gt;.  Every time a program started writing to the disk,
Firefox would freeze, sometimes for many seconds at once.  And Firefox 3,
you see, &lt;i&gt;also&lt;/i&gt; writes to disk, so this was no rare occurrence.
&lt;p&gt;
You see, Debian had installed my new ext3 filesystem using the kernel's
default data=ordered option.  data=ordered is one of those things that I'm
&lt;b&gt;shocked&lt;/b&gt; was allowed into the kernel at all, let alone made the
default.  Basically, it means that all relevant data will always be flushed
to disk before its journal (metadata) entries can be flushed, so your files
will never contain data that was just leftover if your computer crashes
between metadata and data updates.  Sounds great, right?  Well yes, until
you think about how you actually have to implement that.  The journal is
always flushed sequentially, so if someone calls fsync() on a file, we try
to flush its data first, then all the metadata changes that were made on
disk &lt;i&gt;up to and including&lt;/i&gt; this file's metadata.  But that metadata
leading up to this change, of course, can't be flushed until we include
&lt;i&gt;all the data related to all that metadata&lt;/i&gt;.  This is a long story, but
essentially, it makes fsync() of a 4k file turn into essentially a sync() of
your entire disk.  Result?  Firefox 3, which fsync()s like 300 times a
minute for no good reason, grinds to a halt.  And your system performance is
craptastic because basically your disk's write cache is gone.
&lt;p&gt;
After reading the &lt;a
href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=421482&quot;&gt;mostly retarded
discussion in the Bugzilla case&lt;/a&gt;, I gave up on the Firefox guys actually
fixing the problem anytime soon.  fsync() slightly less often??  That's a
fix?? What part of &quot;every time I fsync() it syncs ALL outstanding
transactions immediately to disk&quot; do you not understand?
&lt;p&gt;
So, I made a shared library called libnofsync.so that just makes fsync() do
nothing, and used LD_PRELOAD to load that into firefox.  By bookmarks are
not a bloody ACID database!  Nobody cares if they get corrupted!  I only
ever visit like three sites, and two of them are GMail! Get over it.  With
this hack, I suppose my Linux Firefox 3 is probably the fastest one around,
because data=ordered or not, everybody else is doing &lt;b&gt;multiple synchronous
disk writes every time they try to load a page&lt;/b&gt;.  Good grief.
&lt;p&gt;
The next task is to get rid of the completely obnoxious data=ordered
setting, which involved messing in my grub configuration file(s).  Grub, if
you haven't heard me rant about it before, is a total complete pukefest.  It
does absolutely nothing of value that lilo doesn't do, but it does it in a
way that's about 1000x more complicated.  Then Debian layers another pile of
crud on top.  The long and the short of this is that I COULD NOT FIND A WAY
to add &quot;rootflags=data=writeback&quot; to my kernel command line in any sort of
permanent fashion.  Now, you can edit the kernel command line during boot,
and there's an option right there that says &quot;savedefaults&quot; that sounds
promising but does absolutely nothing, but (at least) one of the 1000 layers
of garbage shoveled on top of grub overwrites and/or ignores my config file
changes no matter how I try to make them.
&lt;p&gt;
So I uninstalled grub and installed lilo, after which things were trivially
easy because lilo was not written by morons.
&lt;p&gt;
Around this time I tried out a 2.6.25 kernel from backports.org, which
happily crashed my system repeatedly.  What the heck was I thinking?  The
kernel hasn't actually been missing any significant features for something
like five years.  I don't know why I upgraded it, but I sure won't make
&lt;i&gt;that&lt;/i&gt; mistake again.  Anyway, the crashes served mostly to teach me
that if you crash your system while the RAID is rebuilding, it might not
come back all by itself.  Instead, it silently kicks the second disk from
the RAID and leaves it idle, without actually telling anyone about this
&lt;b&gt;INCREDIBLY SERIOUS RELIABILITY LOSS&lt;/b&gt;.  But that's par for the course
by now.  I added it back into my array and off I went.
&lt;p&gt;
Fast forward to a few days later; it took some suffering before I bothered
to fix the firefox nonsense and got sick enough of the random kernel crashes
to downgrade my kernel back to Debian's stable version.&lt;sup&gt;(1)&lt;/sup&gt;
&lt;p&gt;
That was about when I noticed that my new, fancy-pants RAID was rebuilding
at 80 MB/sec, which is fabulously quick, and yet had still not
&lt;i&gt;finished&lt;/i&gt; rebuilding, after being left uninterrupted for more than a
day.  What?  Well, let's &quot;watch cat /proc/mdstat&quot;.  Hey, check it out!  It's
almost done!  98%... 99%... 100%... 100%... 100%... 0%?  Hey!  What the heck
is this!  Okay, look at dmesg.  Aha, it had a bad sector right at the very
end of the disk!
&lt;p&gt;
And so it decided to start rebuilding the RAID from scratch!
&lt;p&gt;
About once an hour since I installed it at the beginning of the
week!&lt;sup&gt;(2)&lt;/sup&gt;
&lt;p&gt;
HA HA HA HA!
&lt;p&gt;
Now, that's not actually something that would solve the problem even if I
had bad sectors.  But of course, I don't &lt;i&gt;really&lt;/i&gt; have any bad sectors. 
What I do have is some partitions that apparently Debian's installer screwed
up while creating, so they happily run right past the end of the disk.
&lt;p&gt;
Now okay, Debian's partitioning thingy has an excuse for being buggy;
probably nobody ever uses it to make a RAID, because it's sure the heck not
easy to do.  But here's the thing: mdadm let me create a RAID on a partition
with inaccessible sectors.  Then mke2fs let me create a filesystem on that
broken RAID.  Did it not occur to anyone to sample a few of the sectors
before you decided to actually use them?  Didn't any of you ever wonder why
Windows does that weird thing about &quot;testing sector accessibility&quot; whenever
you make a partition?  No, apparently not.  Gargle.
&lt;p&gt;
Okay, so obviously I need to make my partition a little smaller.  Apparently
it's possible to resize ext3 partitions and RAID devices now.  That's good
news, right?  Well sure!  Let's try that!
&lt;p&gt;
So I switched down to single user mode, remounted my rootfs read only, and
ran &quot;ext2resize /dev/md0&quot;.  It told me a magic number, which is the number
of sectors it's currently using.  I reduced that number by an overly large
factor (hey, I've got whole gigabytes of data to waste here!) and ran
&quot;ext2resize -v /dev/md0 NUMBER&quot;.  It grinded away for a while, giving me
impressive yet scary messages about how it was moving inodes around, and so
on.  I figured it couldn't really do anything &lt;i&gt;too harmful&lt;/i&gt;, since
obvously the space at the end of the disk was nowhere near any of my actual
data.
&lt;p&gt;
Boy, was I ever wrong.
&lt;p&gt;
I foolishly then ran &quot;ext2resize /dev/md0&quot; again to see if it would print
out the new size.  Except, it seems, that's not what it does.  What it does
is try to resize the partition again, this time to the maximum size.  The
maximum size is, as you recall, a size that involves some nonexistent
sectors at the end of my partition.
&lt;p&gt;
So it moved a few more inodes around and then errored out.  Ironically,
ext2resize &lt;i&gt;does&lt;/i&gt; apparently access that area at the end of the disk,
even if mke2fs doesn't.  Sadly however, it moves a bunch of crap around
before erroring out and aborting midstream.
&lt;p&gt;
You might have imagined, as I might have, once, that ext2resize would maybe
do a &quot;hypothetical resize&quot; operation, going all the way through the disk and
confirming that everything would work - like the last sector it was about to
resize into, for example - before it actually starts moving crap around.  Or
you might have imagined that it would undo those changes before it aborts
due to an unexpected error.  But if you thought that, then you, like me,
would have been &lt;b&gt;completely wrong&lt;/b&gt;.  ext2resize does no such thing. 
Instead, it moves a bit of data around, and then aborts when it gets
confused, halfway through the process.
&lt;p&gt;
As I learned, this makes your filesystem completely unusable.  It turns out
that, for no reason I can possibly imagine, moving around the completely
empty unused section at the very end of my disk also involves rewriting
inode 2 (which turns out to be the root directory), as well as an impressive
number of other I-woulda-thought unrelated files and inodes.  Of course,
when you do this &lt;i&gt;wrong&lt;/i&gt;, your filesystem stops mounting.
&lt;p&gt;
Time to boot the rescue disk one more time, pray a little, run e2fsck, and
pray a little more.
&lt;p&gt;
e2fsck was not impressed.  It correctly noted that inode 2 was, if I recall,
&quot;conflicted.&quot;  Also lots of other horrible things.  I asked it to repair
everything.  It crashed.  Well, of course, it didn't &lt;i&gt;crash&lt;/i&gt; exactly. 
It printed messages about &quot;programmer error??&quot; and then restarted the game
all over again.  I actually went through the game a few times before I
finally caught on to the fact that it was the same every single time.
&lt;p&gt;
Luckily, when I bravely answered &quot;no&quot; to all the questions about whether it
should fix things, it finally fixed things&lt;sup&gt;(3)&lt;/sup&gt;, complained that Oh
God Your Filesystem is Still Broken Though, and exited.  But whatever, my
filesystem finally mounted again.  I had to recover all my root-level
folders from their new homes in /lost+found, but oh well, at least I still
had my data.
&lt;p&gt;
And so I rebooted, and my RAID promptly started rebuilding itself again, and
my filesystem was still corrupt, and it couldn't actually be fsck'd because
e2fsck would still go into an infinite loop if I tried.  Back to square
one.
&lt;p&gt;
And now, this is the part where I flame myself, because I forgot something I
already learned a long time ago and then sold to thousands of people:
&lt;p&gt;
Why the heck are you using a RAID in the first place, when you only have two
disks, idiot?  If you only have two disks, just back up your files to the
second disk occasionally using rsync or &lt;a
href=&quot;http://kb.nitix.com/1348&quot;&gt;something&lt;/a&gt;.  That way, when you
ext2resize or just delete a file by accident, the other disk doesn't reflect
your idiotic mistakes until a while later.  Remember?
&lt;p&gt;
So there you have it.  All those things were dumb, but I was the dumbest of
them all.
&lt;p&gt;
I dropped the second disk out of my RAID, repartitioned it correctly, ran
mke2fs, copied all the files to the second disk, and booted from that. 
Done.
&lt;p&gt;
&lt;b&gt;Actual Nice Things to Say&lt;/b&gt;
&lt;p&gt;
Lest it appear that I only hate things:
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; Yes, Debian's stable 2.6.18 kernel actually works, and thus
there's actually a reason they don't carry the highest-numbered one.  Good
job, guys.
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; The guys who implemented the CFQ disk scheduler are my
heroes.  Unlike in the 2.4 kernel, where rebuilding your RAID hugely
degraded your system performance, in 2.6 this operation happens at &quot;idle&quot;
disk priority so it can go at pretty much full speed and yet have
&lt;i&gt;zero&lt;/i&gt; impact on your disk performance.  That's why I didn't even
notice for &lt;i&gt;days&lt;/i&gt; that the rebuild was going on.  Related tool: &lt;a
href=&quot;http://linux.die.net/man/1/ionice&quot;&gt;ionice -c3&lt;/a&gt;.  Use it for your
background compiles and stuff.  It's awesome.
&lt;p&gt;
&lt;sup&gt;(3)&lt;/sup&gt; You know what?  I'm a big fan of e2fsck, even though it's
supremely un-user-friendly and obviously had some bugs here.  But despite
those bugs, it didn't abort when it thought it had a &quot;programmer error,&quot; and
it &lt;b&gt;saved my data&lt;/b&gt; from what I was sure by then was certain death.  No
program is perfect, but at least this one was written by sane people.
      </description>
    </item>
    <item>
      <title>2008-07-22: iPhone 3G</title>
      <pubDate>Tue, 22 Jul 2008 18:52:15 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200807#22</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200807#22</guid>
      <description>&lt;b&gt;iPhone 3G&lt;/b&gt;
&lt;p&gt;
&quot;If you've ever wondered what Apple will be like after Steve leaves and
they've got visionaries like Phil Schiller and Tim Cook running the place,
well, now you've seen the trailer. The movie will be worse.&quot;
&lt;p&gt;
-- &lt;a
href=&quot;http://realdanlyons.com/blog/2008/07/22/hello-cruel-world/&quot;&gt;Dan
Lyons&lt;/a&gt; (aka Fake Steve Jobs) on the iPhone 3G release
      </description>
    </item>
    <item>
      <title>2008-07-17: It lives</title>
      <pubDate>Fri, 18 Jul 2008 00:05:12 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200807#17</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200807#17</guid>
      <description>&lt;b&gt;It lives&lt;/b&gt;
&lt;p&gt;
The company that I co-founded and eventually left lives on as &lt;a
href=&quot;http://lotusfoundations.com/&quot;&gt;Lotus Foundations&lt;/a&gt;.
&lt;p&gt;
There's even a guy &lt;a
href=&quot;http://blog.garethhowell.com/archive?openview&amp;type=cat&amp;cat=Lotus%20Foundations&quot;&gt;blogging
about it&lt;/a&gt;.  (He includes some screenshots of the new webconfig and boot
screens.  The webconfig update looks quite classy.&lt;sup&gt;(1)&lt;/sup&gt;
&lt;p&gt;
It was also &lt;a
href=&quot;http://ross.typepad.com/blog/2008/01/lotusphere-open.html&quot;&gt;featured in
the keynote at Lotusphere 2008&lt;/a&gt;.
&lt;p&gt;
And speaking of things that aren't dead, I discovered all these links using
the beta of &lt;a href=&quot;http://pressflip.com/&quot;&gt;Pressflip, formerly Persai&lt;/a&gt;,
a surprisingly non-sucky news engine from the guy who made &lt;a
href=&quot;http://valleywag.com/347261/valleywag-kills-uncov-once-and-for-all&quot;&gt;uncov&lt;/a&gt;. 
I'm not usually impressed by Web 2.0 startups, to say the least, but this
one is pretty cool.  Check it out.
&lt;p&gt;
&lt;b&gt;Footnote&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt;  The boot screen is less classy; when they changed the
&quot;Nitix - Autonomic Linux&quot; title in syslinux to say &quot;Lotus Foundations&quot;, they
centered it incorrectly, probably because they counted the colour code bytes
as visible characters.  Probably nobody else would ever notice this, except
that I've done it myself in the past.
      </description>
    </item>
    <item>
      <title>2008-07-04: Risk vs. Calculated Risk</title>
      <pubDate>Wed, 02 Jul 2008 15:54:11 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200807#04</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200807#04</guid>
      <description>&lt;b&gt;Risk vs. Calculated Risk&lt;/b&gt;
&lt;p&gt;
It's accepted knowledge that potential returns in business are greater if
you're willing to take on more risk.  That is, a &quot;safe&quot; investment with
guaranteed payoff will generally offer less than an &quot;unsafe&quot; investment that
might fail.  And so, if you have lots of money, as the wisdom goes, you
might want to invest it in a wide variety of risky investments in order to
collect some of that potential gain.  The idea is that even if some of the
risky investments fail, the increased profits from the non-failing ones
should more than pay for the loss.
&lt;p&gt;
Okay, so far so good, but the problem with risk is that it's &lt;i&gt;random&lt;/i&gt;. 
And worse, there are a lot more worthless risky investments than valuable
ones; such is the state of humanity.  (In contrast, &quot;safe&quot; investments, by
definition, don't really have that problem.)
&lt;p&gt;
Enter the concept of a &quot;calculated risk.&quot;  The idea here is that if you're
careful, you'll be able to see which risky investments are better, and thus
collect on the returns instead of losing all your money.
&lt;p&gt;
But there's a problem with that theory.  The problem is that if everyone
could just figure out what's a &quot;good risk&quot; vs. a &quot;bad risk,&quot; then everyone
would want to invest in the same things.  Thanks to supply and demand, this
basically sucks the profit out of such obvious investments.  Various
problems with fancy hedge funds and the recent subprime crisis can all be
traced to this problem: everyone agreed that a particular risk was &quot;good&quot; at
the same time, and over-invested in it until the profit was gone.
&lt;p&gt;
But wait!  If supply and demand can suck the life out of risky invements,
what makes risk such a great thing, again?
&lt;p&gt;
My entrepreneurship professor in university used to say that a better term
for calculated risk would be &quot;risky calculation,&quot; because that puts more
emphasis on calculation than on risk.  And the more I learn about business,
the more I realize how absolutely right that is.  Profits don't come from
risk.  Of course they don't!  Who wants to buy pure risk, except compulsive
gamblers?  Profits actually stem from the quality of the investment, and you
can buy into an investment at a good price &lt;i&gt;only when other people
don't&lt;/i&gt;.  Perceived risk is just one possible reason that people might
avoid a particular high-quality investment.
&lt;p&gt;
I don't have huge boatloads of money, so I don't usually think about
investing from the point of view of investing money.  I think more about
where to invest my time, because my time is the most valuable thing I have. 
Right now, the &lt;i&gt;cool&lt;/i&gt; thing for a programmer like me to do is to form a
web startup.  But I'm not doing that, because the space is &lt;i&gt;risky&lt;/i&gt; and
&lt;i&gt;overinvested&lt;/i&gt;.  It's completely wrong on both axes.  If you want to be
successful in the market right now, do something &lt;i&gt;safe&lt;/i&gt; and
&lt;i&gt;underserved&lt;/i&gt;.
      </description>
    </item>
    <item>
      <title>2008-07-02: Toronto Fringe Festival Suggestions</title>
      <pubDate>Wed, 02 Jul 2008 15:54:05 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200807#02</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200807#02</guid>
      <description>&lt;b&gt;Toronto Fringe Festival Suggestions&lt;/b&gt;
&lt;p&gt;
Congratulations, Torontonians, your &lt;a
href=&quot;http://www.fringetoronto.com/fringe08/harolds08.html&quot;&gt;Fringe
Festival&lt;/a&gt; starts today and runs until July 13th.  Since a lot of shows
tour from East to West and Montreal is the first one of the season, my
friend Elaine asked me to recommend some good shows based on what I saw in
Montreal.  So my good deed for today will be to offer you some
assorted preview reviews:
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Blastback Babyzap.  Go see it.  It's by Uncalled For.  QED.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Teaching the Fringe, by Keir Cutler.  Except that Dr. Cutler won't be able to make it to &lt;b&gt;your&lt;/b&gt; fringe, so Barry Smith, of Barry Smith's Baby Book (not to be seen in Toronto), will be doing the show on his behalf.  That's a bit strange, because both Teaching the Fringe and Baby Book are autobiographical, and so now Barry is doing someone else's autobiography. Oh well, both of them were good.  You might as well give it a shot.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;American Squatter, also by Barry Smith.  Apparently it was popular.  I didn't see it, but Smith himself is pretty funny.  Who knows?
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;'Beth.  As advertised.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Transcendental Masturbation.  Not as advertised.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Wonderbar! and Balls!  Both titles are exclamatory, but both shows I missed.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;The Diaries of Adam and Eve.  Luckily for you, it's cancelled.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;The Tricky Part.  Didn't see it, heard it was awesome.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Die Roten Punkte.  Go see this.  Really.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Telegrams from the New Canadian Cinema.  Didn't see it.  Heard nothing about it.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Time to Put my Socks On.  Be sure you know what you're getting into.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Crude Love.  Reputedly good.  I didn't see this one either.  Gee, I'm starting to sense a pattern here.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Greed.  Well done.  Time-twisted plot exposition.  Cute girls.&lt;br&gt;&lt;b&gt;Update 2008/07/02:&lt;/b&gt; Hmm, I've been told there was only one girl.  Anyway, she had many cute outfits.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Jem Rolls.  Dude, it's &lt;i&gt;Jem Rolls&lt;/i&gt;.  Of course you have to go see him.  If you don't know why, then you have to go see him &lt;i&gt;even more&lt;/i&gt;.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Mating Rituals of the Urban Cougar.  Pretty good, especially the songs.  Unless I got it mixed up with something else, that is.  Actually, I'm pretty sure I did.  Well, it was pretty good anyway, I think.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;The Spy.  This came to Montreal for a one-night show.  The guy was super nervous and unfortunately it showed.  But the show was otherwise excellent, and if he can get into his groove, it'll be awesome.  Maybe wait for a later showing just in case.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Totem Figures, by the increasingly infamous TJ Dawe.  The guy talks at top speed for 90 minutes and doesn't forget any lines.  Worth seeing just for that, although he seems a little oversold to me.  Reputedly the only guy to ever make a full-time career out of doing fringe shows.
&lt;/li&gt;
&lt;/ul&gt;
And two troupes with three shows that you won't be seeing because they're
not coming to Toronto but they're so awesome that I have to mention them
anyway:
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Identity Crisis by &lt;a href=&quot;http://influxdance.org/&quot;&gt;Influxdance&lt;/a&gt;.  More serious and scaled down than previous years, but still excellent.  Sadly, they seem to be done for the summer.  Too bad.
&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;The &lt;a href=&quot;http://www.codyrivers.com/&quot;&gt;Cody Rivers Show&lt;/a&gt;: Stick to Glue, and Boom (by one guy from the Cody Rivers Show).  Neither of the members is named Cody Rivers, but they're both awesome.  Looks like they'll be in Edmonton, if you're lucky enough to live there, or Minnesota, if you're not.
&lt;/li&gt;
&lt;/ul&gt;
And by the way, if you're going to the Toronto fringe, make sure you mention
to them how lame the Fringe Donation Buckets system is, where you basically
have salespeople nagging you while you line up for every single show. 
Please, please, if your fringe festival is going to collapse without these
donations, then just charge a service fee per ticket like they do in
Montreal.  Seriously, guys.  It's either optional or it's not.  Stop
harassing me already.  You want people to go to &lt;i&gt;more&lt;/i&gt; shows, but the
lineup harassment gets &lt;i&gt;less&lt;/i&gt; fun every time.
&lt;p&gt;
But all that said... you Torontonians have a great selection of shows
waiting for you, including a huge number that didn't make it to Montreal. 
Have fun fringing!
&lt;p&gt;
&lt;a href=&quot;http://advogato.org/person/apenwarr/diary/134.html&quot;&gt;Previously.&lt;/a&gt;
&lt;p&gt;
&lt;b&gt;Update (2008/07/02):&lt;/b&gt; jnc has &lt;a
href=&quot;http://joenotcharles.livejournal.com/111758.html&quot;&gt;some alternative
opinions&lt;/a&gt;.
      </description>
    </item>
    <item>
      <title>2008-06-30: A serious case of JustOneMoreBug</title>
      <pubDate>Sun, 29 Jun 2008 19:29:23 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#30</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#30</guid>
      <description>&lt;b&gt;A serious case of JustOneMoreBug&lt;/b&gt;
&lt;p&gt;
I just read &lt;a
href=&quot;http://www.goertzel.org/benzine/WakingUpFromTheEconomyOfDreams.htm&quot;&gt;Waking
Up from the Economy of Dreams&lt;/a&gt;, a pleasant essay about how Webmind, Inc.
went bankrupt in 2001 while trying to invent artificial intelligence.
&lt;p&gt;
The essay is an interesting read, mainly because the author seems to have
come out of the experience so... innocently.  We were 3/4 of the way to a
real, working AI, he insists near the end of the story.  It was just bad
luck that we ran out of money right as the .com bubble burst...
&lt;p&gt;
You might almost be able to believe him, except he also told the rest of the
story.  The original development was supposed to take a &lt;i&gt;few months&lt;/i&gt;. 
To build the first sentient AI!  Unsurprisingly (to me), it took longer than
expected.  They actually ran out of money multiple times in the process, but
managed to land financing at the last minute each time.  (Incidentally, that
sounds to me like a long string of &lt;i&gt;good luck&lt;/i&gt; that finally ended, not
any &lt;i&gt;bad&lt;/i&gt; luck at all.)
&lt;p&gt;
But okay, lots of startups almost run out of money, and just about everyone
underestimates the amount of work involved in their project.  So what?
&lt;p&gt;
Well, the problem is that these guys &lt;i&gt;felt sure&lt;/i&gt;, at each failure along
the way, that they were just one step away from having it finally work.  And
when they finished that step and it still didn't work?  Well, &lt;i&gt;now&lt;/i&gt;
we're just one step away.  We're almost there.  We can feel it!
&lt;p&gt;
At NITI, we called this the JustOneMoreBug syndrome, spelled using WikiCaps
because it was a page in our wiki.  It seems now that we must have been the
ones to invent that term, since I can't seem to find it in Google anywhere. 
So with that in mind, I guess I'd better tell you what it is:
&lt;p&gt;
First of all, the fact that this was featured in our internal wiki probably
tells you something about our experience with it: ie. we had
plenty.&lt;sup&gt;(1)&lt;/sup&gt; JustOneMoreBug is exactly what it sounds like: the
feeling that if you can just fix this one last bug, your software will work
perfectly, customers will come flocking to you, and riches will inevitably
ensue.
&lt;p&gt;
The frustrating thing about JustOneMoreBug is that every successful project
&lt;i&gt;does&lt;/i&gt; have a moment exactly like that: the transition from
unreleasable to releasable, from unusable to usable, from unsellable to
sellable.  And so if you're an optimist, you, like us, would prefer to
believe that this bug is your one last bug.  And maybe it is.
&lt;p&gt;
Unless it's not, which becomes clear one way or the other shortly after you
fix it.  Then what?
&lt;p&gt;
Then, if you're experiencing the JustOneMoreBug &lt;i&gt;syndrome&lt;/i&gt; as opposed
to the JustOneMoreBug &lt;i&gt;major life-changing event&lt;/i&gt;, you realize that
there's just... one more bug holding you back.
&lt;p&gt;
Fool me once, shame on you.  Fool me twice, shame on me.  You can get away
with claiming JustOneMoreBug once or twice per project - but if you go past
that, you have to stop and rethink.  Why are there so many bugs that &lt;i&gt;you
don't even know about yet&lt;/i&gt;?  Believe it or not, really good programmers
will write programs that &lt;i&gt;mostly&lt;/i&gt; work the first time, and the parts
that don't work can fairly easily be uncovered and solved.  If your program
is fooling you about how stable it is, it's because your program isn't very
good.  You need to stop and find a new strategy: often, by doing some heavy
testing and using the results to build a brand new multi-month development
schedule.  That's bad news, because the project was supposed to be done
tomorrow.  After all, there was just one bug left.
&lt;p&gt;
Webmind was on a multi-year marathon of JustOneMoreBug.  I feel sorry for
them, because advanced research has a strong tendency toward that;
structured engineering principles just don't work for software
&lt;i&gt;research&lt;/i&gt; projects.  But it seems like their investors didn't realize
they were &lt;i&gt;doing&lt;/i&gt; software research, and their researchers honestly
didn't realize - repeatedly - that the JustOneMoreBug feeling is just a
&lt;i&gt;feeling&lt;/i&gt;, not a reality.  And if the essay is any indication, they
still don't realize it; they still think they were almost there.
&lt;p&gt;
At least they didn't come out cynical.
&lt;p&gt;
&lt;b&gt;Footnote&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; NITI had two kinds of JustOneMoreBug experience.  First, with
certain internal software projects (which is normal occasionally in any
software company, although if we'd been smarter we would have caught them
sooner).  And second, with our business model: even if your product
&lt;i&gt;works&lt;/i&gt;, if it's not selling as well as it should, there's a strong
tendency to believe that you just need to tweak &lt;i&gt;one more thing&lt;/i&gt; about
your business and it'll take off.  But just like with software, you
shouldn't fall for this trick more than once or twice.  We fell for it
repeatedly, and that was our multi-year marathon.  (Eventually the winning
fix wasn't a tweak.  It was a complete re-analysis and redefinition of our
target market, and a corresponding total change in the way we dealt with
customers and resellers.)
      </description>
    </item>
    <item>
      <title>2008-06-28: Weird things about git, #2: no bug tracking system</title>
      <pubDate>Fri, 04 Jul 2008 10:53:42 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#28</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#28</guid>
      <description>&lt;b&gt;Weird things about git, #2: no bug tracking system&lt;/b&gt;
&lt;p&gt;
The git developers don't track bugs.  If you find a bug, you can write about
it on the mailing list.  You might get flamed.  And then probably someone
will ask you to fix it yourself and send in a patch.
&lt;p&gt;
This is unlike almost all other open source projects.  Virtually every
project out there has a basic bug tracking system attached, courtesy of
SourceForge or Google Code or whatever.  It's a key part of the development
process, right?
&lt;p&gt;
Well, not exactly.
&lt;p&gt;
I'm also following the development mailing list for Mono.  It has
&lt;i&gt;much&lt;/i&gt; less traffic than git, which is weird, because at least by lines
of code (and probably number of users), Mono is a &lt;i&gt;way&lt;/i&gt; bigger project. 
One of the reasons for the quiet is their bug tracking system.  It's a
conversation killer.  Like this:
&lt;p&gt;
Someone reports a bug on the mailing list.  &quot;Please file it in the bug
tracker.&quot;  &quot;I can't figure out how to create a bugzilla account.&quot;  &quot;Do it
like this.&quot;  &quot;Okay, I created the account, but I can't figure out how to
file a bug.&quot;  &quot;Do it like this.&quot;  &quot;Okay, I filed the bug.  Now what?&quot;  &quot;Now
hopefully someone will fix it someday!  Bye!&quot;
&lt;p&gt;
So people aren't supposed to discuss bugs on the mailing list, which begs
the question: what &lt;i&gt;are&lt;/i&gt; they supposed to discuss on the mailing list? 
Nobody really knows.  So the conversation dies.  And not everybody sees
every bug that comes in.  Which is probably good, because there are
thousands of bugs filed, and as with most open source projects (and
commercial ones, for that matter), most of the bugs never get fixed, because
volunteers just aren't actually very interested in fixing every last one of
your problems.  (This isn't to say the Mono developers don't fix tons of
bugs.  Mono is awesome.  But it seems to be a cardinal rule of bug tracking
that the bug database only grows, it never gets smaller.)
&lt;p&gt;
Let's be honest: bug tracking sucks the joy out of software development. 
git developers just work on whatever scratches their itch at that particular
moment.  If the same question comes up too often on the mailing list, they
update the documentation.  If people report a bug, they quiet those people
by fixing the bug (or convincing those people to fix the bug).  If they feel
like implementing a new feature today, then they just do.  And with multiple
examples of this happening every single day, it's easy and fun to subscribe,
get a feel for what's happening, and join in.
&lt;p&gt;
When you work to a bug tracking system, you're just doing what you're told. 
Some poor bug tracking janitor spends hours each day shoveling bugs around
inside the system and assigning them to people and prioritizing which ones
go into which release.  Then the developers line up and take their bugs, and
work on them in sequence so that the release can go out at the pre-ordained
time.
&lt;p&gt;
git developers just make a code freeze branch sometimes and let it simmer
for a while, then release it.  Junio C Hamano is the equivalent of the bug
shoveler for git, except he doesn't shovel &lt;i&gt;bugs&lt;/i&gt;: he shovels
&lt;i&gt;fixes&lt;/i&gt;.  I expect that's a much more gratifying job.
&lt;p&gt;
&lt;b&gt;Update (2008/06/30): &lt;a
href=&quot;http://news.ycombinator.com/item?id=231558&quot;&gt;YCombinator News&lt;/a&gt; has
some commentary on this article.&lt;/b&gt;
      </description>
    </item>
    <item>
      <title>2008-06-25: How to tell the gcc maintainers are all (still) lunatics</title>
      <pubDate>Thu, 26 Jun 2008 21:57:43 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#25</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#25</guid>
      <description>&lt;b&gt;How to tell the gcc maintainers are all (still) lunatics&lt;/b&gt;
&lt;p&gt;
Just got bitten by &lt;a
href=&quot;http://unix.derkeiler.com/Mailing-Lists/FreeBSD/current/2007-05/msg00650.html&quot;&gt;this
insanity&lt;/a&gt; today.
&lt;p&gt;
There's not being backwards compatible, and then there's... that.  What was
the point of upgrading, again?
      </description>
    </item>
    <item>
      <title>2008-06-24: Weird things about git, #1: premature optimization</title>
      <pubDate>Wed, 25 Jun 2008 00:06:46 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#24</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#24</guid>
      <description>&lt;b&gt;Weird things about git, #1: premature optimization&lt;/b&gt;
&lt;p&gt;
I've been hanging out on the git mailing list for the last little while, and
a few things have been striking me as weird.  There are hundreds of people
on that list, and lots of them are active contributors.  Why?  It's &lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/371.html&quot;&gt;just a stupid
version control system&lt;/a&gt; after all.
&lt;p&gt;
But there must be some reason.  I've thought of a few.  Here's one for
today:
&lt;p&gt;
The git developers are &lt;i&gt;completely obsessed&lt;/i&gt; with performance.  Apparently
nobody there has ever heard that &quot;premature optimization is the root of all
evil.&quot; (Incidentally, the ACM has &lt;a
href=&quot;http://www.acm.org/ubiquity/views/v7i24_fallacy.html&quot;&gt;a recent article
explaining why that statement is a fallacy&lt;/a&gt;.)
&lt;p&gt;
It's enlightening just to watch the git developers optimize every
possible part of their system: syscall overhead, memory allocation, path
trees, file size, network turnarounds, etc.  And even while they optimize
the heck out of everything, they still complain about how inefficient it all
still is.  Which it is, of course, if you follow the discussions.
&lt;p&gt;
Also interesting is that large parts of git are written in sh and perl and
it's &lt;i&gt;still&lt;/i&gt; fast, because while they obsess about performance, they
also know which parts actually matter to performance.  It helps to be a
Linux kernel developer sometimes, I guess.
&lt;p&gt;
There's no doubt that git's optimization is premature: it &lt;i&gt;started out&lt;/i&gt;
way faster than svn, and it gets even faster with each release.  Is that
really necessary?  Of course not.  Everyone was doing just fine with things
like svn.  But life is just so much &lt;i&gt;better&lt;/i&gt; when programs go
unnecessarily fast.  It's a very strange sensation; pain you didn't realize
you were having just goes away.  I've been doing a lot of Windows
development lately, and let me tell you, Windows developers have a whole lot
of pain that they don't realize they have, because it's not overt.  Windows
development is mostly fine, really.  But what kills it is all
the little random delays, the crashes, the giant memory-leaky .Net-based
IDEs that make you point-and-click fifty things sequentially once a week
because you don't have a way to write a script to do it for you.  Just give
me a text editor and 'make' any day, thanks.
&lt;p&gt;
What was my point again?  Oh right, unnecessary optimization.  While I've
been writing this article, I've been waiting for svn to finish committing
20000 tiny files to a fresh svn repository.  It's still not done.  (Watching
a strace of this is hilarious.  Among other things, it's creating an XML
file for every single one.)
&lt;p&gt;
...
&lt;p&gt;
And for comparison, git just did the same thing in 23 seconds.  (About half
that time was spent running my shell script to create 20000 files.)
&lt;p&gt;
Who cares?  How often do you create a repo with 20000 tiny files in it
anyway?  Almost never, of course.  It's not an important optimization goal. 
&lt;p&gt;
...
&lt;p&gt;
svn finally finished.  See?  That wasn't so bad.
      </description>
    </item>
    <item>
      <title>2008-06-05: I Am Of Literary Significance</title>
      <pubDate>Mon, 02 Jun 2008 22:55:05 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#05</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#05</guid>
      <description>&lt;b&gt;I Am Of Literary Significance&lt;/b&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.suite101.com/article.cfm/classic_literature/67104&quot;&gt;Oh
yes&lt;/a&gt;.  &lt;a
href=&quot;http://jostamon.blogspot.com/2008/05/snark-was-boojum.html&quot;&gt;Fear
me&lt;/a&gt;.
&lt;p&gt;
Stupid internet.
&lt;p&gt;
(The rather dull &lt;a href=&quot;http://alumnit.ca/~apenwarr/log/?m=199506&quot;&gt;ancient
high school essay that started it all&lt;/a&gt;.  But &lt;a
href=&quot;http://alumnit.ca/~apenwarr/log/?m=199503&quot;&gt;this is better&lt;/a&gt;.  Or &lt;a
href=&quot;http://alumnit.ca/~apenwarr/log/?m=199502&quot;&gt;maybe this&lt;/a&gt;.)
      </description>
    </item>
    <item>
      <title>2008-06-03: So... what do *you* do?</title>
      <pubDate>Mon, 02 Jun 2008 14:34:59 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#03</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#03</guid>
      <description>&lt;b&gt;So... what do *you* do?&lt;/b&gt;
&lt;p&gt;
I got married a couple of weeks ago.  We and our guests planted some trees:
&lt;p&gt;
&lt;div align=center&gt;&lt;img
src=&quot;http://lfpress.ca/gallery/2437/photos/LDN20080517dr_tree.jpg&quot;&gt;&lt;br&gt;&lt;font
size=-1&gt;Me
getting married.  Via the &lt;a
href=&quot;http://www.lfpress.com/perl-bin/publish.cgi?x=articles&amp;p=234045&amp;s=pets_nature&quot;&gt;London Free
Press&lt;/a&gt;.&lt;br&gt;Also note Peter, Luke, Ed,
and Anna.&lt;/font&gt;&lt;/div&gt;
&lt;p&gt;
But wait, I'm getting ahead of myself.  The story goes something like this:
&lt;p&gt;
Erin and I got engaged shortly after she went tree planting last year.  (I
had been too lazy to get up early.) We thought it would be fun to have a
tree planting at our wedding, so we set about trying to find a wedding site
that would let us plant trees.  Alas, there were none.  But one of Erin's
friends referred her to a berry farm out in the wilderness somewhere, which
we visited and decided it would make a fitting wedding location.  Sadly,
they already had plenty of trees.  We proceeded to the local coffee shop
(there's only one) to discuss our strategy.  I asked someone there, &quot;So,
let's say you happened to have a bunch of trees that needed planting.  What
would you do?&quot; She looked at me seriously, thought about it for a second,
and said, &quot;How many?&quot;
&lt;p&gt;
A couple days later, she set up a meeting for us with a local lady, Barbara,
who happened to be planning to reforest some of her family's historical
farmland with trees that originally grew in the area.  (In Southern Ontario,
many of the original forests were clear cut and converted to farmland, so a
lot of the original species are getting pretty rare.)
&lt;p&gt;
We agreed that her land would be a great place for our tree planting, and
she said she'd name it &quot;Erin's Dell.&quot;  She offered to pay for the trees.  I
said no, no, that's okay, we couldn't ask you to do that.  Instead she
formed a charitable foundation, got donations, and had the Ontario
government match them so that Erin and I ended up paying nothing.  She also
picked the trees, hired a landscaper, got a local lady to bake fresh bread,
and had everything ready for us the day we arrived.
&lt;p&gt;
Oh, also, it turns out that before she retired she specialized in public
relations and marketing, so she could hardly resist issuing a press release. 
That's probably why the London Free Press showed up at our wedding (where
our guests, by the way, were doing almost all the actual digging/planting
work) and took the photo featured above.  A couple of smaller local papers
picked up the story as well.
&lt;p&gt;
So what's the point of this story?
&lt;p&gt;
Well, when you meet people, one of the first questions they always ask is,
&quot;What do you do?&quot; Erin finds this question annoying, because it isn't the
right question.&lt;sup&gt;(1)&lt;/sup&gt; 
&lt;p&gt;
Ask yourself instead: if it weren't for her, how much of the above would
have happened?
&lt;p&gt;
&lt;b&gt;Footnote&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; It's not actually the right question for me either.  When I
answer &quot;I'm a Computer Engineer!&quot; most people's eyes instantly glaze over
and the conversation ends.  That's not supposed to be the purpose of small
talk, so I usually dodge the question too nowadays :)
&lt;p&gt;
&lt;b&gt;Epilogue&lt;/b&gt;
&lt;p&gt;
And then our honeymoon in &lt;a href=&quot;http://www.saltspringisland.org/&quot;&gt;Salt
Spring Island&lt;/a&gt;, BC, was almost entirely organized by Juli, my bus driver
from high school.  I am not making this up.
      </description>
    </item>
    <item>
      <title>2008-06-02: A note on drowning in work</title>
      <pubDate>Mon, 02 Jun 2008 14:34:55 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#02</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#02</guid>
      <description>&lt;b&gt;A note on drowning in work&lt;/b&gt;
&lt;p&gt;
Glub.
      </description>
    </item>
    <item>
      <title>2008-06-01: Being Right</title>
      <pubDate>Sat, 31 May 2008 19:30:56 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200806#01</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200806#01</guid>
      <description>&lt;b&gt;Being Right&lt;/b&gt;
&lt;p&gt;
A few months ago I learned what is, so far, the most fascinating thing I've
learned about human nature: the difference between being right, and being
able to look someone in the eyes.
&lt;p&gt;
If they practice, people can learn to look you in the eyes even when
they're lying to you.  But it's kind of like a fake smile; there are
involuntary muscles up there.  If you know what you're looking for, you can
still tell.
&lt;p&gt;
But what does it mean if they're looking you in the eyes and they
&lt;i&gt;mean&lt;/i&gt; it?  It means that, at least in that moment, they're doing what
they really believe is right.  That's the definition of &lt;b&gt;integrity&lt;/b&gt;.
&lt;p&gt;
That part is easy.  That's not the surprising thing.
&lt;p&gt;
The surprising thing, to me, was that someone can have integrity and still
be &lt;i&gt;completely evil&lt;/i&gt;.  It's kind of obvious in retrospect; the
super-villain in an action movie can always look the hero in the eye, and he
always does, just to prove it.  He has integrity.  Evil with integrity is
more respectable, somehow, than plain evil.
&lt;p&gt;
All it takes to have integrity is to do what you think is right, no matter
how stupid that may be.
&lt;p&gt;
Beware of people with integrity.
      </description>
    </item>
    <item>
      <title>2008-05-29: Ctrl-scrollwheel</title>
      <pubDate>Thu, 29 May 2008 10:45:18 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#29</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#29</guid>
      <description>&lt;b&gt;Ctrl-scrollwheel&lt;/b&gt;
&lt;p&gt;
Today I accidentally discovered the craziness of Ctrl-scrollwheel on a Mac. 
It also works with two-finger scrolling on a touchpad (although you need an
extra finger for Ctrl), so MacBook users need not feel left out.  Try it! 
It's ridiculous.
&lt;p&gt;
I'm totally going to use this next time I do a presentation.  Which I think
is in 15 minutes.
      </description>
    </item>
    <item>
      <title>2008-05-25: On the causes of poverty</title>
      <pubDate>Thu, 29 May 2008 10:43:21 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#25</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#25</guid>
      <description>&lt;b&gt;On the causes of poverty&lt;/b&gt;
&lt;p&gt;
&lt;ul&gt;&lt;i&gt;To seek &quot;causes&quot; of poverty in this way is to enter an intellectual
dead end because poverty has no causes.  Only prosperity has causes.&lt;/i&gt;
&lt;br&gt;-- Jane Jacobs, The Economy of Cities&lt;/ul&gt;
      </description>
    </item>
    <item>
      <title>2008-05-20: On projects that don't die</title>
      <pubDate>Tue, 20 May 2008 11:25:25 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#20</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#20</guid>
      <description>&lt;b&gt;On projects that don't die&lt;/b&gt;
&lt;p&gt;
I find it interesting to track which of the things I create that continue to
exist and flourish when I get bored with them, and which just drop dead when
I stop working on them, and everything in between.
&lt;p&gt;
For example, I've posted several times &lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/229.html&quot;&gt;before&lt;/a&gt;
about random people still do with my obsolete-before-I-even-wrote-it Linux
Arcnet driver.
&lt;p&gt;
Another one that I find interesting is the &lt;a
href=&quot;http://popcon.debian.org/&quot;&gt;Debian Popularity Contest&lt;/a&gt;, which I
created in... hmm, late 1998, almost ten years ago now.  I intended it as a
simple way to demonstrate that Debian really didn't need to distribute a
5-CD set; the packages most people wanted would happily fit onto one CD. 
Also, I was hoping I could forge enough results to get &lt;a
href=&quot;http://joe-editor.sourceforge.net/&quot;&gt;joe&lt;/a&gt; installed by default.
&lt;p&gt;
The first goal worked out great; Debian and Ubuntu now use popcon to fill
their CDs, and your system will be just fine even if you only download a
single CD image.  The second goal unfortunately still hasn't come to pass...
perhaps someday.
&lt;p&gt;
But more interesting is where these projects went &lt;i&gt;beyond&lt;/i&gt; my original
intention.  The reason arcnet is still popular is that it's used in quite a
few factories, because of its extremely good noise resistance and because
it's good enough that nobody wants to replace it.
&lt;p&gt;
And popcon?  Well, it now seems to have become the de-facto method of
resolving things like vi vs. emacs wars or &lt;a
href=&quot;http://people.debian.org/~igloo/popcon-graphs/index.php?packages=darcs%2Cgit-core%2Cmercurial%2Cbzr%2Csubversion%2C+cvs&amp;show_vote=on&amp;want_percent=on&amp;want_legend=on&amp;want_ticks=on&amp;from_date=2003-10-01&amp;to_date=&amp;hlght_date=&amp;date_fmt=%25Y-%25m&amp;beenhere=1&quot;&gt;how
soon git will be more popular than cvs&lt;/a&gt;, including a graph all the way
back to 2004.
&lt;p&gt;
Amazing.
      </description>
    </item>
    <item>
      <title>2008-05-15: jwz's collected bicycle wisdom</title>
      <pubDate>Wed, 14 May 2008 16:57:05 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#15</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#15</guid>
      <description>&lt;b&gt;jwz's collected bicycle wisdom&lt;/b&gt;
&lt;p&gt;
jwz has a &lt;a href=&quot;http://jwz.livejournal.com/883988.html&quot;&gt;remarkably
insightful article&lt;/a&gt; about bike ownership.  Notably, item #6 makes me feel
better about getting my own bike stolen last summer:
&lt;p&gt;
&lt;ul&gt;&lt;i&gt;Get a u-lock. Lock through the frame and the back wheel. Your bike
&lt;b&gt;will&lt;/b&gt; be stolen, so don't get too attached to it. This also means,
don't waste your money on junk like baskets and lights. Just get a backpack.
It doesn't matter how crappy your bike looks: any bike is worth stealing for
$2 worth of crack. Your bike is temporary. Accept this and move on.&lt;/i&gt;&lt;/ul&gt;
      </description>
    </item>
    <item>
      <title>2008-05-13: A note on market research</title>
      <pubDate>Mon, 12 May 2008 21:06:57 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#13</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#13</guid>
      <description>&lt;b&gt;A note on market research&lt;/b&gt;
&lt;p&gt;
I left one company after several years of faithful service.  The CEO himself
was elected to get me a going-away present on behalf of everyone.  He got
me... &lt;a href=&quot;http://en.wikipedia.org/wiki/Cuff_link&quot;&gt;cuff links&lt;/a&gt;.  (I
include the wikipedia link to help out those of you who know as much about
cuff links as I do.)
&lt;p&gt;
By comparison, where I work now, an office manager was elected to buy me a
wedding present.  She didn't know what I would want, so she went through my
emergency contact information (the privileges of being an office manager!),
called my parents, and asked &lt;i&gt;them&lt;/i&gt; what I would want.  My parents
didn't know, so they sneakily called me under false pretenses, got the
information out of me, and reported back.  What I got, among other things,
was a &lt;a href=&quot;http://www.freepatentsonline.com/6834411.html&quot;&gt;shower
squeegee&lt;/a&gt;. (I include the patent office link so you can truly understand
what an amazing gift that is.)
&lt;p&gt;
So what's the moral of this story?
&lt;p&gt;
Well, sometimes your office manager knows a lot more about pleasing
customers than your CEO does.
      </description>
    </item>
    <item>
      <title>2008-05-11: Engineers without Borders</title>
      <pubDate>Thu, 08 May 2008 14:57:02 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#11</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#11</guid>
      <description>&lt;b&gt;Engineers without Borders&lt;/b&gt;
&lt;p&gt;
I went to an Engineers Without Borders conference in Montreal a while ago,
and I was very impressed; these people seem to have their goals straight. 
And little did I know that it was &lt;a
href=&quot;http://en.wikipedia.org/wiki/Engineers_Without_Borders_(Canada)&quot;&gt;founded
in 2000 by University of Waterloo students&lt;/a&gt; who were in school at the
same time I was.  Considering it now has 25000+ members, that's incredibly
fast growth.
&lt;p&gt;
Anyway, as a sample of the sort of things they do, here's a report of a &lt;a
href=&quot;http://www.ewb.ca/e-news/en/2008/05/2&quot;&gt;field study of how a proposed
drought-resistant crop worked out in a heavy rainfall season&lt;/a&gt;.  Summary:
not so well.  But that's not the point; the point is that they actually went
to check, and then reported the results honestly, just like you'd expect
engineers to do.  I really respect that.
      </description>
    </item>
    <item>
      <title>2008-05-09: Great moments in probability</title>
      <pubDate>Wed, 07 May 2008 14:22:52 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#09</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#09</guid>
      <description>&lt;b&gt;Great moments in probability&lt;/b&gt;
&lt;p&gt;
Years ago (around 1999) when dcoombs and I were debugging the first versions
of our &quot;weaver&quot; Linux-based server appliances from our apartment in
Waterloo, we used to test on the cheapest hardware we could obtain for
cheap.
&lt;p&gt;
One of these boxes absolutely refused to boot weaver, but the symptoms were
&lt;i&gt;strange&lt;/i&gt;.  We had three ways of booting: boot from a CD, install an image on the hard drive and boot that, or load &lt;a
href=&quot;http://www.etherboot.org/wiki/index.php&quot;&gt;Etherboot&lt;/a&gt; from a floppy
and use that to network-boot the kernel over tftp.
&lt;p&gt;
The symptoms were as follows:&lt;ol&gt;
&lt;li&gt;Booting from CD worked fine.
&lt;li&gt;Installing from CD to the hard drive and booting that worked fine.
&lt;li&gt;Booting a weaver image from the hard drive (with a kernel downloaded via ftp) always gave kernel decompression error.
&lt;li&gt;The etherboot TFTP process would always
abort with a timeout after a few packets.  (Etherboot of the era would do
that occasionally even on a good day, but here it happened every time.)&lt;/ol&gt;
&lt;p&gt;
The obvious conclusion here was that our weaver kernel image was broken,
because you could boot the Debian kernel from either CD or hard disk without
a problem.  Right?
&lt;p&gt;
Well... as it turned out, no.  The actual problem was a horribly broken
network card that would randomly corrupt bits.  About 9 out of 10 packets
would be corrupted.  You'd think that would be obvious, right?
&lt;p&gt;
Well, no.  In fact, TCP/IP is specially designed to deal with the occasional
corrupted packet.  TCP and UDP have a 16-bit checksum on every packet, and
if it doesn't match, the receiver simply throws the packet away; the sender
is supposed to resend (and it does!).
&lt;p&gt;
I had noticed the FTP transfers were surprisingly slow, but not *that* slow,
and back in those days, you could never quite remember if your network card
was 10 MBit or 100 MBit.  This happened to be a 100 MBit card, but 9/10
packets were getting thrown away, so we got around 10 MBit performance from
ftp.
&lt;p&gt;
But here's what killed us: a 16-bit checksum can only detect 65535 out of
65536 possible errors.  A 9/10 error rate means you're sending 10x as much
data as you think you are, so a 12MB kernel+rootdisk package is actually
about 120MB of packets; that is, about 80000 packets at 1500 bytes each. 
Thus, virtually every transfer was destined to have a tiny number of
incorrect bytes!  Ha!
&lt;p&gt;
Of course TFTP is extra dumb and doesn't deal well at all with packet loss,
so it would just time out.  But I remain very impressed at how well TCP
managed to paper over a 90% broken network.  That's the power of the
Internet for you, right there.
&lt;p&gt;
(Thanks to &lt;a href=&quot;http://jwz.livejournal.com/880990.html&quot;&gt;jwz&lt;/a&gt; for
having a hopefully-unrelated problem that reminded me of this.)
      </description>
    </item>
    <item>
      <title>2008-05-07: Oil usage trends</title>
      <pubDate>Wed, 07 May 2008 13:11:58 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#07</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#07</guid>
      <description>&lt;b&gt;Oil usage trends&lt;/b&gt;
&lt;p&gt;
Every now and then, you see a trendline that actually tells you something
cool.
&lt;p&gt;
Check out the &lt;a
href=&quot;http://paul.kedrosky.com/archives/2008/05/06/nothing_but_flo.html&quot;&gt;average
number of vehicle-miles travelled in the U.S. since 1983&lt;/a&gt;... and how it's
finally stopped increasing.  Via Paul Kedrosky.
&lt;p&gt;
&lt;p&gt;
      </description>
    </item>
    <item>
      <title>2008-05-03: Architecture Astronauthood</title>
      <pubDate>Sat, 03 May 2008 14:04:49 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#03</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#03</guid>
      <description>&lt;b&gt;Architecture Astronauthood&lt;/b&gt;
&lt;p&gt;
Joel Spolsky has a recent article called &lt;a
href=&quot;http://www.joelonsoftware.com/items/2008/05/01.html&quot;&gt;Architecture
Astronauts take over&lt;/a&gt;.  The only comments I can seem to find on his
article are negative ones, which is too bad.
&lt;p&gt;
Now, I'm a bit of an architecture astronaut myself sometimes. Even so, I
believe Joel's totally right.
&lt;p&gt;
...but he's missed (maybe deliberately for effect) a couple of important
points.
&lt;p&gt;
One is that &quot;architecture problems&quot; really can be important to customers in
the end.  Not directly, but because they can make it easier to solve a
certain class of problems that customers &lt;i&gt;do&lt;/i&gt; have.  Synchronization
is, I believe, one of those problem classes.  I've spent a lot of time
thinking about and working on (real customer) problems that come down to the
synchronization problem, and wishing there were a magic &quot;synchronize this&quot;
button I could just click and have things always work out.  There still
isn't, and maybe there never will be, but I still hope there will.  (&lt;a
href=&quot;http://samba.anu.edu.au/rsync/&quot;&gt;rsync&lt;/a&gt; is the closest thing we
have, and it's a &lt;i&gt;huge&lt;/i&gt; architectural step forward - but there's more I
need to synchronize than just files, and librsync seems to be largely
ignored for some reason.)
&lt;p&gt;
The second point he misses is that giant non-user-focussed architectural
projects are not &lt;i&gt;always&lt;/i&gt; a waste of time.  &quot;The only difference
between genius and insanity is success.&quot;&lt;sup&gt;(1)&lt;/sup&gt; Look at MacOS X, for
example; Apple threw out pretty much everything from the original MacOS, and
spent years rewriting the entire thing from scratch.  It was a total loser
for &lt;i&gt;years and years&lt;/i&gt; of development, and the pain continued even for
years &lt;i&gt;after&lt;/i&gt; its initial release, because it was slow and buggy and
incompatible.  And yet now it's powering some of the world's most popular
(or at least coveted) laptops and cell phones.
&lt;p&gt;
It was a huge risk.  For every MacOS X, there are dozens of examples of
failed, mind-bogglingly expensive and time-consuming, attempts to build a
new desktop operating system.  Even Apple hasn't won more than a tiny
fraction of the market.  Thus, Joel is exactly right; anybody who would try
this basically has no concept of risk vs. return.
&lt;p&gt;
And yet, thank goodness for those people.&lt;sup&gt;(2)&lt;/sup&gt;
&lt;p&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; Can anybody find a good source for that quote?
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; Not that Microsoft's latest attempt seems any more likely to
succeed than the previous ones.  I said rsync was a huge step forward, but
it's really just a tiny little tool based on a brilliant concept.  The
&quot;synchronization problem&quot; needs more of those, not another giant
multibillion dollar &quot;synchronization platform.&quot;  An operating system needs
to support everything I need to do, while synchronization is just one of the
difficult things I need to do sometimes.
      </description>
    </item>
    <item>
      <title>2008-05-01: Logic can only help you achieve your goals, not set them</title>
      <pubDate>Thu, 01 May 2008 17:11:22 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200805#01</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200805#01</guid>
      <description>&lt;b&gt;Logic can only help you achieve your goals, not set them&lt;/b&gt;
&lt;p&gt;
Today, a quickie on the respective values of logic vs. emotion (intuition).
&lt;p&gt;
At one point, a person I know turned down an offer to work for my company in
favour of an offer at Google.  He had worked both with me and for Google at
different points in the past, so he knew a lot about both choices.  Our job
offer was competitive with Google's in terms of salary and benefits, and as
a bonus, he wouldn't have to relocate to a foreign country as with Google. 
Still, after a lot of deliberation, he went with Google, and I encouraged
him to.  Why?
&lt;p&gt;
Because he felt like it.
&lt;p&gt;
You can't argue with logic like that.  You shouldn't try.  The reason is
simple: because doing what you feel like makes you happy.  Doing what you
&lt;i&gt;don't&lt;/i&gt; feel like &lt;i&gt;doesn't&lt;/i&gt; make you happy.  And that's just the
end of it.  No amount of thinking it through will change those basic facts.
&lt;p&gt;
Unfortunately, a lot of people don't know what they feel like doing; they
don't know what they want out of life, and they certainly don't know why. 
So they try to &lt;i&gt;figure it out&lt;/i&gt;.  That's where consumerism, among other
things, comes from (&lt;a
href=&quot;http://www.washingtoncitypaper.com/display.php?id=34682&quot;&gt;weird article
about escaping from consumerism&lt;/a&gt;).  &quot;I don't know which job will make me
happier, so I'll take the one with the higher salary.&quot; &quot;Maybe if I had a
bigger house or a nicer car or whiter teeth, then I could be happy.&quot; If
those things will &lt;i&gt;actually&lt;/i&gt; make you happier (and if you're honest
with yourself, you already know if they will), then that's it; you win.  But
if you &lt;i&gt;don't know&lt;/i&gt; anything that will make you happier, and you're
trying to choose on an &quot;objective&quot; basis, then you'll lose for sure.
&lt;p&gt;
This problem - overthinking your desires - is surprisingly widespread, not
just among programmers, but for almost everyone.  Programmers happen to be
especially stubborn at rationalizing, so they sound more convincing than
most, but it's all the same game.
&lt;p&gt;
So what is logic good for, then?  It's good for &lt;i&gt;achieving&lt;/i&gt; your
desires.  If you're honestly having trouble deciding which of two job offers
makes you &lt;i&gt;feel&lt;/i&gt; better, maybe you honestly don't like either of them. 
Maybe, regardless of how objectively great they both sound, neither is
subjectively good at all.
&lt;p&gt;
When that happens - and this is a last resort for only that case -
&lt;i&gt;then&lt;/i&gt; you can use logic.  First, imagine what you want your life to be
like.  It can be anything you want.  Seriously.  Imagine it in excruciating
detail.  Then figure out, in just as much excruciating detail, all the steps
you'll have to take to get there.  If you do this exercise properly, all the
way back to the present, then you'll know what to do next.  You'll have
figured it out using logic, but that's okay, because your logic was guided
by emotion, not the other way around.
&lt;p&gt;
--
&lt;p&gt;
For more on logic vs. intuition vs. several other human attributes you can
combine for use in decision making, you might want to read the book &lt;a
href=&quot;http://www.penguin.ca/nf/Book/BookDisplay/0,,9780140288032,00.html&quot;&gt;On
Equilibrium&lt;/a&gt; by John Ralston Saul.  It has lots of big words, but it's
enlightening.
&lt;p&gt;
Also beware that if you believe what I've said above, you probably now
believe in fluffy emotional stuff called the &lt;a
href=&quot;http://en.wikipedia.org/wiki/Law_of_Attraction&quot;&gt;Law of Attraction&lt;/a&gt;. 
Hope you don't mind.  If you're like me, you'll find the traditional
explanations of it (eg. follow the link) unbelievable and silly, but what
I've said here is just a sanitized translation, honest.
      </description>
    </item>
    <item>
      <title>2008-04-29: The "culture of quitting"</title>
      <pubDate>Tue, 29 Apr 2008 18:29:21 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200804#29</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200804#29</guid>
      <description>&lt;b&gt;The &quot;culture of quitting&quot;&lt;/b&gt;
&lt;p&gt;
Here's an interesting article called &lt;a
href=&quot;http://thedailywtf.com/Articles/Up-or-Out-Solving-the-IT-Turnover-Crisis.aspx&quot;&gt;Up
or Out&lt;/a&gt; that talks about how people whose careers have stopped
progressing should just leave with no hard feelings... and how this is
already the case in legal and accounting firms (ie. if you don't &quot;make
partner&quot;), but for some reason doesn't seem to happen in IT organizations.
&lt;p&gt;
He even refers to employees that leave happily in this was as &quot;&lt;a
href=&quot;http://people.alumnit.ca/&quot;&gt;alumni&lt;/a&gt;&quot;.
&lt;p&gt;
This is an interesting point of view, since most people are more obsessed
with increasing the quality of their workforce through hiring rather than
&lt;strike&gt;firing&lt;/strike&gt; attrition.  For comparison, see &quot;&lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/145.html&quot;&gt;hiring above
the average&lt;/a&gt;&quot; at Google.
      </description>
    </item>
    <item>
      <title>2008-04-25: Shameless request</title>
      <pubDate>Fri, 25 Apr 2008 23:12:17 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200804#25</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200804#25</guid>
      <description>&lt;b&gt;Shameless request&lt;/b&gt;
&lt;p&gt;
Hello fellow alumnits,
&lt;p&gt;
I know that quite a lot of you work at Google now, so I want to ask for a
favour: can you weasel me a preview license to &lt;a
href=&quot;http://code.google.com/appengine/&quot;&gt;Google Appengine&lt;/a&gt;?  It sounds
really fun to play with, and I even have a project in mind.
&lt;p&gt;
Way back at NITI, we used to have a system for catching &lt;a
href=&quot;http://open.nit.ca/wvstreams/tutorial/wvcrash.html&quot;&gt;wvcrash&lt;/a&gt; output
and querying it in various different ways.  I wrote a system similar to
wvcrash &lt;a href=&quot;http://www.advogato.org/person/apenwarr/diary/337.html&quot;&gt;for
AmSchedule Express&lt;/a&gt; and other Versabanq stuff, but I haven't yet written
a handy analysis and tracking system for the crashes.  I think this would be
a fun project to run publicly with someone else's resources and let all
sorts of software send their crash dumps to it.  And since I need it anyway,
I'd do most of the work.  See?  Everybody wins!
&lt;p&gt;
(Except Google, who's giving all this away for free :))
&lt;p&gt;
&lt;b&gt;Update:&lt;/b&gt; Well, that was quick.  Thanks, &lt;a
href=&quot;http://www.luminal.org/wiki/index.php/Mag/Mag&quot;&gt;mag&lt;/a&gt;!
      </description>
    </item>
    <item>
      <title>2008-04-20: Linus on Caching</title>
      <pubDate>Sun, 20 Apr 2008 18:53:32 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200804#20</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200804#20</guid>
      <description>&lt;b&gt;Linus on Caching&lt;/b&gt;
&lt;p&gt;
&lt;ul&gt;I really dislike adding a cache that is there just because we do
something
stupid. We can fix the over-abundance of lstat() calls by just being
smarter. And the smarter we are, the less the cache will help, and the
more it will hurt. Which is the real reason why I think the cache is a
really really bad idea: it optimizes for the wrong kind of behavior.
&lt;p&gt;
So we have other caches and hashes we use, like the index itself, or the
name lookup hash into the index, or the delta cache. Maintaining those
caches takes some effort too, but those caches aren't there because we're
doing something stupid, they are there because they allow us to do
something smart.
&lt;p&gt;
-- &lt;a
href=&quot;http://article.gmane.org/gmane.comp.version-control.git/79961&quot;&gt;Linus
Torvalds&lt;/a&gt; on caching repeated operations&lt;/ul&gt;
      </description>
    </item>
    <item>
      <title>2008-04-08: The triumphant return of ion1</title>
      <pubDate>Tue, 08 Apr 2008 19:23:58 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200804#08</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200804#08</guid>
      <description>&lt;b&gt;The triumphant return of ion1&lt;/b&gt;
&lt;p&gt;
I really like the &lt;a href=&quot;http://modeemi.fi/~tuomov/ion/&quot;&gt;ion window
manager&lt;/a&gt;.  However, recent versions (ie. post version 1.0) haven't added
anything I wanted, while adding significant complexity and making it so that
certain things I liked in the original are nearly impossible to attain.
&lt;p&gt;
Specifically, I have &quot;split this frame vertically&quot; defined as ALT-S-V, and
&quot;delete the current frame&quot; defined as ALT-S-X.  If I do these commands in
quick succesion in ion1, effectively nothing happens; my focus is where it
started, and the order of my windows is the same as it was when it started. 
Unfortunately, I can't find a way to do the same thing in later versions of
ion; &quot;delete the current frame&quot; always ends up moving my focus around and
changing the order of windows.  Probably there's a way to program what I
want in &quot;lua&quot;, the oddball scripting language it uses, but I haven't
bothered to learn lua and I don't see the point of doing extra work.
&lt;p&gt;
Thus, I hereby announce the stillborn &lt;a
href=&quot;http://code.google.com/p/ion1/&quot;&gt;ion1 revival project&lt;/a&gt;.  I say
&quot;stillborn&quot; because I have taken the source code to ion1, built it as a .deb
package for Ubuntu Hardy, and I now plan to stop working on it since it
already does what I want, and that was the whole point.
&lt;p&gt;
Enjoy.
&lt;p&gt;
(If you do happen to want to contribute patches, though, please let me
know.  ion1 *does* have a few bugs that I'd love to see get fixed.)
      </description>
    </item>
    <item>
      <title>2008-04-07: The Google Situation</title>
      <pubDate>Mon, 07 Apr 2008 16:56:24 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200804#07</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200804#07</guid>
      <description>&lt;b&gt;The Google Situation&lt;/b&gt;
&lt;p&gt;
&lt;ul&gt;&quot;It's not a company, it's a cult, and frankly I can appreciate that because
we're a cult too and the fact is that cults are easier to run than
companies.&quot;&lt;br&gt;-- &lt;a
href=&quot;http://fakesteve.blogspot.com/2008/04/google-putting-up-fence-and-gate-to.html&quot;&gt;Fake
Steve Jobs&lt;/a&gt;&lt;/ul&gt;
      </description>
    </item>
    <item>
      <title>2008-03-28: Gittorrent</title>
      <pubDate>Mon, 24 Mar 2008 00:44:24 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200803#28</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200803#28</guid>
      <description>&lt;b&gt;Gittorrent&lt;/b&gt;
&lt;p&gt;
Can your version control system's design do this? &lt;a
href=&quot;http://gittorrent.utsl.gen.nz/rfc.html&quot;&gt;Gittorrent&lt;/a&gt;.
      </description>
    </item>
    <item>
      <title>2008-03-27: A tale of five merges, part 5: darcs and patch theory</title>
      <pubDate>Thu, 20 Mar 2008 13:26:26 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200803#27</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200803#27</guid>
      <description>&lt;b&gt;A tale of five merges, part 5: darcs and patch theory&lt;/b&gt;
&lt;p&gt;
This is not really an article about darcs.  Actually, I've never used darcs. 
It's not even really about patch theory, because I'm too lazy to read
through the actual &lt;a
href=&quot;http://en.wikibooks.org/wiki/Understanding_darcs/Patch_theory&quot;&gt;article
on patch theory&lt;/a&gt; in enough detail.
&lt;p&gt;
What this really is is a nice way to finish off my series of articles on
version control and merging concepts, by discussing some features that a
program like darcs might or might not have, because of some theory that
patch theory might or might not provide.  In other words, here are some good
ideas of unknown origin that I hope git will steal.  But I'll call our
imaginary system that might have these features darcs, because it ought to
have a name.  My apologies to the actual darcs maintainers.
&lt;p&gt;
So far, we've talked about branch merging in CVS, SVN, and git, both with
git-merge and git-rebase.  We've been addressing each one in terms of four
main questions: (A) how automatic is it, (B) what happens to the change
history, (C) what happens when you merge back and forth multiple times
between two branches, and (D) what happens when you &quot;cherry pick&quot; individual
changes, usually bugfixes, from one branch to another.
&lt;p&gt;
What we find is that with all the systems discussed so far, most of these
answers end up being some kind of &lt;a
href=&quot;http://www.advogato.org/person/apenwarr/diary/101.html&quot;&gt;compromise&lt;/a&gt;. 
None of the options presented so far has really been entirely what we want. 
So what would the ideal solution be like?
&lt;p&gt;
&lt;b&gt;A note on versioned storage&lt;/b&gt;
&lt;p&gt;
Before we can talk about the world of perfect version merging, we have to
talk about how those versions are stored in the first place. 
There are two basic philosophies about that: (a) store the files, or (b)
store the patches.
&lt;p&gt;
Speaking very roughly and inaccurately, SVN and CVS store one version and
then a bunch of patches against that version.  git stores just stores the
files.&lt;sup&gt;(1)&lt;/sup&gt;  Systems like darcs, on the other hand, prefer to talk
about groups of patches, rather than the files themselves.
&lt;p&gt;
The results of these philosophical decisions are very interesting.  For
example, if you branch and merge a lot in SVN, your repository gets a lot
bigger, because you store the patches from A to B, and from B to C, and from
A to A', and from B to B', and from C to C', and so on.  All those patches
will be slightly different, even if the resulting files are mostly the same,
so it's impossible to eliminate any redundancy (except trivially with
something like gzip).  git, on the other hand, stores just the files, and
when files are the same (which is very frequently), it doesn't store them
over again.  That means that in git, branching is basically always free.
&lt;p&gt;
darcs, on the third hand, mostly stores each version as a big pile of
patches, and it stores them in a particularly efficient way: if it is
&lt;i&gt;possible&lt;/i&gt; to use the patch from A to A' to convert from B to B', even
if the patch application is a bit &quot;fuzzy&quot;, then we just add that patch to
the pile for B'. Similarly if it will work to convert C to C'.  So in darcs,
branches are about as cheap as in git.
&lt;p&gt;
Now, regardless of which storage method you choose, you can obviously
convert quite easily from files to patches and back.  Version control
systems do this all the time; if you do &quot;git show&quot; or &quot;git diff&quot;, it's
converting from files to patches; if you do &quot;svn checkout&quot;, it's converting
from patches to files.  The only difference is that certain operations go
faster than others depending on your storage format.
&lt;p&gt;
&lt;b&gt;Why git is so fast&lt;/b&gt;
&lt;p&gt;
For example, &quot;git clone&quot; (the equivalent of &quot;svn checkout&quot;) goes much faster
than checking out of any of the other systems, because no conversion is
necessary.  On the other hand, &quot;git diff&quot; might be faster or slower than a
diff on one of the other systems; if you're asking about a patch that darcs
has already stored, darcs will probably be faster, because git has to
generate a patch.  But if you're asking about the difference between two
arbitrary sets of files, darcs will first have to figure out what those
files look like, then generate the patch, which is two steps to git's one,
so git will be faster.
&lt;p&gt;
And this is where the fun starts.  Because of git's storage system, some
operations are just plain amazingly fast: such as creating a commit.  The
secret to git's speed is that making a checkin just involves copying the
changed files verbatim into the repository; it doesn't think about deltas,
or patches, or anything.  And checking out any version, or creating a
branch, involves simply copying a file directly out of the repository.  Even
finding the differences between any two versions simply requires reading the
index to see which files have different SHA-1 hashes, and doing a diff
between them.  And the &quot;git merge&quot; operation does exactly that: it figures
out the differences from BEFORE to AFTER, and applies them to TARGET, and
checks in the result.  All of these operations are about as fast as they
get.
&lt;p&gt;
Where git gets slow is exactly where darcs gets fast.  In darcs, every merge
is like a &quot;batch cherry picking&quot; operation in git.  When there are no patch
conflicts - and darcs' &quot;patch theory&quot; will tell you in advance if there's a
conflict - then darcs can cherry pick a batch of patches in the same time it
takes for git to make an empty commit.  For git, on the other hand, every
single cherry you pick takes the same time as a git-merge: checkout, diff,
patch, and checkin.
&lt;p&gt;
git-rebase is just a big batch of cherry picking, and it's &lt;b&gt;slow&lt;/b&gt; in
git.  It would be a non-event in darcs.
&lt;p&gt;
git-svn uses git-rebase extensively, because it pulls patches out of svn and
then rebases all your work on top of it.  In darcs, the patches would just
go straight into the repository, no questions asked, and the conflicts could
be resolved later.
&lt;p&gt;
But much more importantly than the speed, cherry picking patches (and thus
&quot;rebasing&quot; branches) in darcs retains the history of those patches; after
all, they're just the same patches in another place, and all there is is
patches.  Where history in SVN is a line, and history in git is a helix,
history in darcs... well, we don't like to talk about &quot;history&quot; in darcs. 
We talk about... Patch Commutation and Inverses.&lt;sup&gt;(2)&lt;/sup&gt; Erm, okay,
maybe another time.
&lt;p&gt;
The major difference in the way darcs thinks about these things is in what
happens during a merge.  In git, we noted that merging two branches in
either &quot;direction&quot; always results in the same merged result, ie. set of
merged files.  But in darcs, you don't talk about files, you talk about
patches, and the merged result is &lt;i&gt;not&lt;/i&gt; the same: the two merges have
the same set of patches, but &lt;i&gt;the patches are in a different order&lt;/i&gt;. 
&lt;p&gt;
The order of the patches is the missing information that SVN's simple-minded
merge history emphasizes, and git's merge history hides.  Moreover,
git-rebase is all about changing the order of patches, and since git doesn't
really &lt;i&gt;know&lt;/i&gt; anything about patches, that's exactly why it makes
git-merge so angry.
&lt;p&gt;
How does darcs do back-and-forth merges between two branches?  Well, that's
easy: you simply look at the list of patches in the source branch, and the
list of patches in the destination branch, and you add the patches to the
destination that weren't already there.
&lt;p&gt;
How about reordering and recombining patches, like in git's interactive
rebase?  Well, if &quot;patch theory&quot; says there aren't any conflicts, then feel
free to reorder them; darcs already knows it'll work, so it doesn't actually
need to calculate anything.  It finishes instantly, and doesn't mess up
future merges to or from other branches.&lt;sup&gt;(3)&lt;/sup&gt;  That's way better
than git-rebase.
&lt;p&gt;
&lt;b&gt;A perfect world&lt;/b&gt;
&lt;p&gt;
At last, we come to the end of our series!  Let's put it all together.  What
would an ideal system look like?
&lt;p&gt;
My suggestion would be to base the system on git - because it's fast for
everyday operations like checkout, checkin, diff, and merge - but add some
elements of patch theory.  Most importantly, it's not okay for a
git-cherry-pick or git-rebase operation to forget the old commits that the
new commits were based on.  They need to store a &quot;patch parent&quot; field that
basically says, &quot;this commit is what happens when you take the difference
from BEFORE my patch parent to AFTER my patch parent, and apply it to my
PARENT.&quot;  Then git-merge will have some extra work to do sometimes to unwind
the criss-crossing patches, but it's not the end of the world: after the
next git-merge between a given two branches, we're entirely caught up and
everything is easy again.  It seems a small price to pay in order to have
git-svn, git-rebase, and git-filter-branch all magically work properly with
git-merge and git-pull.
&lt;p&gt;
So how does our imaginary new system stack up with respect to our four
key questions?
&lt;p&gt;
Our newfangled merging system: (A) allows you to rearrange patches as easily
as git-rebase, and yet still merge as easily as git-merge; (B) allows you to
shuffle and clean up change history at will, while still tracing (via
patch-parent) into the detailed original patches if you want; (C) easily
handles back-and-forth merges as well as git-merge or darcs, *and* even if
you've been using git-rebase; (D) easily supports cherry picking without
disrupting future back-and-forth merges.
&lt;p&gt;
Yeah, yeah, I know what you're going to say.  I should go write it myself. 
Well, maybe someday I will.  But don't hold your breath. :)
&lt;p&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; This is really true, honest.  The existence of &quot;git repack&quot;,
which rewrites groups of files using xdelta encodings, is really an
optimization.  It's not how git actually thinks about things.
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; That's probably why most people don't use darcs.
&lt;p&gt;
&lt;sup&gt;(3)&lt;/sup&gt; There are actually huge theoretical problems with doing this,
so you wouldn't actually implement it that way.  Imagine you had a patch to
add a function declaration to foo.h, and another one to add the function
body in foo.c, and another one to &lt;i&gt;call&lt;/i&gt; the function and include the
header from blue.c.  If you check in the changes in that order, you'll have
a compiling program at each step.  And these three patches are &quot;independent&quot;
according to patch theory, since they all change different files.  But if
you reorder them and change blue.c before foo.h and foo.c, your program
won't actually work.  So arbitrarily reordering patches produces software
versions that never actually existed and were never tested and thus might
not work, which is of limited use.  That's why &quot;patch theory&quot; as I've
described is mostly &quot;theory&quot; and not &quot;practice&quot;, even in darcs.
      </description>
    </item>
    <item>
      <title>2008-03-25: A tale of five merges, part 4: 'git rebase'</title>
      <pubDate>Thu, 20 Mar 2008 13:26:24 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200803#25</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200803#25</guid>
      <description>&lt;b&gt;A tale of five merges, part 4: 'git rebase'&lt;/b&gt;
&lt;p&gt;
So far, we've talked about branch merging concepts in CVS, SVN, and git.  Of
the three, git's is by far the most convenient and magical... when it does
what you want.  When it doesn't do what you want, you find yourself in a bit
of trouble.
&lt;p&gt;
&lt;b&gt;Rebasing git branches&lt;/b&gt;
&lt;p&gt;
Last time, we brought up one example of a major problem with the &quot;git merge&quot;
command: if you create BRANCH1 from MASTER, and then BRANCH2 from BRANCH1,
and you merge BRANCH2 into MASTER, then you end up merging BRANCH1 into
MASTER as well by accident.  That's because &quot;git merge&quot; finds the first
common ancestor of BRANCH2 and MASTER, which is MASTER, and merges all the
changes from there to BRANCH2.  In between those two points lies all of
BRANCH1.
&lt;p&gt;
This is exactly the problem that &quot;git rebase&quot; was designed to solve.  Here's
what you do:&lt;ol&gt;
&lt;li&gt; git checkout BRANCH2
&lt;li&gt; git rebase --onto MASTER BRANCH1&lt;/ol&gt;
&lt;p&gt;
What the above command does is re-apply all the changes from BRANCH1 to
BRANCH2 onto MASTER.  Sound familiar?  Yes, that's right, it's exactly what
&quot;cvs up -j BRANCH1 -j BRANCH2&quot; would have done. And with &quot;git rebase&quot;, you
specify revisions just as manually as you would with CVS or
SVN.&lt;sup&gt;(1)&lt;/sup&gt;
&lt;p&gt;
Here's the problem: the rebase command generates entirely new patches onto
an entirely new branch.  The old BRANCH2 is gone&lt;sup&gt;(2)&lt;/sup&gt;, and the new
BRANCH2 has a bunch of commits on it that look similar to a person, but as
far as git knows, have nothing in common with the old ones.  If you've ever
shared your old BRANCH2 with anyone, they will no longer be able to merge to
and from your new BRANCH2.  If you use git-rebase, the only sane thing you
can do is throw away all the pre-rebase versions of BRANCH2... and that's
tricky, since people all over the world might have a copy.  They might even
have merged it with their own branches.  Oops.
&lt;p&gt;
This combination of inconveniences, by the way, is the absolute most
frustrating problem with using git-svn.  Every time a new revision comes in
from SVN, you need to git-rebase your patches on top of it, screwing up all
git branches in the entire repository.
&lt;p&gt;
The good news is that you can continue to work on your new BRANCH2, and when
you merge it (with &quot;git merge&quot;) back and forth with MASTER, at least you
won't have a problem.
&lt;p&gt;
&lt;b&gt;Interactive Rebase&lt;/b&gt;
&lt;p&gt;
Another concern that people run into with git's merging style is more about
their sense of aesthetics.  git makes it really easy to create local
branches and check in frequently - it even encourages this, since it has
such easy merging and branching and such fast checkins.
&lt;p&gt;
The problem is if you take advantage of this, you end up checking in code
every ten minutes, and sometimes it doesn't work.  When you later want to
prepare a set of patches for submission to an upstream maintainer, you don't
want to send in 57 patches, none of which work independently.  You probably
want to send maybe three patches, each of which adds a separate feature.
&lt;p&gt;
For this, git introduces &quot;git rebase -i&quot;, known as &quot;interactive rebase.&quot;  I
won't go into detail, since &lt;a
href=&quot;http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html&quot;&gt;the
git-rebase man page&lt;/a&gt; is detailed enough.  But the idea is that you can
take your original patchset and shuffle it around and split and join patches
however you want, making it &lt;i&gt;look&lt;/i&gt; like that's what actually happened
as you developed your project.  So if you added feature #1, then feature #2,
then realized there was a bug in feature #1 and fixed it, then fixed another
bug in feature #2, you can join patches #1 and 3, and then #2 and 4, so it
&lt;i&gt;looks&lt;/i&gt; to the world like you just did everything perfectly the first
time.  As a bonus, when people are doing code reviews of your patches, they
won't have to review code that you already knew was broken.  That ought to
save some time.
&lt;p&gt;
Interactive rebase is an innovative feature that certainly isn't available
in something like CVS or SVN, and it can be addictive.  Of course, before
you have it, it's hard to imagine that you'd need it.  Personally, I find
myself reshuffling my patches a bit unnecessarily just for the aesthetics of
a clean repository where each patch does what it says.  This is both fun and
time consuming, and it's debatable whether it's worth it or not.
&lt;p&gt;
To some degree, the reason interactive rebase is popular is that &quot;git merge&quot;
history is &lt;i&gt;too&lt;/i&gt; detailed.  In svn, you'd make your mess on a branch,
get things all cleaned up, and then do a one-shot merge from your branch
into the trunk.  The merge would just say &quot;added features X and Y.&quot; Nobody
was forced to look at the inevitable long string of screw-ups that actually
led to features X and Y getting added.  &lt;b&gt;Interactive rebase exists
primarily to get back the feeling of cleanliness that SVN had and git took
away.&lt;/b&gt;
&lt;p&gt;
&lt;p&gt;
&lt;b&gt;Git rebase summary&lt;/b&gt;
&lt;p&gt;
For each merging system, we've been asking: (A) how automatic is it, (B)
what happens to the change history, (C) what happens when you merge back and
forth multiple times between two branches, and (D) what happens when you
&quot;cherry pick&quot; individual changes, usually bugfixes, from one branch to
another.
&lt;p&gt;
&quot;git rebase&quot; is unusual for a merging system, but it's basically a
paraphrased version of old-style CVS and SVN merge commands.  Thus, the
answers it gives to these questions are roughly the same: (A) it's
semi-automatic, as long as you provide the right revision numbers; (B) it's
mostly used to make the change history look cleaner, at the expense of
losing the detailed history git-merge could provide; (C) it actively
complicates merging back and forth between branches, and produces more
conflicts than CVS or SVN would have; and (D) it's highly compatible with
patch cherry picking, since that's pretty much all it does.
&lt;p&gt;
In short, a combination of &quot;git merge&quot; and &quot;git rebase&quot; either gives you the
best of both worlds, or the worst of both worlds, depending on your point of
view.  But having to choose between them, and trying to figure out what
crazy thing happened when you chose the wrong one, is one of the scariest
and most confusing parts of git as far as new users are concerned.  In fact,
for me, it's much harder to sort out the combination of &quot;git merge&quot; and &quot;git
rebase&quot; than it is to figure out two-way merging in CVS... and that's saying
a lot.
&lt;p&gt;
Next time: darcs and patch theory.
&lt;p&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; One cool thing about &quot;git rebase&quot;, however, is that it keeps
your original patches as separate checkins.  With CVS or SVN, you would get
one big checkin with a merge of all your patches; with &quot;git rebase&quot;, it
keeps your patch series intact.  There is no technical reason that CVS or
SVN couldn't do the same trick, though.
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; Usually you don't want to actually delete the old BRANCH2,
just in case you screw up.  Perhaps you'll call the new one BRANCH2a.  But
you'll still never be able to merge between BRANCH2 and BRANCH2a, even though
they contain the same set of changes.
      </description>
    </item>
    <item>
      <title>2008-03-23: A tale of five merges, part 3: 'git merge'</title>
      <pubDate>Thu, 20 Mar 2008 13:26:22 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200803#23</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200803#23</guid>
      <description>&lt;b&gt;A tale of five merges, part 3: 'git merge'&lt;/b&gt;
&lt;p&gt;
In the last two articles from this series, I talked about merging branches
in CVS and SVN, and how they're largely the same.
&lt;p&gt;
Today is the first of two articles about merging in &lt;a
href=&quot;http://git.or.cz/&quot;&gt;git&lt;/a&gt;.  git is most definitely &lt;i&gt;not&lt;/i&gt; the
same as CVS and SVN.
&lt;p&gt;
Remember, the questions we're investigating for each merging system are: (A)
how automatic is it, (B) what happens to the change history, (C) what
happens when you merge back and forth multiple times between two branches,
and (D) what happens when you &quot;cherry pick&quot; individual changes, usually
bugfixes, from one branch to another.
&lt;p&gt;
&lt;b&gt;Merging with 'git merge'&lt;/b&gt;
&lt;p&gt;
Compared to working with CVS or SVN, merging branches in git feels like
magic.  First, you check out the branch that you want to merge into, say
MASTER.  Then you type &quot;git merge BRANCH&quot;, where BRANCH is the name
of the branch you want to merge from.  And that's all.
&lt;p&gt;
...When it works.
&lt;p&gt;
Aha.  You see, &quot;git merge&quot; is really just doing exactly what you were doing
in CVS or SVN by hand.  That's why I went into CVS merging in such detail
before.
&lt;p&gt;
Here's what really happens: given the name BRANCH and the implicit name
MASTER (since that's the one you have checked out), git traces back in the
history of both until it finds the branchpoint, that is, the last commit
before the two diverged in the first place.&lt;sup&gt;(1)&lt;/sup&gt;  If we were using CVS, we'd call
that point BEFORE, and BRANCH would be called AFTER.  git then simply takes
all the changes from BEFORE to AFTER and adds them to MASTER.
&lt;p&gt;
Now here's where things get especially clever.  Remember when we were
discussing bidirectional merges in CVS, and I pointed out that merging all
the changes from BEFORE to AFTER into HEAD was the same as merging all the
changes from BEFORE to HEAD into AFTER?  The resulting tree is the same in
both cases, but of course, in CVS and SVN, the actual commit you make is
different in each case.  After all, in one case, you're committing to the
HEAD branch, and in another, you're committing to the AFTER branch.
&lt;p&gt;
git is smarter than that.  In git, &lt;b&gt;there really is no difference between
the two operations&lt;/b&gt;.  You generate a single commit that has &lt;i&gt;two
parents&lt;/i&gt;: AFTER and HEAD (or BRANCH and MASTER).  Now, it so happens that
git updates the MASTER branch pointer to point at your new commit in one
case, or the BRANCH branch pointer in the other case, but the commit itself
is exactly the same in both cases.
&lt;p&gt;
And that simple fact is why repeated merges and bidirectional merges work. 
Next time you're merging MASTER and BRANCH, git will trace back, and the
most recent checkin that is shared between the two branches will be one of
the parents of that magical two-parent merge checkin.  We use that one as
BEFORE, and merge the changes from BEFORE to BRANCH into MASTER.  Or else we
merge the changes from BEFORE to MASTER into BRANCH; again, it's the same
thing.
&lt;p&gt;
This concept of a two-parented commit is what makes git merging totally
different from SVN, and it's the difference between SVN's &quot;linearized
history&quot; (in which every commit has exactly one parent, even if we made it
that way artificially) and git's non-linear history.&lt;sup&gt;(2)&lt;/sup&gt;  It's
also the reason git merging can be automatic, while svn's cannot.
&lt;p&gt;
&lt;b&gt;Why it doesn't always work&lt;/b&gt;
&lt;p&gt;
The problem with git's automatic merging is, well, that it's automatic. 
When it's working for you, it's amazingly powerful.  But people who are used
to CVS or SVN merging sometimes feel like git is taking their power away.
&lt;p&gt;
For example, perhaps you don't want to merge &lt;i&gt;all&lt;/i&gt; the changes from
BRANCH; perhaps you only want the changes up until sometime last week.  With
'svnmerge' this is easy enough to do, but with git it requires multiple
steps, since git-merge won't accept arbitrary revisions on its command line,
only branch names.&lt;sup&gt;(4)&lt;/sup&gt;
&lt;p&gt;
Or say you create BRANCH1 from MASTER, and start to add feature #1.  Then
you create BRANCH2 from BRANCH1, and add (unrelated) feature #2. Now you
decide that feature #2 is ready to merge back into MASTER, but feature #1 is
not.  No problem, right?  You checkout MASTER and then type &quot;git merge
BRANCH2&quot;.
&lt;p&gt;
Oops!  git has just merged &lt;i&gt;all&lt;/i&gt; the history of BRANCH1 *and* BRANCH2
back into MASTER, which is not what you wanted at all!  Unfortunately,
because git's merging is fully automatic, there is no easy way to get the
behaviour you wanted.&lt;sup&gt;(3)&lt;/sup&gt; With CVS, on the other hand, what you
would do is obvious: &quot;cvs up -j BRANCH1 -j BRANCH2&quot;, to merge all the
changes from BRANCH1 to BRANCH2 into MASTER.  With SVN, it would be similar,
except that BRANCH1 and BRANCH2 involve revision numbers and URLs.
&lt;p&gt;
In git, the solution to this sort of problem is to use the &quot;git rebase&quot;
command, which we'll discuss in more detail next time.  But any use of
git-rebase or git-filter-branch, both of which are very useful,
fundamentally change the commit IDs on the modified branch.  &quot;git push&quot; and
&quot;git pull&quot; stop working as expected.  Essentially, these commands generate
entirely new commits for the part of the tree they change, so now there are
&lt;i&gt;two&lt;/i&gt; sets of commits in your repository that do the same thing in two
different ways, with nothing tying them together. Worse, after a rebase, the
point where your two branches diverged might be no longer known to git -
they no longer have a single commit id in common - so it just gives
up.&lt;sup&gt;(5)&lt;/sup&gt; And trying to merge the new MASTER back into the original
BRANCH2 later will result in a ton of conflicts.
&lt;p&gt;
The really bad news is that git-svn, which is otherwise a great tool to help
with migrating between git and svn, uses git-rebase pretty heavily.  That
confuses git's automated merging features altogether, and git's
&lt;i&gt;manual&lt;/i&gt; merging features are not as straightforward as SVN's, so
things get confusing very fast.
&lt;p&gt;
&lt;b&gt;Git merge and cherry picking&lt;/b&gt;
&lt;p&gt;
git includes another command called &quot;git cherry-pick&quot;.  Its job is to take
the changes from &lt;i&gt;one&lt;/i&gt; specific commit and apply them to the current
branch.
&lt;p&gt;
Unfortunately, the existence of git cherry-pick is incompatible with git
merge's view of the world.  git's history may not be &lt;i&gt;linear&lt;/i&gt;, but at
least it's &lt;i&gt;continuous&lt;/i&gt;: branches may swerve into and out of each other
as they pass through time, but individual changes aren't supposed to simply
jump from the middle of one tree into the middle of another.
&lt;p&gt;
Since there's no way to represent what really happened, a cherry-picked
patch instead produces an entirely new commit with exactly one parent (the
destination branch), so a future git-merge from that branch has no idea the
patch already existed, and usually produces a conflict.
&lt;p&gt;
Cherry picking in SVN with 'svnmerge' definitely works better than this.
&lt;p&gt;
&lt;b&gt;How the git changelog tracks merges&lt;/b&gt;
&lt;p&gt;
Last time around, I talked about how SVN's &quot;linear&quot; change history tracks
merges, which is simple enough: every time you do a merge, it puts a single
checkin into the destination branch which contains all the changes.  And if
you want to know the details of every patch from the source branch, well,
you'll have to go look at the source branch yourself.
&lt;p&gt;
git definitely doesn't do that.  Instead, if you ask for &quot;git log&quot; it will
show you the &lt;i&gt;complete set of changes in all branches leading up to the
current commit&lt;/i&gt;.  That is, all of the checkins to &lt;i&gt;either&lt;/i&gt; of the
merged branches show up in the log, with nothing in particular in the &quot;git
log&quot; output identifying which patch came from where.&lt;sup&gt;(6)&lt;/sup&gt; &lt;b&gt;This
is technically correct, but is not actually what most users wanted to
know&lt;/b&gt;.
&lt;p&gt;
Most people who ask for the history of the MASTER branch want to know the
&quot;simplified&quot; form of its history: Added feature X; added feature Y; fixed
feature X; added feature Z.  But instead, they confusingly see all the
individual 57 commits making up &quot;added feature X&quot;, even though if they were
ignoring your featureX branch all along, &quot;added feature X&quot; was really a
one-time event for them.&lt;sup&gt;(7)&lt;/sup&gt;
&lt;p&gt;
A related problem is that git doesn't have a way of naming branches
globally.  So if you merge from the &quot;featureX&quot; branch, you're not really
merging from featureX; you're merging from
2bed2ad4845eceb8ee650f34e476a60f9fbecc7c.  As far as the computer is
concerned, that's the same thing, but when it comes to tracing back through
your history, it's not actually what you wanted to know.
&lt;p&gt;
Worse still, git doesn't remember &lt;i&gt;at branch time&lt;/i&gt; where you diverged;
it only figures it out &lt;i&gt;at merge time&lt;/i&gt;.  That means there is no
equivalent to SVN's &quot;svn log --stop-on-copy&quot;, which shows only the changes
you added &lt;i&gt;in this branch&lt;/i&gt;.&lt;sup&gt;(8)&lt;/sup&gt;
&lt;p&gt;
&lt;b&gt;git-merge overall&lt;/b&gt;
&lt;p&gt;
Now let's go back to the questions we were trying to answer in the first
place:
&lt;p&gt;
git-merge: (A) does merges fully automatically, when it works, but
complicates manual merges; (B) retains the history of each change, but that
often turns out to be more than you wanted; (C) easily supports
back-and-forth merges with no more trouble than single merges; and (D) does
not really support cherry picking without introducing future merge
conflicts.
&lt;p&gt;
Phew!
&lt;p&gt;
Next time: how 'git rebase' tries to solve some of the things people don't
like about git merge.
&lt;p&gt;
&lt;p&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; This is actually greatly oversimplified.  Since git history
is nonlinear, just tracing back through it is a bit complicated.  On top of
that, you can play tricks with selecting different branchpoints for
different files, and so on.
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; I guess if SVN's history is &quot;linear&quot;, then git's history is
&quot;helix shaped,&quot; with endless splitting and remerging of histories.
&lt;p&gt;
&lt;sup&gt;(3)&lt;/sup&gt; git proponents would say that what you should have done is
branched BRANCH2 from MASTER in the first place.  But not everyone is lucky
enough to get everything right the first time.
&lt;p&gt;
&lt;sup&gt;(4)&lt;/sup&gt; There seems to be no actual reason for this restriction. 
Perhaps it will go away eventually.
&lt;p&gt;
&lt;sup&gt;(5)&lt;/sup&gt; That's the source of the mysterious note that &quot;You should
understand the implications of using git rebase on a repository that you
share&quot; in the git-rebase man page.  Of course, the man page doesn't really
tell you what the implications are.  It just says it &quot;will cause problems.&quot;
&lt;p&gt;
&lt;sup&gt;(6)&lt;/sup&gt; The &quot;gitk&quot; and &quot;gitweb&quot; programs attempt to represent this
graphically, which helps.  The &quot;git show-branch&quot; program is also somewhat
useful here.  But all of these are much harder to understand than &quot;svn log&quot;.
&lt;p&gt;
&lt;sup&gt;(7)&lt;/sup&gt; There is actually a &quot;--squash&quot; feature of git-merge that
tries to resolve this problem.  Essentially it creates an entirely new
commit with only one parent - the destination branch - and doesn't tie in at
all to the history of the other branch.  In other words, it does exactly
what &quot;svn merge&quot; would do, but that has exactly the opposite set of
tradeoffs, as discussed last time, and makes bidirectional merges very ugly. 
Alternatively, &quot;git log --first-parent&quot; displays only the first parent of
each merge, which is closer to what most users actually want.
&lt;p&gt;
&lt;sup&gt;(8)&lt;/sup&gt; If you manually keep track of which branch you came from, you
can use &quot;git log BEFORE..MYBRANCH&quot; to see the list of changes between BEFORE
and MYBRANCH.  But if you're going to manually keep track of BEFORE, you
might as well be using CVS.  &quot;git show-branch&quot; also attempts to help here,
but if you ever use &quot;git rebase&quot; its output will be hopelessly cluttered and
confusing.
      </description>
    </item>
    <item>
      <title>2008-03-21: A tale of five merges, part 2: Subversion (svn)</title>
      <pubDate>Thu, 20 Mar 2008 13:26:07 -0400</pubDate>
      <link>http://alumnit.ca/~apenwarr/log/?m=200803#21</link>
      <guid isPermaLink="true">http://alumnit.ca/~apenwarr/log/?m=200803#21</guid>
      <description>&lt;b&gt;A tale of five merges, part 2: Subversion (svn)&lt;/b&gt;
&lt;p&gt;
Last time, I introduced the confusing but definitely workable concept of
merging branches with CVS.
&lt;p&gt;
Of course, CVS is completely obsolete nowadays, having been wholeheartedly
replaced by Subversion.  SVN really does do everything CVS can do, plus
more, and it includes awesome CVS import tools and clients for every
platform, so if you're still using CVS, do yourself a favour and just switch
to SVN right away.  I mean it.&lt;sup&gt;(1)&lt;/sup&gt;
&lt;p&gt;
As a refresher, the questions we're investigating for each merging system
are: (A) how automatic is it, (B) what happens to the change history, (C)
what happens when you merge back and forth multiple times between
two branches, and (D) what happens when you &quot;cherry pick&quot;
individual changes, usually bugfixes, from one branch to another.
&lt;p&gt;
&lt;b&gt;Merging with 'svn merge'&lt;/b&gt;
&lt;p&gt;
If you understood what I said about CVS last time, it won't take you much
work to understand merging in SVN.  The key things to note are:
&lt;ul&gt;
&lt;li&gt;SVN numbers each commit automatically, and uses its commit numbers like CVS uses tags.
&lt;/li&gt;
&lt;li&gt;SVN tags, conversely, are almost nothing like CVS tags. (They're conceptually more like making new repositories altogether.)
&lt;/li&gt;
&lt;li&gt;'svn merge' is essentially the same thing as 'cvs up -j -j', only with more annoying syntax.
&lt;/li&gt;
&lt;/ul&gt;
I won't go into much detail here, as conceptually, merging in SVN is pretty
much the same thing as merging in CVS, and &lt;a
href=&quot;http://svnbook.red-bean.com/en/1.0/ch04s04.html&quot;&gt;is covered
excellently in the SVN Book&lt;/a&gt;.
&lt;p&gt;
The strangest thing about merging with SVN is that even though SVN supports
tags, they are mostly worthless for merging purposes.  Instead, people use
svn &quot;tags&quot; as branches and just merge based on revision ids.  Where in CVS
you would &quot;cvs up -j BEFORE -j AFTER&quot;, you would now &quot;svn merge
-rBEFORE:AFTER that_other_repository&quot;, where BEFORE and AFTER are magic
numbers and that_other_repository is the place in SVN where you've been
working on your branch.&lt;sup&gt;(2)&lt;/sup&gt;
&lt;p&gt;
As with CVS, repeated merging and bidirectional merging are both entirely
possible, as long as you remember which revision numbers correspond to
BEFORE and AFTER.  Usually you do this by putting the revision numbers (by
hand) into your commit messages, which is gross, but I guess no more gross
than manually creating tags in CVS.
&lt;p&gt;
&lt;b&gt;Merging with 'svnmerge'&lt;/b&gt;
&lt;p&gt;
'&lt;a href=&quot;http://www.orcaware.com/svn/wiki/Svnmerge.py&quot;&gt;svnmerge&lt;/a&gt;' is a standalone program that is not officially part of svn.  It
is not to be confused with 'svn merge' (above), which is a command built
into svn itself.
&lt;p&gt;
The purpose of 'svnmerge' is to get rid of the grossest parts of SVN
merging, namely the fact that humans have to remember and type SVN revision
numbers to do a merge, as well as repeatedly type the stupid
that_other_repository path.
&lt;p&gt;
&lt;b&gt;Simple advice:&lt;/b&gt; If you're using SVN, you should probably be using
svnmerge for your merges.&lt;sup&gt;(3)&lt;/sup&gt;
&lt;p&gt;
Unfortunately, one thing that svnmerge &lt;i&gt;doesn't&lt;/i&gt; do easily is
bidirectional merging.  If you're working in a feature branch and
occasionally merging into your branch from /trunk (the same thing as HEAD in
CVS), you can use svnmerge to do it.  But when you go to merge your feature
branch back into /trunk, svnmerge will get horribly confused, and you'll
have to do it using plain 'svn merge'.  It's not the end of the world, but
you have to know what you're doing.
&lt;p&gt;
On the other hand, svnmerge adds support for &quot;cherry picking&quot;, or choosing
to merge individual revisions from one branch into another.  You can use
this to backport bugfixes from /trunk into a patch release, for example.
(Rumour has it that the SVN developers themselves use this technique a lot.)
&lt;p&gt;
&lt;b&gt;How the SVN changelog tracks merges&lt;/b&gt;
&lt;p&gt;
SVN has what is called a &quot;linearized&quot; view of history.  Every repository has
a sequence of checkins, and each checkin affects one or more branches.  So
you can view the changes to a particular branch over time (by showing the
sequence of checkins, and filtering out the ones that didn't affect your
branch).  You can also view the list of &lt;i&gt;all&lt;/i&gt; the checkins, regardless
of branch, and see a linear history of &quot;what people did over time.&quot;
&lt;p&gt;
Perfect, right?
&lt;p&gt;
Well, not quite.  The problem is that merge history isn't very easy to view. 
If you view the history of a branch, one of the checkins you see will be
something like &quot;merged changes from /branches/whatever, r3456:3573&quot;.  If
you're smart and use the 'svnmerge' tool, the changelog of r3456:3573,
filtered for /branches/whatever, will be appended to the message.  But if
you want to know exactly what happened in r3458, then what happened in
r3504, and then what happened in r3573... you'll have to ask about those
revisions on /branches/whatever, not on your destination branch.  And &lt;b&gt;the
only way you know that is by reading the freeform English message in the
changelog&lt;/b&gt;.  That's subversion's &quot;linearized view&quot; in action: as far as
SVN is concerned, that branch just saw one checkin, the merge
checkin.  All those other details happened on some other, totally unrelated
branch.
&lt;p&gt;
This is actually both good and bad, because it turns out that
&lt;i&gt;sometimes&lt;/i&gt; you want the detailed history, and &lt;i&gt;sometimes&lt;/i&gt; you
want the summary version.
&lt;p&gt;
For example, say I'm adding feature X in a branch called /branches/featureX. 
It takes me 57 commits, including a few merges to catch up with /trunk,
before my changes are ready to go back into /trunk.  Everyone else working
on the project will be very interested to know that I &quot;Merged
/branches/featureX into the trunk&quot; - as well as the precise set of changes
that introduced - but they almost certainly don't care about my 57 commits
in detail.  &lt;b&gt;For most humans, the preferred view of the trunk is SVN's
linearized view.&lt;/b&gt;
&lt;p&gt;
That is, until it's time to track down which of those commits introduced a
bug, or which lines of code were contributed by that guy who was copying
source code from SCO, or who I should ask about this particular new
function, or whatever.  In SVN, you can do &quot;svn annotate&quot; to find out which
revision a line was last modified in, and who did it... but it almost always
turns out to have been modified by some guy who merged the changes from some
branch, so you have to manually go look in that branch, and so on.
&lt;p&gt;
Next time, when we talk about git, we'll see how the opposite solution is
bad for the opposite reasons.
&lt;p&gt;
&lt;b&gt;SVN overall&lt;/b&gt;
&lt;p&gt;
Let's answer our original questions.
&lt;p&gt;
SVN: (A) is not very automatic at merges, albeit better than CVS, and
'svnmerge' makes it significantly better; (B) retains change history across
all branches, but the detailed history of a merge must be traced manually to
its source branch; (C) like CVS, supports back-and-forth merges with no more
trouble than single merges; and (D) has okay support for cherry picking if
you use 'svnmerge --bidirectional' carefully.
&lt;p&gt;
Next time: how 'git merge' works.
&lt;p&gt;
&lt;b&gt;Footnotes&lt;/b&gt;
&lt;p&gt;
&lt;sup&gt;(1)&lt;/sup&gt; Or switch to git, which someday will probably be the
worldwide successor to svn.  The road there is much bumpier, though, as
git is much more confusing than SVN and does &lt;i&gt;not&lt;/i&gt; (yet?) have a strict
superset of SVN's features (it has some new things, but is missing some old
things).  I'll get to that later in this series.
&lt;p&gt;
&lt;sup&gt;(2)&lt;/sup&gt; Ironically, that_other_repository must &lt;i&gt;actually&lt;/i&gt; be
just another path in your current repository, even though SVN forces you to
specify the whole @#$#$ URL every single time.  This wouldn't be so
insulting except that I can't think of any good reason &lt;i&gt;why&lt;/i&gt; it has to
be in the same repository; the SVN merge algorithm should work just fine if
the changes exist in some totally different SVN repository, and even the
command-line syntax is designed to permit this.
&lt;p&gt;
&lt;sup&gt;(3)&lt;/sup&gt; Rumour has it that Subvers