1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
namespace :migrations do desc 'reverts, renames and re-executes uncommitted migrations that conflict with already committed migrations' task :repair => :environment do uncommitted = `svn status`.select {|line| line =~ /db\/migrate\//}.collect {|line| line.match(/ db\/migrate\/(.*rb)/)[1]} committed = Dir.glob('db/migrate/*').collect {|line| line.match(/db\/migrate\/(.*rb)/)[1]} - uncommitted highest_committed = committed.collect(&:to_i).max lowest_uncommitted = uncommitted.collect(&:to_i).min schema_version = ActiveRecord::Base.connection.select_one("select version from schema_info")["version"].to_i # revert uncommitted migrations uncommitted.sort_by(&:to_i).reverse.each do |migration| version = migration.to_i if version <= schema_version name = migration.match(/(\d*_.*).rb/)[1] class_name = (require 'db/migrate/' + name)[0] puts class_name.constantize.down end end #set it back to the version prior to all the uncommitted migrations - this doesn't get done automatically by calling down ActiveRecord::Base.connection.execute("update schema_info set version=#{schema_version-1}") version_offset = (highest_committed - lowest_uncommitted) + 1 uncommitted.each do |old_name| version = old_name.to_i + version_offset new_name = version.to_s.rjust(3,'0') + old_name.gsub(/\d/, '') `mv db/migrate/#{old_name} db/migrate/#{new_name}` end puts "Uncommited migrations have been reversed and renamed. You can now migrate." end end
Refactorings
No refactoring yet !
macournoyer
October 29, 2007, October 29, 2007 20:57, permalink
This is the most useful rake task ever for a Rails user!
A couple of changes:
* rename to db:migrate:repair
* fix version on line 24 if more then one uncommitted migration
* invoke db:migrate at the end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
namespace :db do namespace :migrate do desc 'Reverts, renames and re-executes uncommitted migrations that conflict with already committed migrations' task :repair => :environment do uncommitted = `svn status`.select {|line| line =~ /db\/migrate\//}.collect {|line| line.match(/ db\/migrate\/(.*rb)/)[1]} committed = Dir.glob('db/migrate/*').collect {|line| line.match(/db\/migrate\/(.*rb)/)[1]} - uncommitted highest_committed = committed.collect(&:to_i).max lowest_uncommitted = uncommitted.collect(&:to_i).min schema_version = ActiveRecord::Base.connection.select_one("SELECT version FROM schema_info")["version"].to_i # revert uncommitted migrations uncommitted.sort_by(&:to_i).reverse.each do |migration| version = migration.to_i if version <= schema_version name = migration.match(/(\d*_.*).rb/)[1] class_name = (require 'db/migrate/' + name)[0] puts class_name.constantize.down end end # set it back to the version prior to all the uncommitted migrations - this doesn't get done automatically by calling down ActiveRecord::Base.connection.execute("UPDATE schema_info SET version = #{schema_version - uncommitted.size}") version_offset = (highest_committed - lowest_uncommitted) + 1 uncommitted.each do |old_name| version = old_name.to_i + version_offset new_name = version.to_s.rjust(3,'0') + old_name.gsub(/\d/, '') `mv db/migrate/#{old_name} db/migrate/#{new_name}` end Rake::Task['db:migrate'].invoke end end end
Explained here: http://www.danielharan.com/2007/10/26/rails-migrations-handling-naming-conflicts/