Skip to content

Instantly share code, notes, and snippets.

@jswanner
Last active August 15, 2024 15:15
Rolls back migrations in current branch not present in specified branch.
desc 'rolls back migrations in current branch not present in other'
task :rollback_branch_migrations, [:other_branch] do |t, args|
load "#{Dir.pwd}/Rakefile"
branch_migrations = BranchMigrations.new(args.other_branch)
puts ['Rollback the following migrations', branch_migrations, 'y,n? ']
next if %w[no n NO N].include?(STDIN.gets.chomp)
Rake::Task['environment'].invoke
migrate_task = Rake::Task['db:migrate:down']
branch_migrations.each_version do |version|
ENV['VERSION'] = version
migrate_task.execute
end
puts 'Will probably need to discard changes to db/schema.rb'
end
class BranchMigrations
def initialize other_branch
@other_branch = other_branch
end
attr_reader :other_branch
def each_version
filenames.each do |filename|
yield filename.split('_')[0]
end
end
def filenames
list.map { |migration_path| migration_path.match(%r{/(\d+.*)\z})[1] }
end
def list
@list ||= begin
list = %x{git diff #{other_branch} --name-only --diff-filter=A db/migrate/}
list.split.reverse
end
end
def to_ary; filenames end
end
@jswanner
Copy link
Author

jswanner commented Apr 2, 2013

Installation:

# use a different filename if you already have a ~/.rake/migrate.rake file
curl "https://gist.githubusercontent.com/jswanner/5293719/raw/migrate.rake" --create-dirs -o ~/.rake/migrate.rake

Usage:

While in topic branch with migrations, before switching to another branch (such as master):

rake -g rollback_branch_migrations[master]

The migrations to be rolled back will be listed, then a prompt for acknowledgement before continuing.

Note:

Running this command will make your local database no longer match the definition defined in db/schema.rb, and therefore that file will be modified. But, you do not want to commit the changes to the db/schema.rb file, you can undo the changes to the file by running:

git checkout -- db/schema.rb

@olivierlacan
Copy link

I'm scope creeping but it would be nice to add proper error handling when there are pending migrations, otherwise it errors like this:

rake aborted!
ActiveRecord::ConnectionNotEstablished
/Users/olivierlacan/.rake/migrate.rake:14:in `block (2 levels) in <top (required)>'
/Users/olivierlacan/.rake/migrate.rake:29:in `block in each_version'
/Users/olivierlacan/.rake/migrate.rake:28:in `each'
/Users/olivierlacan/.rake/migrate.rake:28:in `each_version'
/Users/olivierlacan/.rake/migrate.rake:12:in `block in <top (required)>'
Tasks: TOP => rollback_branch_migrations

@olivierlacan
Copy link

Actually, even when I fix pending migrations it errors out:

$ bundle exec rake -g rollback_branch_migrations[master]
Rollback the following migrations
20140429233035_remove_mixpanel_columns_on_users.rb
y,n? 
y
rake aborted!
ActiveRecord::ConnectionNotEstablished
/Users/olivierlacan/.rake/migrate.rake:14:in `block (2 levels) in <top (required)>'
/Users/olivierlacan/.rake/migrate.rake:29:in `block in each_version'
/Users/olivierlacan/.rake/migrate.rake:28:in `each'
/Users/olivierlacan/.rake/migrate.rake:28:in `each_version'
/Users/olivierlacan/.rake/migrate.rake:12:in `block in <top (required)>'
Tasks: TOP => rollback_branch_migrations
(See full trace by running task with --trace)

I'm running rake 0.9.6

@jswanner
Copy link
Author

Hmm, I haven't seen that error when using this Rake task before. I don't use bundle exec, have you tried running it without that, or using a binstub instead?

@jswanner
Copy link
Author

@olivierlacan I've found the ActiveRecord::ConnectionNotEstablished problem you were running into and it's been fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment