What is the preferred way to manage schema.rb in git?

Ruby on-RailsGitWorkflowschema.rb

Ruby on-Rails Problem Overview


I don't want to add schema.rb to .gitignore, because I want to be able to load a new database schema from that file. However, keeping it checked in is causing all sorts of spurious conflicts that are easily resolved by a fresh db:migrate:reset.

Basically I want a way to:

  1. Keep schema.rb in the repository for deploy-time database setup
  2. Keep schema.rb in '.gitignore' for general development

There would be one or two people responsible for updating schema.rb and knowing that it was correct.

Is there a way I can have my cake and eat it, too?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

I'm afraid the magic solution you're looking for does not exist. This file is normally managed in version control, then for any conflicts on the version line just choose the later of the two dates. As long as you're also running all of the associated migrations nothing should get out of sync this way. If two developers have caused modifications to a similar area of schema.rb and you get conflicts in addition to the version then you are faced with a normal merge conflict resolution, but in my opinion these are normally easy to understand and resolve. I hope this helps some!

Solution 2 - Ruby on-Rails

One other thing you can do is use:

git update-index --assume-unchanged /path/schema.rb

This will keep the file in the repository but won't track changes. you can switch the tracking anytime by using:

git update-index --no-assume-unchanged /path/schema.rb

Solution 3 - Ruby on-Rails

What has worked really well for me is to delete and .gitignore schema.rb and then have it regenerated for each developer when they rake db:migrate.

You can still achieve what you wanted without migrating from 0 and risking broken migrations from years ago by simply doing a "roll-up" of the migrations periodically. You can do this by:

  1. Run all outstanding migrations with rake db:migrate
  2. Taking the contents of your schema.rb in the ActiveRecord::Schema.define block
  3. Paste it into your initial_schema migration inside def up (overwriting what's already there)
  4. Delete all other migrations

Now your initial_schema migration is your starting point for new systems and you don't have to worry about conflicts in schema.rb that may not be resolved correctly. It's not magical, but it works.

Solution 4 - Ruby on-Rails

Would it be sufficient to do a rake db:dump in a pre-commit git hook?

The following won't necessarily fix (1) or (2), but it might take care of the merging issue, and then maybe (1) and (2) go away.

Solution 5 - Ruby on-Rails

Instead of using .gitignore, use separate branches: Develop which omits schema.rb and Test and Deploy which include schema.rb. Only make code changes in the Develop branches and never merge from Test into Develop. Keep schema.rb in a separate branch:

Developer A             
    Develop      --------             
    Local Schema          \           Your Repo
    Test                    --------->    Dev A
                            --------->    Dev B
Developer B               /               Master
    Develop      --------                 Schema
    Local Schema                          Test
    Test                                  Deploy

In Git, branches are pointers to collections of file contents, so they can include or exclude particular files as well as track file versions. This makes them flexible tools for building your particular workflow.

Solution 6 - Ruby on-Rails

You could define a merge strategy. I've found this solution, but dont remember the source

[merge "railsschema"]
name = newer Rails schema version
driver = "ruby -e '\n\
	system %(git), %(merge-file), %(--marker-size=%L), %(%A), %(%O), %(%B)\n\
	b = File.read(%(%A))\n\
	b.sub!(/^<+ .*\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n=+\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n>+ .*/) do\n\
	  %(ActiveRecord::Schema.define(:version => #{[$1, $2].max}) do)\n\
	end\n\
	File.open(%(%A), %(w)) {|f| f.write(b)}\n\
	exit 1 if b.include?(%(<)*%L)'"

put this "somewhere" and

git-config --global core.attributesfile "somewhere"

Solution 7 - Ruby on-Rails

I built a gem to solve this problem.

It sorts columns, index names and foreign keys, removes excess whitespace and runs Rubocop for some formatting to unify the output of your schema.rb file.

https://github.com/jakeonrails/fix-db-schema-conflicts

After you add it to your Gemfile you just run rake db:migrate or rake db:schema:dump like normal.

Solution 8 - Ruby on-Rails

  1. Commit schema.rb file.
  2. Run git pull (or continue with what you're doing)

Every time you migrate the database, the schema.rb file updates and appears in git status. When working on something and occasionally doing git pull, this can be annoying because you have to commit schema.rb file before pulling to resolve conflict. This means that every time you migrate the database, you need to commit schema.rb file.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOttoView Question on Stackoverflow
Solution 1 - Ruby on-RailsAdam AlexanderView Answer on Stackoverflow
Solution 2 - Ruby on-RailsHeadshotaView Answer on Stackoverflow
Solution 3 - Ruby on-RailsTom HarrisView Answer on Stackoverflow
Solution 4 - Ruby on-Railsdbrown0708View Answer on Stackoverflow
Solution 5 - Ruby on-RailsPaulView Answer on Stackoverflow
Solution 6 - Ruby on-RailsandreaView Answer on Stackoverflow
Solution 7 - Ruby on-RailsjakeonrailsView Answer on Stackoverflow
Solution 8 - Ruby on-RailsChemistView Answer on Stackoverflow