디비를 모두 날렸어도 처음부터 끝까지 마이그레이션 파일을 실행했을때 날리기 전의 디비의 스키마를 그대로 복구할 수 있어야만 완전한 마이그레이션 파일입니다.
그런 상태일때만 여러분 각자의 로컬 디비가 서로 같은 상태를 유지하며 개발되고 있음을 보장할 수 있기 때문입니다.
그래서 마이그레이션 파일은 디비에 변경점을 가하기 위한 도구라기보단 디비의 변경점을 기록해두는 커밋 로그 처럼 다뤄야 합니다.
가끔 심각하게 꼬인 마이그레이션의 경우 커밋을 롤백하면서 마이그레이션 파일을 지워야할 수도 있습니다. 하지만 프로덕션 db에 이미 반영된 마이그레이션 파일의 경우는 조심히 다뤄야합니다. 프로덕션 db도 같이 롤백해주거나, 아니면 파일을 지우지 마세요.
마이그레이션 파일을 커밋하고 push 해야 한다는 주장에는 여러 근거가 있습니다. 첨부해드리니 참고해주세요.
일단 공식 문서가 그러라고 하고 있어요.
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.
https://docs.djangoproject.com/en/3.2/topics/migrations/
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.
https://stackoverflow.com/a/28035246/11321149
마이그레이션 파일이 충돌이 나는 케이스는 여러가지가 있을 수 있습니다.
A가 먼저 커밋을 했고 B가 나중에 커밋을 한다고 가정했을 때,
아래 케이스를 상상해보세요.
: A가 테이블을 삭제하고 B가 삭제된 테이블에 컬럼을 추가함
이 경우에는 A가 코드에서 모델을 삭제했을 것이고, B는 같은 모델에 컬럼을 추가했을 겁니다.
그러면 당연히 merge conflicts가 나겠죠? 그 conflict을 해결하면서 마이그레이션 파일도 같이 해결해주세요.
선택지는 두가지가 있습니다.
테이블을 삭제하고 컬럼을 추가하지 않음
이 경우는 B의 마이그레이션 파일을 지우면 됩니다. (아직 merge 전이므로)
이미 PR을 올렸다는건 로컬에서는 한번 migrate를 진행했을텐데요, 디비에 마이그레이션 기록이 남아있으면 앞으로 꼬일 가능성이 있습니다
이런식으로 롤백을 한 후에 파일을 지워주시면 됩니다.
./manage.py migrate my_app 0010_add_column
코드 변경사항을 커밋한 후 develop을 merge 해옵니다 (혹은 rebase)
테이블을 삭제하지 않고 컬럼을 추가함
이 경우는 A의 마이그레이션 파일을 지워야 합니다.
하지만 이건 좀 까다롭겠죠? A가 마이그레이션을 롤백해야 하니까 좀 어렵습니다.
그래도 이렇게 해야 한다면 아래와 같이 진행해보세요.
: A가 test라는 컬럼을 추가하고 B도 test라는 컬럼을 추가함
이 문제는 두개의 개별 마이그레이션 파일이 서로 같은 컬럼을 추가하려고 해서 문제가 됩니다.
그리고 같은 컬럼을 추가하려고 하고 있으니까 model에도 conflict이 있을텐데요, 아래와 같이 해결하면 됩니다. 기본적으로는 위의 a 방법과 동일합니다.
위 케이스는 model의 코드가 conflict가 났기 때문에 PR단계에서 미리 충돌을 감지할 수 있었습니다.
하지만 보통 마이그레이션 파일은 파일 이름이 같지 않는 이상 충돌이 날리가 없어서, 서로 반대되는 내용을 가진 migration파일이 merge되고 있음을 감지할 수가 없습니다.
그래서 권장하는 방법은, develop 브랜치를 메인 브랜치로 사용하는 것입니다.
master <- develop <- feature1
<- feature2
이런식으로 gitflow를 짜신다면, master 브랜치로 넘기기 전에 develop 브랜치를 pull 받은 후, 마이그레이션이 문제가 없는지 확인할 수 있습니다.
많은 프로젝트에서 사용하는 방법이니 이 기회에 적용해보시는 것도 추천드려요.
또 다른 방법은 merge 전 CI를 수행하는 것입니다.
python [manage.py](http://manage.py/) makemigrations --check --dry-run
merge 되기 전에 이 명령어를 수행한다면 기본적인 에러와 함께, 모델 변경점은 있지만 마이그레이션 파일이 만들어지지 않은 케이스를 막을 수 있습니다.
$ python manage.py makemigrations -n add_test_column
Migrations for 'sampleapp':
sampleapp/migrations/0001_add_test_column.py
- Create model SampleModel
n 파라미터를 넘기면 파일 이름을 직접 지을 수가 있습니다. 꼭 n 파라미터를 넘겨서 migration 파일을 만들도록 습관을 들여보세요.
한번에 모든 변경사항을 마이그레이션 파일로 만들지 마세요.
커밋을 한꺼번에 하면 롤백이나 서로 리뷰하기 힘들어지듯이, 마이그레이션 파일도 작은 단위로 쪼개서 잘게 잘게 커밋하는걸 추천드립니다.