Каков наилучший способ решения потерянных миграций Rails?

Я переключался между ветвями в проекте, и у каждой из них разные миграции... Это сценарий:

$ рейк БД:мигрировать:статус

 Status   Migration ID    Migration Name
--------------------------------------------------
   ...
   up     20130307154128  Change columns in traffic capture
   up     20130311155109  Remove log settings
   up     20130311160901  Remove log alarm table
   up     20130320144219  ********** NO FILE **********
   up     20130320161939  ********** NO FILE **********
   up     20130320184628  ********** NO FILE **********
   up     20130322004817  Add replicate to root settings
   up     20130403190042  ********** NO FILE **********
   up     20130403195300  ********** NO FILE **********
   up     20130403214000  ********** NO FILE **********
   up     20130405164752  Fix ap hostnames
   up     20130410194222  ********** NO FILE **********

Проблема в том, что rake db:rollback вообще не работает из-за отсутствующих файлов...

Что я должен сделать, чтобы иметь возможность снова откатиться и избавиться от сообщений NO FILE?

Кстати, rake db:reset или rake db:drop не вариант, я не могу потерять данные из других таблиц...


person Adrian    schedule 16.04.2013    source источник


Ответы (10)


В итоге я решил проблему следующим образом:

(1) Перейдите в ветки с файлами миграции и откатите их. Это не тривиально, когда у вас много ветвей, которые приведут к множеству конфликтов, если вы попытаетесь их объединить. Поэтому я использую эти команды, чтобы узнать, к каким ветвям принадлежит каждая потерянная миграция.

Итак, мне нужно найти фиксацию последнего изменения миграции.

git log --all --reverse --stat | grep <LASTEST_ORPHAN_MIGRATION_ID> -C 10

Я беру хэш коммита и определяю, какой ветке он принадлежит, вот так:

git branch --contains <COMMIT_HASH>

Затем я могу вернуться к этой ветке, выполнить откат и повторить этот процесс для всех отсутствующих файлов.

(2) Запустите миграцию: проверьте ветку, над которой вы, наконец, хотите работать, и запустите миграцию, и все готово.

Устранение неполадок

Я также запускал в некоторых случаях, когда потерянные миграции были в удаленных ветках.

Чтобы решить эту проблему, я создал фиктивные файлы миграции с тем же миграционным_идентификатором отсутствующих файлов и откатил их. После этого я смог удалить фиктивные миграции и получить чистый статус миграции :)

Другой альтернативой является удаление отсутствующих файлов напрямую из базы данных:

delete from schema_migrations where version='<MIGRATION_ID>';
person Adrian    schedule 22.04.2013
comment
отличный ответ. Дайте нам более легкий, короткий, практичный путь первым, а не последним! =] Я был весь в стрессе, пока, о. хороший - person ahnbizcad; 16.09.2014
comment
Где вы это печатаете? delete from schema_migrations where version='<MIGRATION_ID>'; - person ahnbizcad; 16.09.2014
comment
в консоли вашей базы данных... вы можете получить к ней доступ, набрав: rails dbconsole - person Adrian; 16.09.2014
comment
@ Адриан, еще короче, вы можете ввести rails db ;) - person kittyminky; 24.02.2017
comment
Если у вас возникли проблемы с запуском rails db, как у меня, вы также можете сделать то же самое из консоли rails, например: sql = "delete from schema_migrations where version='<MIGRATION_ID>';", а затем ActiveRecord::Base.connection.execute(sql) - person Hubert Jakubiak; 28.11.2018

Миграции хранятся в вашей базе данных. Если вы хотите удалить заброшенные миграции, удалите их из базы данных.

Пример для Постгреса:

  1. Откройте psql:

    psql
    
  2. Подключиться к вашей БД:

    \c your_database
    
  3. Если вам интересно, отобразите schema_migrations:

    SELECT * FROM schema_migrations;
    
  4. Если вам интересно, проверьте, присутствуют ли заброшенные миграции:

    SELECT version FROM schema_migrations WHERE version IN 
    ('20130320144219', '20130320161939', '20130320184628', '20130403190042',
     '20130403195300', '20130403214000', '20130410194222');
    
  5. Удалите их:

    DELETE FROM schema_migrations WHERE version IN (<version list as above>);
    

Теперь, если вы запустите bundle exec rake db:migrate:status, вы увидите, что потерянные миграции были успешно удалены.

person medik    schedule 25.10.2016
comment
Спасибо, это потрясающе и не испортило мои промежуточные данные. - person Alba Hoo; 17.01.2018

Изменить: СЛЕДУЮЩИЕ УСЛОВИЯ УДАЛЯЮТ ВАШУ БАЗУ ДАННЫХ

Более простой подход, который сработал для меня (обратите внимание, что эта команда удалит базу данных, и все ваши данные будут потеряны):

rake db:migrate:reset

..а потом:

rake db:migrate:status

Сироты должны исчезнуть.

person spandata    schedule 13.03.2014
comment
ВНИМАНИЕ: db:migrate:reset удалит базу данных, что приведет к полной потере данных!! - person Phil; 14.01.2015
comment
ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ СООБЩЕНИЕ ВЫШЕ. Не выполняйте сброс базы данных, так как вы потеряете все свои данные. - person Alex Villa; 06.03.2015
comment
«Я не всегда уничтожаю свою базу данных, но когда я это делаю, это происходит потому, что я сначала не читаю комментарии SO. - person Dem Pilafian; 11.03.2015
comment
Ядерная бомбардировка с орбиты гарантированно устранит сирот. - person Andrew Grimm; 10.08.2016
comment
@ЭндрюГримм, ха-ха! а так же любые другие дети и мужчины живые :/ - person Magne; 07.06.2017
comment
Какой садист поддерживает это как ответ? Не делайте этого, чтобы удалить потерянные миграции. - person Clintm; 20.12.2018

Вот версия ответа psql от @medik, которая не сотрет вашу базу данных и не сделает ничего сумасшедшего:

1) Найдите потерянные версии миграции:

rails db:migrate:status

2) Обратите внимание на версии отсутствующих миграций и перейдите в консоль БД:

rails dbconsole

3) Теперь удалите версии из таблицы миграции вручную:

delete from schema_migrations where version='[version_number]';
person stackPusher    schedule 19.07.2019
comment
Это сработало для меня, Rails 6.0.0. Красиво, чисто и просто. - person LunaCodeGirl; 11.11.2019
comment
Это было очень полезно, большое спасибо! - person kdweber89; 02.02.2021
comment
примечание: удалите [ ] из версии, если есть только 1 номер версии. - person Robert; 26.07.2021

создайте новые файлы с такими именами, как 20130320144219_migration_1, поместите пустой код в

class Migration1 < ActiveRecord::Migration 
  def change; end 
end 

и запустите команду rails db:migrate:down VERSION= 20130320144219 и наконец - удалите эти файлы

person Evseev Vadim    schedule 20.04.2020

Вот задача грабли, которую я написал для этой цели. Он вызывает тот же метод, который db:migrate:status использует под капотом, ActiveRecord::Base.connection.migration_context.migrations_status

# lib/tasks/cleanup_migration_entries.rake

desc 'Removes schema_migration entries for removed migration files'
task 'db:migrate:cleanup': :environment do
  migration_context = ActiveRecord::Base.connection.migration_context
  versions_to_delete =
    migration_context.migrations_status
                     .filter_map { |_status, version, name| version if name.include?('NO FILE') }

  migration_context.schema_migration.delete_by(version: versions_to_delete)

  puts "Cleaned up #{versions_to_delete.size} orphaned migrations."
end
person Jared    schedule 01.09.2020

Предполагая, что вы используете Git, должно быть относительно просто получить эти миграции и перенести их в вашу текущую ветку. Если у вас есть конкретная фиксация, из которой вы хотите получить файл, вы можете использовать:

git checkout <commit hash> <file_name>

(Благодаря этому ответ)

В качестве альтернативы вы можете проверить из определенной ветки HEAD:

git checkout <branch name> -- <file_name>

Согласно этому сообщению в блоге

Предполагая, что на самом деле это версии миграций, выполняемых в базе данных, вы должны быть готовы к откату.

person mikeryz    schedule 16.04.2013
comment
Спасибо за ответы. Проблема в том, что я работаю над большим проектом с большим количеством филиалов и разработчиков. Итак, я не знаю, в какой ветке есть потерянная миграция. Наконец-то я нашел способ (см. мой ответ) - person Adrian; 22.04.2013

Вы можете объединить две ветки обратно в мастер, чтобы у вас были все доступные миграции. Если вам действительно не нужны эти миграции, но вы хотите иметь возможность отката, вы можете отредактировать таблицу schema_migrations в своей базе данных, чтобы удалить строки, соответствующие миграциям, для которых у вас нет файлов. Однако это вызовет проблемы, если вы затем переключитесь на другую ветку с другими миграциями.

person Whit Kemmey    schedule 20.04.2013
comment
Это хорошая идея - временно объединить ветки и выполнить откат до тех пор, пока не будет достигнуто хорошее состояние. Однако у некоторых веток не было коммита ближайшего предка, поэтому у них будет множество конфликтов во время слияния... Я решил вернуться к каждой из веток, содержащих осиротевшие миграции, откатить их, а затем снова вернуться к моей ветке. .. - person Adrian; 22.04.2013

Если файлы миграции действительно отсутствуют (например, выполнили миграцию, забыли откатить миграцию, а затем удалили файл миграции перед фиксацией), я смог воспроизвести отсутствующую миграцию следующим образом:

  1. вернуться в историю git, чтобы получить копию файла schema.rb и сохранить его вне репозитория git (git log; git checkout xxxxxx; cp schema.rb ~/schema_old.rb, git checkout master).
  2. запустите diff для двух файлов и скопируйте команды миграции в файл миграции, который соответствует отсутствующему идентификатору миграции (diff schema.rb ~/schema_old.rb > migration_file.rb; vi migration_file.rb)
  3. Проверьте свой статус миграции и откат (rake db:migrate:status; rake db:rollback; rake db:migrate:status;)
person Taylored Web Sites    schedule 01.02.2017

Один вкладыш для консоли Rails, если у вас есть номера версий из неудачных rake db:migrate или NO FILE записей из rake db:migrate:status

 class SchemaMigration < ActiveRecord::Base; end; SchemaMigration.where(version: %i[the version numbers to delete]).delete_all

Это означает, что с терминала вы можете

rails runner "class SchemaMigration < ActiveRecord::Base; end; SchemaMigration.where(version: %i[the version numbers to delete]).delete_all"

Хотя в этот момент может быть быстрее использовать одну из прямых команд базы данных из предыдущих ответов.

person Chad M    schedule 04.06.2020