Нужно ли добавлять файлы миграции в git
Я работаю над приложением rails с несколькими ветками git, и многие из них включают миграцию db. Мы стараемся быть осторожными, но иногда какой-то фрагмент кода в мастере запрашивает столбец, который был удален/переименован в другой ветке.
Что было бы хорошим решением для «связывания» веток git с состояниями БД?
Какими на самом деле были бы эти «состояния»?
Мы не можем просто продублировать базу данных, если ее размер составляет несколько ГБ.
А что должно происходить со слияниями?
Будет ли решение переведено на базы данных noSQL?
В настоящее время мы используем MySQL, mongodb и Redis.
РЕДАКТИРОВАТЬ: Похоже, я забыл упомянуть очень важный момент, меня интересует только среда разработки , но с большими базами данных (размером несколько ГБ).
Что вы делаете, если у вас есть среда, в которой работает ваша главная ветка, база данных которой может быть изменена другими ветками? Я не понимаю, каков ваш рабочий процесс или почему вы думаете, что вам нужно синхронизировать ветки с определенными базами данных.
Допустим, у нас в базе есть таблица с клиентами (имя, емейл, телефон) и в ветке мы разбиваем одну из колонок (имя -> имя_имя+фамилия). Пока мы не объединим ветку с мастером, мастер и все остальные ветки на его основе не будут работать.
Когда вы добавляете новую миграцию в любую ветку, запустите rake db:migrate и зафиксируйте как миграцию , так и db/schema.rb
Если вы сделаете это, в процессе разработки вы сможете переключиться на другую ветку с другим набором миграций и просто запустить rake db:schema:load .
Обратите внимание, что при этом будет воссоздана вся база данных, а существующие данные будут потеряны .
Вы, вероятно, захотите запустить производство только из одной ветки, с которой вы очень осторожны, поэтому эти шаги не применимы к ней (просто запустите там, rake db:migrate как обычно). Но при разработке не должно быть большой проблемы воссоздать базу данных из схемы, что и rake db:schema:load будет делаться.
Я думаю, что это решит только проблему схемы, данные будут потеряны при каждой миграции вниз, и их больше никогда не увидят. Было бы неплохо сохранить какой-нибудь патч db-data-patch, который сохраняется при перемещении из ветки, и другой, который загружается при переходе в другую ветку? Патчи должны содержать только те данные, которые будут потеряны по пути вниз (миграции).
Если вы хотите загрузить данные, используйте db/seeds.rb . Это не должно быть слишком разрушительным, чтобы уничтожить вашу БД разработки, если вы настроите там разумные начальные данные.
не надо ничего бомбить. см. мое решение ниже. Просто имейте в виду, что у вас будет много экземпляров, и когда вы переключаете ветки, данных там нет. Это совершенно нормально, если вы разрабатываете тесты.
Спасибо, Энди, этот ответ также мой вопрос. И договоритесь об использовании db/seeds.rb для повторного заполнения потерянных данных БД.
Для больших сложных приложений, где вам нужно воспроизвести реальные ошибки локально, абсолютно невозможно использовать файл сидов, вам нужны реальные данные из производства (или постановки). И восстановление базы данных может занять довольно много времени, так что нет, это не очень хорошее решение для моего случая.
Если у вас есть большая база данных, которую вы не можете быстро воспроизвести, я бы рекомендовал использовать обычные инструменты миграции. Если вам нужен простой процесс, я бы рекомендовал следующее:
- Перед переключением ветвей выполните откат ( rake db:rollback ) к состоянию перед точкой ветвления. Затем, после переключения веток, запустите db:migrate . Это математически правильно, и пока вы пишете down сценарии, это будет работать.
- Если вы забудете это сделать перед переключением веток, то в целом вы можете спокойно переключаться назад, откатывать и снова переключаться, так что я думаю, как рабочий процесс, это осуществимо.
- Если у вас есть зависимости между миграциями в разных ветках. что ж, вам придется хорошенько подумать.
Вы должны иметь в виду, что не все миграции являются обратимыми, тем не менее, первый предложенный шаг не гарантирует успеха. Я думаю, что в среде разработки хорошей идеей было бы использовать rake db:schema:load и rake db:seed , как сказал @noodl.
@pisaruk Я знаю, что вы ответили на этот вопрос шесть лет назад, но мне любопытно, каким может быть пример необратимой миграции. Я с трудом представляю себе ситуацию. Я предполагаю, что самым простым будет отброшенный столбец, содержащий кучу данных, но его можно «обратить», чтобы иметь пустой столбец или столбец с некоторым значением по умолчанию. Вы думали о других случаях?
Я думаю, вы сами ответили на свой вопрос! Да, отброшенный столбец — хороший пример. Или деструктивная миграция данных.
Вот скрипт, который я написал для переключения между ветками, содержащими разные миграции:
Это не решит всех проблем, о которых вы упомянули, но, учитывая имя ветки, это:
- Откатите любые миграции в вашей текущей ветке, которые не существуют в данной ветке.
- Отменить любые изменения в файле db/schema.rb.
- Проверьте данную ветку
- Запустите любые новые миграции, существующие в данной ветке.
- Обновите тестовую базу данных
Я постоянно делаю это вручную в нашем проекте, поэтому я подумал, что было бы неплохо автоматизировать этот процесс.
Этот скрипт делает именно то, что я хочу сделать, я бы хотел, чтобы он был помещен в крючок автоматической проверки.
В вашем сценарии вы действительно хотели сказать git checkout db/schema.rb или имели в виду git checkout -- db/schema.rb ? (т.е. с двойным тире)
Ну да. В то время я не знал о двойных тире. Но команда будет работать так же, если у вас нет ветки с именем db/schema.rb . :)
Это единственный способ летать.
lib/tasks/db.rake
Вот задача Rake, чтобы легко клонировать вашу базу данных из одной ветки в другую. Это принимает a SOURCE_BRANCH и TARGET_BRANCH переменные окружения. На основе задачи @spalladino .
Обновление от 16 октября 2017 г.
Я вернулся к этому через некоторое время и внес некоторые улучшения:
- Я добавил еще одну задачу rake для пространства имен, чтобы создать ветку и клонировать базу данных одним махом с расширением bundle exec rake git:branch .
- Теперь я понимаю, что клонирование из master — это не всегда то, что вы хотите сделать, поэтому я сделал более явным, что db:clone_from_branch задача принимает переменную окружения SOURCE_BRANCH и . TARGET_BRANCH При git:branch его использовании будет автоматически использоваться текущая ветка в качестве файла SOURCE_BRANCH .
- Рефакторинг и упрощение.
config/database.yml
А чтобы вам было проще, вот как вы обновляете свой database.yml файл, чтобы динамически определять имя базы данных на основе текущей ветки.
10 Answers 10
The migration files for each app live in a “migrations” directory inside of that app, and are designed to be committed to, and distributed as part of, its codebase. You should be making them once on your development machine and then running the same migrations on your colleagues’ machines, your staging machines, and eventually your production machines.
If you follow this process, you shouldn't be getting any merge conflicts in the migration files.
When merging version control branches, you still may encounter a situation where you have multiple migrations based on the same parent migration, e.g. if to different developers introduced a migration concurrently. One way of resolving this situation is to introduce a merge_migration. Often this can be done automatically with the command
which will introduce a new migration that depends on all current head migrations. Of course this only works when there is no conflict between the head migrations, in which case you will have to resolve the problem manually.
Given that some people here suggested that you shouldn't commit your migrations to version control, I'd like to expand on the reasons why you actually should do so.
First, you need a record of the migrations applied to your production systems. If you deploy changes to production and want to migrate the database, you need a description of the current state. You can create a separate backup of the migrations applied to each production database, but this seems unnecessarily cumbersome.
Second, migrations often contain custom, handwritten code. It's not always possible to automatically generate them with ./manage.py makemigrations .
Third, migrations should be included in code review. They are significant changes to your production system, and there are lots of things that can go wrong with them.
So in short, if you care about your production data, please check your migrations into version control.
lib/tasks/git.rake
Эта задача создаст ветку git из текущей ветки (мастер или что-то другое), проверит ее и клонирует базу данных текущей ветки в базу данных новой ветки. Это гладкий автофокус.
Теперь все, что вам нужно сделать, это запустить bundle exec git:branch , ввести новое имя ветки и начать убивать зомби.
Возможно, вы должны принять это как намек на то, что ваша база данных разработки слишком велика? Если вы можете использовать db/seeds.rb и меньший набор данных для разработки, ваша проблема может быть легко решена с помощью schema.rb и seed.rb из текущей ветки.
Это предполагает, что ваш вопрос относится к разработке; Я не могу представить, почему вам нужно регулярно переключать ветки в производстве.
Я боролся с той же проблемой. Вот мое решение:
Для развертывания в рабочей среде должен быть один человек/машина. Назовем эту машину машиной слияния. Когда изменения переносятся на машину слияния, автоматическое слияние для schema.rb завершится ошибкой. Без вопросов. Просто замените содержимое любым предыдущим содержимым для schema.rb (вы можете отложить копию или получить ее из github, если вы ее используете. ).
Вот важный шаг. Миграции от всех разработчиков теперь будут доступны в папке db/migrate. Идем дальше и запускаем пакет exec rake db:migrate. Это приведет к тому, что база данных на машине слияния будет соответствовать номиналу со всеми изменениями. Он также регенерирует schema.rb.
Зафиксируйте и разместите изменения во всех репозиториях (удаленных и отдельных, которые также являются удаленными). Вы должны быть сделаны!
в последнее время я получаю много проблем git из-за конфликтов миграции и задавался вопросом, должен ли я отмечать файлы миграции как игнорировать.
Если да, то как я могу добавить все миграции, которые у меня есть в моих приложениях, и добавить их в ?
файлы миграции для каждого приложения живут в каталоге "миграции" внутри этого приложения и предназначены для фиксации и распространения как часть его кодовой базы. Вы должны сделать их один раз на своей машине разработки, а затем запустить те же миграции на машинах ваших коллег, ваших промежуточных машинах и, в конечном итоге, на ваших производственных машинах.
Если вы будете следовать в этом процессе вы не должны получать конфликтов слияния в файлах миграции.
чтобы уменьшить любые проблемы, которые у вас есть в настоящее время, вы должны указать, какой репозиторий или филиал имеет авторитетную версию файлов миграции, а затем использовать механизм атрибутов git чтобы указать стратегию слияния "ours" для этих файлов. Это скажет git всегда игнорировать внешние изменения в этих файлах и предпочитать локальную версию.
Я был над этим много раз, и я не могу, для жизни меня, найти случай, когда нам нужны миграции в репо.
как я вижу, окончательная Запись Схемы models.py . Если я объединю изменение, а кто-то другой потянет его, все будет правильно, когда они запустятся makemigrations и migrate . Нет необходимости определять, какова стратегия" нашей " миграции.
если нам нужно откатиться назад, то мы возвращаемся models и перенести. Все хорошо, нет проблемы, никогда.
нет жалоб на то, что поле уже существует и т. д.
интересно, может ли кто-нибудь дать мне конкретный случай, когда мне нужно объединить файлы миграции другого разработчика, прежде чем я смогу приступить к работе. Я знаю, что доктора говорят, что я должен, поэтому я предполагаю, что это так. Но я никогда не встречал ни одного.
вы можете следовать приведенному ниже процессу.
вы можете запустить makemigrations локально и это создает файл миграции. Зафиксируйте этот новый файл миграции в repo.
по-моему, вы не должны бежать makemigrations в производстве. Вы можете запустить migrate в производстве, и вы увидите, что миграции применяются из файла миграции, который вы зафиксировали из локального. Таким образом, вы можете избежать всех конфликтов.
В МЕСТНОМ ENV, чтобы создать миграции файлы
теперь совершать эти вновь созданные файлы, что-то вроде ниже.
В ПРОИЗВОДСТВЕ ENV, выполните только следующую команду.
цитата из документов 2018, Django 2.0. (две отдельные команды = makemigrations и migrate )
обычно используемое решение заключается в том, что, прежде чем что-либо будет объединено в master, разработчик должен вытащить любые удаленные изменения. Если есть конфликт в версиях миграции, он должен переименовать его местные миграция (удаленная была запущена другими разработчиками и, возможно, в производстве), в N+1.
во время разработки может быть нормально просто не фиксировать миграции (не добавляйте игнорирование, хотя, просто не add них). Но как только вы войдете в производство, вы они нужны для того, чтобы держать схему в синхронизации с изменениями модели.
затем вам нужно отредактировать файл и изменить dependencies до последней удаленной версии.
это работает для миграции Django, а также других подобных приложений (sqlalchemy+alembic, RoR и т. д.).
Я не могу представить почему у вас будут конфликты, если вы не редактируете миграции каким-то образом? Это обычно заканчивается плохо - если кто-то пропустит некоторые промежуточные коммиты, они не будут обновляться с правильной версии, и их копия базы данных будет повреждена.
процесс, за которым я следую, довольно прост-всякий раз, когда вы меняете модели для приложения, вы также совершаете миграцию, а затем , что миграция не меняет - Если вы нужно что-то другое в модели, затем вы меняете модель и совершаете новую миграцию вместе с вашими изменениями.
в проектах greenfield вы можете часто удалять миграции и начинать с нуля с миграции 0001_ при выпуске, но если у вас есть производственный код, то вы не можете (хотя вы можете раздавить миграции в один).
чувствует, что вам нужно будет настроить свой git workflow, вместо того, чтобы игнорировать конфликты.
в идеале, каждая новая функция разрабатывается в другой ветке, и слился обратно с pull-запрос.
PR не может быть объединен, если есть конфликт, поэтому кому нужно объединить свою функцию, необходимо разрешить конфликт, включая миграции.
короткий ответ: Я предлагаю исключить миграции в репо. После слияния кода, просто запустите ./manage.py makemigrations и все готово.
ответ Я не думаю, что вы должны помещать файлы миграции в репо. Это испортит состояния миграции в среде dev другого человека и другой среде prod и stage. (см. комментарий Sugar Tang для примеров).
С моей точки зрения, цель миграции Django-найти пробелы между предыдущие состояния модели и новые состояния модели, а затем сериализовать разрыв. Если ваша модель изменяется после слияния кода, Вы можете просто сделать makemigrations чтобы узнать разрыв. Почему вы хотите вручную и тщательно объединить другие миграции, когда вы можете достичь того же автоматически и без ошибок? документация Django говорит,
Они*(миграции) * разработаны в основном автоматически
; пожалуйста, держите его таким образом. Чтобы объединить миграции вручную, необходимо должны в полной мере понимать, что изменили другие и какая зависимость от изменений. Это много накладных расходов и ошибок. Таким образом, файл отслеживания моделей достаточно.
это хорошая тема для рабочего процесса. Я открыт для других вариантов.
имея кучу файлов миграции в git грязно. В папке миграции есть только один файл, который не следует игнорировать. Этот файлinit.py-файл, если вы проигнорируете его, python больше не будет искать подмодули внутри каталога, поэтому любые попытки импорта модулей потерпят неудачу. Поэтому вопрос должен состоять в том, как игнорировать все файлы миграции, но init.пай? Решение: Добавить '0*.пы' для .файлы gitignore, и он отлично выполняет свою работу.
Поделитесь опытом, нужно ли вносить файлы миграции под систему контроля версий? Их же можно самостоятельно генерировать, и вроде как смысла нет.
Нужно. Зачем на каждой площадке их дублировать, если можно использовать готоые.
Я разработкой занимаюсь дома и в офисе. дома создал миграцию, сделал коммит tmp_название_задачи, запушил, в офисе миграцию накатил и дальше работаю.
Там все на много сложнее. У всех должны выполняться одинаковые миграции. Иначе можно конретно отгребти проблем.
Ну лично я принял волевое решение и вынес миграции из под гита, ибо действительно, если один работаешь над проектом, то еще куда ни шло, но нужно делать все то же, что на локалке, еще и на тестовом и боевом сервере, что уже увеличивает мне количество телодвижений. Кроме того миграции еще и в БД хранятся.Не каждое изменение идет на сервер, может передумаешь и ищменишь структуру еще раз ну и так далее.А если вдруг садишься за чужой проект и как начнешь фейкать и делать --delete-ghost-migrations после того, как склонируешь реп. Мне проще без миграций сделать syncdb (олд стайл, уже deprecated), и вести на каждом сервере свою историю миграций
Тут можно и даже желательно начать холивар ибо истина рождается в спорах
не знаю насчёт холиваров. Но вот мы работаем сейчас над одним проектом втроём. Кто-то один делает изменения в БД. Как сделать так, чтобы у всех остальных проект продолжил работать? Вручную добавлять поля или как? А ещё есть демо-сервер и боевой. На обоих есть уже множество данных, которые должны в БД оставаться. А боевой ещё и работать должен без перерывов. Так вот деплоится новая версия, а там структура БД другая, и как быть? Используем миграции, во всех случаях после изменения кода (хоть git pull у разработчика, хоть деплой), можно запустить миграцию, и БД автоматом примет нужную структуру. Как то же самое делать без миграций и без гемора — ума не приложу.
Ну лично я принял волевое решение и вынес миграции из под гита, ибо действительно, если один работаешь над проектом, то еще куда ни шло, но нужно делать все то же, что на локалке, еще и на тестовом и боевом сервере, что уже увеличивает мне количество телодвижений. Кроме того миграции еще и в БД хранятся.Не каждое изменение идет на сервер, может передумаешь и ищменишь структуру еще раз ну и так далее.
Это у вас процесс через ж. построен и вы пытаетесь его пофиксить аналогично. Если изменения не идут на сервера, что они делают в репо? Для таких изменений делаются отдельные ветки. В конце мержите окончательную миграцию. Хранения в БД истории миграций позволяет понять правильно ли прошли миграции. А так будет у вас история миграций из БД и как без кода миграции понять что вообще произошло и кто накосячил? А как же миграции данных? Как их генерировать?
Это у вас процесс через ж. построен и вы пытаетесь его пофиксить аналогично. Если изменения не идут на сервера, что они делают в репо? Для таких изменений делаются отдельные ветки. В конце мержите окончательную миграцию. Хранения в БД истории миграций позволяет понять правильно ли прошли миграции. А так будет у вас история миграций из БД и как без кода миграции понять что вообще произошло и кто накосячил? А как же миграции данных? Как их генерировать?
Дмитрий всё правильно говорит. Боевые миграции обязательно должны быть в репозитории. Промежуточные миграции, которыми вы тестируете некую функциональность надо хранить в своих отдельных ветках и при необходимости сливать в master .
Правда иногда бывают такие ситуации, что приходится впиливать большой функционал (это занимает достаточно длительное время) или одновременно работать над разными версиями БД. Для таких непростых проектов я создавал разные наборы конфигураций, нужная определялась текущей веткой репозитория. Таким образом, я спокойно переключался между ветками (например, между актуальной разработкой и веткой фичи), мог оперативно осуществлять поддержку боевого кода и разрабатывать новый функционал. А Django сама знала в какую базу данных надо сейчас смотреть.
Вообще, я всегда обеспечивал наличие на своей машине копии боевой БД, копии тестовой БД и пачку БД для веток. И перед вливанием кода очередной фичи в master и перед push ем его в главный репозиторий, я всегда прогонял тесты последовательно, на ветке фичи, затем на ветке тестовой машины, затем выкладывал код на тестовый сервер, где его протыкивал заказчик, после одобрения функционала, происходило тестирование на локальной мастер ветке с её БД и затем выкладывание на боевую машину. Этот может звучать сложно, но именно такой подход обеспечивал 146% гарантию того, что при обновлении сайт не грохнется и процессы у клиента не встанут.
Следует ли мне добавлять в файл файлы миграции Django .gitignore ?
Недавно я получал много проблем с git из-за конфликтов миграции, и мне было интересно, следует ли отмечать файлы миграции как игнорируемые.
Если да, как мне добавить все миграции, которые есть в моих приложениях, и добавить их в .gitignore файл?
The migration files for each app live in a “migrations” directory inside of that app, and are designed to be committed to, and distributed as part of, its codebase. You should be making them once on your development machine and then running the same migrations on your colleagues’ machines, your staging machines, and eventually your production machines.
Если вы последуете этому процессу, у вас не должно возникнуть конфликтов слияния в файлах миграции.
При объединении ветвей управления версиями вы все равно можете столкнуться с ситуацией, когда у вас есть несколько миграций, основанных на одной и той же родительской миграции, например, если разные разработчики представили миграцию одновременно. Один из способов разрешить эту ситуацию - ввести _merge_migration_. Часто это можно сделать автоматически с помощью команды
который представит новую миграцию, которая зависит от всех текущих миграций головы. Конечно, это работает только тогда, когда нет конфликта между головными миграциями, и в этом случае вам придется решать проблему вручную.
Учитывая, что некоторые люди здесь предложили вам не передавать свои миграции в систему управления версиями, я хотел бы подробнее остановиться на причинах, по которым вам действительно следует это делать.
Во-первых, вам нужна запись о миграциях, примененных к вашим производственным системам. Если вы развертываете изменения в производственной среде и хотите перенести базу данных, вам потребуется описание текущего состояния. Вы можете создать отдельную резервную копию миграций, применяемых к каждой производственной базе данных, но это кажется излишне громоздким.
Во-вторых, миграции часто содержат собственный рукописный код. Не всегда возможно автоматически сгенерировать их с помощью ./manage.py makemigrations .
В-третьих, миграции должны быть включены в обзор кода. Это значительные изменения в вашей производственной системе, и есть много вещей, которые могут пойти не так.
Короче говоря, если вы заботитесь о своих производственных данных, проверьте свои миграции в системе контроля версий.
Should I be adding the Django migration files in the .gitignore file?
I've recently been getting a lot of git issues due to migration conflicts and was wondering if I should be marking migration files as ignore.
If so, how would I go about adding all of the migrations that I have in my apps, and adding them to the .gitignore file?
Обновление от 16 октября 2017 г.
Я вернулся к этому через некоторое время и внес некоторые улучшения:
- Я добавил еще одну задачу rake для пространства имен, чтобы создать ветку и клонировать базу данных одним махом с расширением bundle exec rake git:branch .
- Теперь я понимаю, что клонирование из master — это не всегда то, что вы хотите сделать, поэтому я сделал более явным, что db:clone_from_branch задача принимает переменную окружения SOURCE_BRANCH и . TARGET_BRANCH При git:branch его использовании будет автоматически использоваться текущая ветка в качестве файла SOURCE_BRANCH .
- Рефакторинг и упрощение.
Читайте также: