In Rails, the file db/structure.sql or db/schema.rb (depending) captures a snapshot of the state of the development database after a migration, when you run the db:migrate or db:schema:dump tasks.

What do you do when you have migrations in two different branches of your development tree? Do you get a merge conflict? How do you resolve it? What if you don’t get a merge conflict?

I’ll use the term “schema” now to refer to the file (db/structure.sql or db/schema.rb). It is the file that captures the structure of the database. Because the schema is generated by a program, not hand written, the best effort of git to try to merge two changes to it will often produce a result different than what you will get from running the db:schema:dump.

Why is that important?

  • It might have duplications or content out of sequence.
  • The next migration will produce a schema with differences unrelated to the migration.
  • The schema is the only source of truth about the database structure. It deserves extra care, to keep it aligned with what the framework and tooling expect and produce.

Here’s a process that allows the tooling to keep the schema in order, combining independent migrations without errors induced by merging.

First, do not allow git to merge the file. Set-up git to always treat independent changes to the schema as a conflict. You do this by placing a .gitattributes file in the db directory with content,

schema.rb -merge
structure.sql -merge

(Or add those lines to the existing .gitattributes file if there is one.) The reference for doing that is deep down in the documentation of gitattributes.

Second, when you do get a conflict, resolve it as follows:

If your database migrations come after those you picked-up in the merge:

  • Abort the merge git merge --abort
  • Roll back your migrations, however many, rails db:rollback
  • Pull the changes a second time

In either case,

  • Run the migrations picked-up in the merge, rails db:migrate
  • Accept the newly generated schema, e.g. git add db/structure.sql
  • Make that merge commit, git commit

In this way, your database schema will always be wholly in agreement with the text wanted by the framework, because it is always and only ever generated by the framework.