# hash

Why I Won’t Squash My Commits

tl;dnr

While I really appreciate the constructive comments I get on pull requests I make, there’s one type of comment I have a hard time with.

Please don’t ask me to squash the commits of my pull requests.

Don’t ask me because, with all due respect to the amazing work from committers, I won’t do it.

Unless I’ve made an actual mistake, if my pull request has 5 commits, it is because each of them is independent and I feel they should remain so.

If they really want to, project committers can manually squash and merge the commits, wait for someone else to make a PR with the commits squashed or even reject the PR.

Call it lunacy or pride, but I just won’t squash my commits. Hopefully committers won’t take offense at that as I’ll do my best to not take offense at their suggestion that I didn’t segment my commits correctly.

Why committers ask to squash commits?

I imagine the historical reason it that many contributors aren’t super comfortable with git and git rebase -i in particular, so their commits represent their train of thought, not a sequence of independent changes to apply. E.g.:

  • Introduce <great feature>
  • Oops, fix typo
  • Oh oh, fix a bug of <great feature>
  • Fix bug of <great feature> (for real this time)

For these contributors, it is mandatory that the commits are not accepted as is. Squashing the whole thing is usually the safest bet.

There are many contributors that use git rebase -i and git commit -p in their sleep though, so that won’t be the situation.

The other reason I’ve been told is that “we generally squash all commits so that it’s easy to backport/revert”. I can’t agree with that. First, it is much more difficult to backport/revert just part of the PR if it is squashed. Morever, it’s pretty easy to backport/revert the whole PR by using git revert and git cherry-pick either with a range of commits or the merge commit. Less than 2% of commits get reverted anyways.

When should committers not ask to squash commits?

If all commits can stand on their own, i.e. all tests pass after each individual commit, then the commits are atomic and do not need to be squashed. I’d even say they probably shouldn’t be squashed.

My commits are typically the smallest unit of change that will work and still pass all tests. The main exception is a commit of a bunch of trivial changes that are isolated (e.g. removing trailing whitespace, fixing a bunch of typos in the doc,renaming of a local variable). Even then, I won’t commit doc typos and renaming of a variable together, say.

When doing a refactor, I will usually split the changes in small independent refactoring commits. I believe it makes it easier to understand and judge than one big commit.

A rather telling example was this PR I made recently. It aims at fixing one bug, but I broke it down into 15 commits. Each consists of a single refactoring step in the right direction, until the last commit which is the one fixing the bug per say. It’s easier to see the validity of each change this way, while the combined diff has a lot of noise and does a bunch of different things at once. I just can’t grok the combined diff.

I’m not asking everyone to structure their commits with such detail and attention; I’m only asking that it be, if not appreciated, at least accepted to do so.

DRY Migrations

I wanted to write a post about the many things that should be fixed with Rails.

Interestingly, Rails 3.1 fixes quite many of these.

Method_missing, Politely

In their Polite Programmer talk at Rubyconf, Jim Weirich and Chris Nelson pointed out that merely adding some behavior with method_missing wasn’t quite polite, as shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class StereoPlayer
  def method_missing(method, *args, &block)
    if method.to_s =~ /play_(\w+)/
      puts "Here's #{$1}"
    else
      super
    end
  end
end

p = StereoPlayer.new
# ok:
p.play_some_Beethoven # => "Here's some_Beethoven"
# not very polite:
p.respond_to? :play_some_Beethoven # => false

In order for respond_to? to return true, one can specialize it

Fixing MRI, a Dozen Steps at a Time

Is there a term like bugfield? You know, when everytime you get to take a couple of steps in a code base you encounter a different bug, which leads to another one, …, like a minefield of bugs?

Here was my last sequence in Ruby (MRI)…

Main goal: improve Matrix#determinant and #rank after a suggestion of Yu Ichino. The bulk of the work took me quite a while, as I had to check a bunch of things, understand the algorithm, do some performance testing, etc…

Best Time to Get Involved in Ruby Core

Apart from enjoying the summer, I’ve spent time hacking on MRI, especially since I’ve been accepted as a committer. The feature freeze for Ruby 1.9.2 was planned for yesterday and this has been pushed back a couple of days before. Rejoice!

Why?

Stickler in Silicon Valley

I have not been actively looking for a job yet. Nevertheless, I was contacted by a startup and invited to spend a week in Silicon Valley / San Francisco, hacking around with them to see if I could become part of their team, which I found quite flattering. I learned lots of new things in California. A couple of new words too. I’m still unsure as to what exactly a hipster is, but “stickler” was easier to grasp: one who insists on exactness or completeness in the observance of something.

A Schizo Ruby Puzzle

Quick quirky quiz (schizo version)

1
2
3
4
# Without writing any method/block/lambda,
# can you find ways to obtain, in Ruby 1.8.7 or 1.9:
x == y   # ==> true
y == x   # ==> false

Here’s how I got to checkout Ruby’s source and stumble upon that.

Lost in Recursion

Last time I asked a simple (but quite hard) Ruby quiz:

1
2
3
4
# Without writing any method/block/lambda,
# can you find ways to obtain, in Ruby 1.8.7 or 1.9:
x == y   # ==> true
y == x   # ==> false