Skip to content

Children in Git

There are many ways to name commits in git. For example:

$ git show HEAD^ # the parent of the HEAD commit

This made me hope that there was an analog for finding an immediate child. I did not see any evidence of this in the docs. So I went on the git IRC room and engaged in a discussion.

I suggested using a syntax such as HEAD$ — inspired by regular expressions, which use ^ to match the beginning of a line and $ to match the end of a line. I got a lot of pushback along the lines of (1) “this can’t be sanely done” or (2) “I don’t see why this would be useful.”

1. “This can’t be sanely done”

I don’t believe it. I’m sure the git community has solved far harder problems already. Git stores a repository as a directed acyclic graph and it is easy to lookup a parent. Traversing to a child is more expensive (but probably not prohibitively expensive.) With some caching and incremental updating, looking up a child should not be very costly. This is an interesting discussion to have — and there are lots of salient details that we can talk about in the comments — but ultimately this is a matter of ‘how to do it’ not ‘if it can be done’.

2. “I don’t see why this would be useful”

I have mixed feelings about this statement. I understand that building software is about choices, and open source software is often about scratching your own itches. So I can understand why a person might say, “I wouldn’t use the child style syntax, so why should I care about it?” Indifference is one thing: it is perhaps natural. But sometimes people take indifference a step further and also say that the idea is not of value to the community — this is flawed. In any case, broad concepts of user interface symmetry and beauty have more gravitas than one-off individual preferences.

Design should drive implementation

Git is unnecessarily complicated to new users. Parts of the git community do not grok the importance of the user perspective. Symmetry and beauty are not just nice to have: they are essential drivers for API design. A good API design goes a long way in enhancing the user experience.

The intrinsic worth of symmetry

The discussion was interesting and civil but somewhat unsatisfying because there was an elephant in the room: the importance of symmetry as a fundamental concept. Sometimes I see things as symmetrical or beautiful and others just don’t. I will try to explain.

Symmetry in user interface design can be defended on psychological or linguistic grounds. Humans think in opposites. Hot and cold. Parent and child. Love and hate. Don’t let ‘opposite’ throw you — the ‘opposite’ relationship is a very strong cognitive link.

Once an API lets you find a parent, it won’t be long before a user asks for the ability to find the child. Big surprise! Opposites are just part of how humans think. My suggestion: when people ask for symmetry, give it to them whenever you can.

It is expensive to try to fight that expectation. So don’t. Build great software for people. Don’t propagate the status quo by holding onto your current view of the software as being ‘good enough.’

Instead, admit that your API has a little flaw (of asymmetry) and take an objective look at what can be done about it. Remember: API design is more important than implementation details; so change the implementation as needed.

Don’t try to convince users that their intuition is wrong; instead, build a better user experience so that their intuition is right. As the application designer, you have the ability to frame concepts as you see fit. Frame them so the opposites make sense and everyone will be better off.

Conclusion

Neither pushback #1 nor #2 convinced me. I suspect they are veneers; the real reason seems to be: (3) “we have more important things to work on”. There is nothing wrong with saying that, but I find it interesting when people do not admit it up front. It seems like a defense mechanism.

REST Fortune Cookie

Today is my lucky day. I had a fortune cookie with this gem inside: “Rest has a peaceful effect on your physical and emotional health.”

I interpret this as a message from Roy Fielding: “REST has a peaceful effect on your physical and emotional health.”

Broken == in MongoMapper

I am hoping to bring a few more eyes to an equality bug I found in MongoMapper:


p1 = Post.new
p2 = p1.dup
p1 == p2 # => true
# so far so good
p2.title = 'changed'
p1 == p2 # => false
# uh-oh!

If you want to see chaos, please join us for a spirited mailing list discussion. Despite my best efforts, it seems to be spiraling out of control.

Update as of 5:55pm: ActiveRecord gets it wrong, too, but in a different way:


p1 = Post.new
p2 = p1.dup
p1 == p2 # => false
# drat!
p2.title = 'changed'
p1 == p2 # => false
# double drat!

Update as of 6:08pm: DataMapper is the only one that gets it right:


p1 = Post.new
p2 = p1.dup
p1 == p2 # => true
# yay!
p2.title = "x"
p1 == p2 # => false
# yay!

Merb to Rails Transition

I found myself wondering about the planned transition from Merb 1.X to Rails 3. I did a little reading and research and would like to share the best information that I’ve found.

On June 28, Yehuda Katz said “we are ABSOLUTELY still planning on an easy transition path” [from Merb 1.X to Rails 3] in a helpful Merb mailing list discussion. The next day on the mailing list, Yehuda elaborated:

All the work [on Rails] we [(meaning Yehuda and Carl)] have done so far (and some we have yet to do) will make that transition possible. We could have started releasing some transitional releases [for Merb] over the past six months, but that would have been mostly guesswork, and we likely would have needed several different releases, requiring app changes, as we continued our work in Rails. As Ezra said, Merb is mostly stable at this point, and we’d like to keep it that way until we can offer something clear and compelling. We have some more work to do, but making it possible to transition smoothly remains a high priority for the Rails 3 release for Carl and I.

Bayard Randel asks on Stack Overflow: “I’d really like to know if it would be worth starting development in Merb now and then porting it to Rails, but I’ve yet to find anything suggesting how difficult this may be.” This is a shorter page, but the takeaway is clear: “If you’re using Merb today, continue using Merb. If you’re considering using Merb for a project because it works better for your needs, use Merb.” This quote is from Yehuda’s December 23, 2008 post that announced the Rails / Merb merger.

In terms of specific Merb releases: back in March, Matt Aimonetti talked about the Merb 1.1 roadmap which at the moment seems to be taking a bit longer than expected. You can find the Merb master branch on GitHub, which indicates the latest tagged release is 1.0.10.

HAppS-HTTP Not Looking Good

Just a few minutes ago, I wanted to take a look at HAppS, a Web server written in Haskell. I tried checking out HAppS-HTTP using the directions on the front page:
darcs get --partial --tag=0.9.2 http://happs.org/repos/HAppS-HTTP

Unfortunately, this failed with this error message:

darcs: failed to read patch:
Tue Dec 18 14:22:39 EST 2007 alex@happs.org
tagged 0.9.1.2
/Users/david/src/HAppS-HTTP/_darcs/patches/20071218192239-49c54-88c23fec4a12830b80c79ff71af2341d7cc59e1e.gz: openBinaryFile: does not exist (No such file or directory)

This is kind of sad. I’d like to check out HAppS, but I can’t even download it! This is not a good first introduction to a code base. :/

Please give this a try. If it fails for you too, please make a note here on ticket #39 in the issue tracker. Thanks!

On Philosophical Talks at Technical Conferences

Chad Fowler’s talk at Ruby Nation titled The Passionate Programmer has got me thinking. After writing a review over at SpeakerRate, I decided that it would be better to share my thoughts here.

I have mixed feelings about Chad’s presentation. On one hand, discussions along the lines of career development and life decisions are needed in the programming community. On the other, the subject areas of “life balance” and “passion” are very tricky to present. They are inherently subjective and philosophical.

Some of the content of Chad’s talk reminded me of the philosophies of Tim Ferriss which I find half-useful and half-not. I welcome discussion and even polarizing figures. But over time, I would prefer that Ruby conferences draw from a wider base of philosophical inspiration than just one popular and self-admitted master of self-promotion.

I find it telling that in the Ruby community, we’ve seen several successful Rubyists talk about life balance issues: DHH (RailsConf, a few years back), Chris Wanstrath (at RailsConf this year), and now Chad. These have been talks based in personal experience, and I have enjoyed them.

The issues of developing careers and finding meaning are well-worn topics. Just look at the shelves at any bookstore. Great thinkers and everyday people have struggled with these issues for thousands of years.

I hope we beware the echo-chamber effect — where Rubyists form little enclaves and isolate ourselves. We should seek out many voices: not just the ones of us “at the top” and not just programmers. If we Rubyists are truly interested in these subject areas, we should seek out a broad variety of thinkers and invite them to our conferences. I think we’d be better for it.

Fearless Git Merging

I just read a cool idea from the Git Internals PDF by Scott Chacon on page 33. If you don’t know how well a merge might work, just create a new branch and try the merge there. If it works, it will be easy enough to merge into your master branch as a next step.

Something that Mr. Chacon didn’t mention (at least not in the vicinity of page 33) is that there is a –no-commit flag on the git merge command:


--no-commit
Perform the merge but pretend the merge failed and do not
autocommit, to give the user a chance to inspect and further tweak
the merge result before committing.

API != Web protocol

According to a press release from the DC government announcing the new DC Government Open APIs:
“An API is a web protocol that gives programmers anywhere access to data on a web server to build custom applications using that data.”

Not quite. An API is not the same thing as a Web protocol. An API is layered on top of Web protocols. (As you probably know, there are a lot of interesting things happening with Web protocols lately; for example, XMPP and the Google Wave Federation Protocol.)

Tracking Remote Git Branches

Remote then Local

It is easy to setup a local branch (we’ll call it zzz here) to track a pre-existing remote branch:

$ git --track branch zzz origin/zzz

Alternately, if you use the branch.autosetupmerge setting in your git config to enable automatic branch tracking [1], the command is even shorter:

$ git branch zzz origin/zzz

Local then Remote (reverse)

This much is easy. But what about the reverse? In other words, how do you start with a local branch, push to a remote, and have the local track the remote?

Take One

Let’s give it a try. A warning: it isn’t quite as easy as you might hope.

$ git branch zzz
$ git checkout zzz
# make some changes to files ...
$ git push origin zzz
$ git pull origin zzz

The explicit form of git pull above works. But the shorter form “git pull” is easier, but when we try it we get an error message (but at least it is helpful):

$ git pull
From git@my-server.com:my_project
 * [new branch]      zzz -> origin/zzz
You asked me to pull without telling me which branch you
want to merge with, and 'branch.zzz.merge' in
your configuration file does not tell me either.	Please
specify which branch you want to merge on the command line and
try again (e.g. 'git pull <repository> <refspec>').
See git-pull(1) for details.

If you often merge with the same branch, you may want to
configure the following variables in your configuration
file:
    branch.zzz.remote = <nickname>
    branch.zzz.merge = <remote-ref>
    remote.<nickname>.url = <url>
    remote.<nickname>.fetch = <refspec>

See git-config(1) for details.

Adding those lines to the git config file by hand is doable, but not very elegant. You might rather use the command line way:

git config branch.zzz.remote origin
git config branch.zzz.merge refs/heads/zzz
# Note: I'm assuming you already have "origin" setup
# as a remote, so I don't include those commands here.

The latter way lends itself to scripting better than the former. Still, I wasn’t really satisfied with either approach.

Take Two

So I was curious to see if there are other ways to start with a local branch then create a remote branch and have automatic tracking. I did some searching and read over the following blog posts:

There was considerable diversity in the solutions presented.

Take Three

In my opinion, Mark Eli Kalderon’s post explains the simplest and most elegant approach. Here is his approach, slightly adapted:

$ git checkout -b zzz
# Let the hacking commence...
$ git push origin zzz
$ git checkout master # see note 2
$ git branch -f zzz origin/zzz
$ git checkout zzz
# Let the hacking continue...

The key to this approach is using the “-f” flag with “git branch” to force the re-creation of the local branch. It is short and easy to remember. If you find something simpler, please share it. Thanks.

Notes

  1. To enable automatic branch tracking globally, use:
    $ git config --global branch.autosetupmerge true
    

    To do it for a specific repository, use:

    $ git config branch.autosetupmerge true
    
  2. I added the “git checkout master” because otherwise the “git branch -f …” line would fail with this message: “fatal: Cannot force update the current branch.”
  3. It probably doesn’t matter for the purposes of this discussion, but I’m using git 1.6.2.3 installed via MacPorts (“sudo port install git-core”).

Ruby CouchDB Library Comparison

As I looked at some of the Ruby libraries for CouchDB, it was clear that they have very different approaches. In the hopes of keeping them straight I began making a table. I am sharing it for your right-angled pleasure. Warning, it is in beta form. If you post comments, I will try to incorporate your feedback in the table. Thanks!

Last updated on May 6, 2009.

RelaxDB CouchREST CouchFoo DataMapper (DM) Rest Adapter CouchObject Ruby-CouchDB ActiveCouch Coach Potato
Source Code paulcarey on GitHub jchris on GitHub georgepalmer on GitHub

datamapper on GitHub couchobject at RubyForge couchdb at RubyForge activecouch at RubyForge couch_potato on GitHub
Underlying HTTP Library [1] Net::HTTP REST Client ? Net::HTTP ? ? ? REST Client (couchrest is a dependency)
Interface ? ? ActiveRecord style DataMapper style ? Thin wrapper over CouchDB’s RESTful API ActiveRecord style
ORM specific? [2] N ? N ? N ? Y – DataMapper N ? N N ?
Automatic view creation? ? ? ? ? ? ? ? Y
Quality of test suite? ? ? ? ? ? ? ? ?
Do you need to write Javascript? [3] ? ? ? ? ? ? ? Y

Notes:

  1. I personally think Net::HTTP is a bit crufty. I prefer to see other Ruby HTTP libraries, such as HTTParty.
  2. Does a library only works with a particular Object Relational Mapper (ORM)?
  3. Does a library require that you write Javascript? Or does it generate the JS for you automatically? (I am not taking sides on which is better.)