Why does structure.sql use explicit schema_migrations entries, but schema.rb uses assumed migrated version?

I have recently been touching an app which uses schema.rb instead of structure.sql. I have realised that I have “unlearned” one important aspect of it - when I do feature dev in branches, my standard approach to “reset my database to be off-main” was to git checkout main -- db/structure.sql, then rake db:reset followed by db:migrate. Since structure.sql includes INSERTs for all the schema_migrations table entries, it would unambiguously record which migrations did and did not run - so this workflow is pretty bulletproof. I was surprised to find out that these rows do not get captured in schema.rb - so when I want to rebase a feature branch and rerun the migrations in it, I need to muck about with the migration filename (so that its VERSION changes) or the entries in schema_migrations. Is there some Rails command sequence I am missing to replicate the workflow which I have with structure.sql? Because it’s super-handy honestly, and with schema.rb it becomes a drag. To compare:

  • With structure.sql - to apply migration from my feature branch: git checkout main -- db/structure.sql; rake db:migrate
  • With schema.rb - to apply migration from my feature branch: git stash ... && git checkout main && <some kind of db reset> && git checkout <feature branch> ....

With the implicit “migrated to version” with schema.rb, Rails assumes that if there is a migration file in place with version N and there is a schema.rb and the version in the schema is higher than the version N, the migration has been applied and is recorded in the schema. So if the migration is “backdated” (which can easily happen if a branch gets rebased onto newer main, for instance) it will be silently skipped, yet recorded in schema_migrations.

What is the rationale behind having explicit schema_migrations entries in structure.sql but using the assumed version in schema.rb?

I think using only a migrated version in schema.rb, because it is simpler and nicer than having hundreds of version lines in that file. And using all versions in the structure.sql, because it is easily done with pg_dump etc and easily loadable after. But having only the last migrated version in structure.sql will require much more work for rails and structure dumps are in different formats for each dbms.