Reduce Your Rails Schema Conflicts

24 Oct 2010

Update: hookup does all this for you and more!

Tired of conflicts on your schema file that boil down to the version specification at the top? Me too. After reading Will Leinweber’s article on resolving Gemfile.lock conflicts automatically, I decided I could do better. I started with a tweet and a gist, but after seeing the reception it received, I’m expanding it to a full-on blog post.

The snippet below goes in your ~/.gitconfig, and is basically a simple algorithm that resolves a schema version conflict by picking the higher number. Personally, I’d rather have an ugly mess in my Git config file than a second file I have to copy around everywhere or a gem I have to install.

[merge "railsschema"]
	name = newer Rails schema version
	driver = "ruby -e '\n\
		system %(git), %(merge-file), %(--marker-size=%L), %(%A), %(%O), %(%B)\n\
		b = File.read(%(%A))\n\
		b.sub!(/^<+ .*\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n=+\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n>+ .*/) do\n\
		  %(ActiveRecord::Schema.define(:version => #{[$1, $2].max}) do)\n\
		end\n\
		File.open(%(%A), %(w)) {|f| f.write(b)}\n\
		exit 1 if b.include?(%(<)*%L)'"

Now all that’s left is to tell Git to use that algorithm for db/schema.rb. You have to do this on a per project basis. You can either commit it to .gitattributes or keep it locally in .git/info/attributes.

db/schema.rb merge=railsschema

That’s it. I haven’t beat on it too hard yet, but it’s handled simple conflicts beautifully.