Subverted Migrations
I got fed up with the lack of best practice for working with Rails migrations across source control branches, so I decided to write a little Rails plugin. Here it is: the first release of Subverted Migrations!
This is a plugin that manages your migration versions across Subversion branches. It has two primary functions:
- It scans all of your Subversion branches and trunk to find a safe version number when creating migrations.
- It keeps track (à la svnmerge.py) of which migrations have been applied, and applies new migrations when they are merged back into the branch. (A detailed example exploring this feature is below.)
Warning
Careful, it's alpha! Please back up your schemas and data before trying this. At this time, it is only tested on OS X and PostgreSQL.
Getting It
script/plugin install \ svn://svn.madriska.com/plugins/subverted_migrations
Example (with Chunky Bacon)
Assume you have trunk and a ChunkyBacon branch (/branches/chunky_bacon). Both
have their latest migration at revision 010.
You create a migration in trunk:
[trunk]$ script/generate migration BoringBacon
exists db/migrate
create db/migrate/011_boring_bacon.rb
Next, you want to create a migration in branches/chunky_bacon. Without this
plugin, the new migration would have version number 011 and would create a
merge conflict. With the plugin, the version numbers are kept in sync:
[branches/chunky_bacon]$ script/generate migration ExtraCrispy
exists db/migrate
create db/migrate/012_extra_crispy.rb
The migration scripts should work as usual, but behind the scenes they keep
track of which migrations have been run, à la svnmerge.py. So let's say you
run the migration from the branch:
[branches/chunky_bacon]$ rake db:migrate Current version: 1-10 Target version: 1-12 == ExtraCrispy: migrating ================================================== (...) == ExtraCrispy: migrated (0.0000s) ========================================= Final version: 1-10,12
This indicates that the migrated version contains migrations 1-10 (from
before), as well as the ExtraCrispy revision (12). Once the Rake script detects
that a file matching "db/migrate/011_*" has been added, it will apply that
change as well. So if you merge the BoringBacon change from trunk into the
Chunky Bacon branch, just run "rake db:migrate" and it will pick up the new
change:
[branches/chunky_bacon]$ (svnmerge...) [branches/chunky_bacon]$ rake db:migrate Current version: 1-10,12 Target version: 1-12 == BoringBacon: migrating ================================================== (...) == BoringBacon: migrated (0.0000s) ========================================= Final version: 1-12
Note that version 11 has been incorporated, and now the version is 1-12.
You may also specify a version string on the command line. It can either be a
series of ranges or numbers separated by commas ("1-6,7,12-42") or a single
number, as before ("12", equivalent to "1-12"). To specify a single revision,
you must express it as a range (to migrate to revision 6 only, specify "6-6").
To back out the BoringBacon change, we would specify the version string that
removes version 11. The plugin includes a Rake task to show the current
version:
[branches/chunky_bacon]$ rake db:version 1-12
We remove 11 from the range and give the new range as an environment variable:
[branches/chunky_bacon]$ rake db:migrate VERSION="1-10,12" Current version: 1-12 Target version: 1-10,12 == BoringBacon: reverting ================================================== (...) == BoringBacon: reverted (0.0000s) ========================================= Final version: 1-10,12
And now the change is backed out.