Skip to content

Instantly share code, notes, and snippets.

@jswanner
Last active April 1, 2021 22:05
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save jswanner/5293719 to your computer and use it in GitHub Desktop.
Save jswanner/5293719 to your computer and use it in GitHub Desktop.
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