# What should we do when a migration already applied in production was edited in Git?

> Reconstruct the deployed migration and live schema, then restore the original file, add a corrective migration, or repair metadata only when database state already matches.

Canonical URL: https://www.devobs.io/articles/qa-migration-history-checksum-drift/
By: Samira Haddad
Published: 2023-02-28T19:37:15.093Z
Updated: 2026-09-06T10:18:15.722Z
Section: Architecture

Do not edit history forward and hope the tool will smooth it over. When a migration already ran in production and its file changed in Git, first reconstruct what each environment actually executed, then choose the smallest truthful fix: restore the original file if production is correct, add a new corrective migration if database state must change, and use checksum-repair mechanisms only when you are intentionally updating metadata to match reality rather than changing the database.

## What is the first thing to verify?

Verify the boundary between **recorded migration history** and **actual database state**. A checksum mismatch means your migration tool sees that the file in Git no longer matches what was recorded when the migration ran. In Flyway, `validate` fails when migration names, types, or checksums differ, and it explicitly says validation stores and compares checksums for executed migrations in schema history ([Flyway validate documentation](https://documentation.red-gate.com/flyway/reference/commands/validate)). In Liquibase, the checksum stored in `DATABASECHANGELOG` is compared against the changeset as currently defined, and Liquibase halts because the database may now differ from what the changelog expects ([Liquibase changeset checksum guide](https://docs.liquibase.com/secure/user-guide-5-1/what-is-a-changeset-checksum)).

That means your first task is not `repair` or `clear-checksums`. It is evidence collection:

- dump the current migration metadata table from each environment
- retrieve the exact SQL or changelog revision that was deployed
- inspect the live schema objects affected by that migration
- identify whether non-production environments already re-ran from the edited file

Compare metadata and live schema **before** changing files or checksums so you preserve the trail showing what happened.

## Should we restore the old file or add a new migration?

Prefer restoring the original file and then adding a new migration for any new intent.

Worked example: `V42__add_orders_status.sql` originally added `status text default 'pending'`. Someone edits it in Git to `default 'draft'` after production already applied it.

If production still has `'pending'`, restore `V42` in Git to the original content. Then create `V43__change_orders_status_default.sql` that changes the default to `'draft'`.

Why this is the safe default:

- migration history stays immutable
- new environments replay the same historical steps truthfully
- existing environments converge through a normal forward migration
- your validate step becomes meaningful again

Use the same principle in Liquibase: revert the modified changeset definition if it represented deployed history, then add a new changeset for the changed default. Do not use `validCheckSum` to disguise a semantic schema change that some databases have and others do not.

## When is metadata repair acceptable?

Repair metadata only when the **database state is already the intended state** and you are correcting history bookkeeping, not applying a hidden schema change.

For Flyway, the documented response to `CHECKSUM_MISMATCH` is either revert the migration changes or run repair to update schema history ([Flyway validate error codes](https://documentation.red-gate.com/flyway/reference/exit-codes-and-error-codes/validate-error-codes)). That is appropriate for benign edits such as comments, file encoding normalization, or a description correction after you have confirmed the executed SQL effect is unchanged.

For Liquibase, the docs describe three ways to ignore a changed changeset: nulling the checksum in `DATABASECHANGELOG`, adding `validCheckSum`, or `clear-checksums`, which clears the whole checksum column and recalculates it on the next run ([Liquibase changeset checksum guide](https://docs.liquibase.com/secure/user-guide-5-1/what-is-a-changeset-checksum)). All three are metadata actions. None of them retroactively apply edited SQL to production.

A short checklist:

- If state differs and needs to change: add a new migration.
- If state matches and only the file drifted: restore or repair metadata deliberately.
- If you cannot prove what ran: stop, recover the original artifact from CI/CD logs, release bundles, or backups before touching metadata.

## Follow-up Q&A?

**Can repair hide a real problem?**

Yes. If the edited file changes semantics, repair can make the history table look clean while environments still differ.

**What artifact proves the original migration?**

Prefer the deployment artifact used at release time: CI build output, migration bundle, container image, or VCS commit pinned in the production release.

Next step: run validation, export migration metadata from every environment, and decide from that evidence whether you need a file restore, a forward corrective migration, or a narrowly justified metadata repair.

Reviewed: 2026-09-05

## Source references

- <https://documentation.red-gate.com/flyway/reference/commands/validate>
- <https://documentation.red-gate.com/flyway/reference/exit-codes-and-error-codes/validate-error-codes>
- <https://docs.liquibase.com/secure/user-guide-5-1/what-is-a-changeset-checksum>
