+1

Cách khôi phục database schema nếu gặp conflicts khi rebase

Đây là vấn đề sẽ thường xuyên xảy ra khi làm các dự án Rails với quy trình làm việc trên branch của git. Giả sử bạn đang làm việc trên một nhánh để phát triển một tính năng nào đó của project. Vấn đề xảy ra khi cả nhánh develop và nhánh của bạn đều chứa file migration, khi đó sẽ xảy ra conflict ở file schema khi bạn rebase, ít nhất là conflict về phiên bản ở đầu file hoặc có thể là conflict ở nhiều chỗ khác nữa. Phiên bản ở đây là một timestamp, tương ứng với timestamp của file cuối cùng được thêm vào trong migration.

Số phiên bản trong file schema cần tương ứng với file migration được tạo ra cuối cùng, là file mà có số timestamp trong tên lớn nhất

Cách giải quyết thông thường

Khi gặp conflict do migration thì sẽ có nhiều người sửa trực tiếp vào file schema.rb. Việc làm này có khả năng sẽ gây ra trường hợp file schema.rb sẽ có số version khác với file schema.rb mà chúng ta tạo ra bằng cách chạy rake db:migrate:reset. Nếu vấn đề trên xảy ra, và tại một thời điểm khác ai đó chạy rake db:migrate, sẽ thu được một file schema.rb không chuẩn, và sau đó sẽ rất khó để giải quyết những vấn đề phát sinh tiếp theo.

Giải quyết như thế nào mới đúng?

Có một cách tiếp cận mạnh mẽ để giải quyết vấn đề trên đó là xây dựng lại schema.rb ở từng giai đoạn như sau:

  1. Trước khi rebase, checkout và pull nhánh develop và phải đảm bảo rằng database đang tương đồng với version schema hiện tại ở nhánh develop. Bạn có thể kiểm tra việc này bằng cách chạy rake db:migrate:status. Trường hợp lý tưởng là mọi thứ bạn nhìn thấy đều là up.
    • Nếu có một vài file là down, thì rất có thể bạn chưa migrate tất cả các file migration có ở trên develop, do vậy hãy chạy lệnh rake db:migrate
    • Nếu bạn thấy có dòng nào đó như sau, có nghĩa là một migration nào đó đã được applied vào database mà lại chưa có trên develop, và có thể đó là migration ở nhánh của bạn đang thực hiện một tính năng và cần rebase. Rails không có cơ chế rollback migration này, vì vậy bạn cần chuyển sang một nhánh bất kỳ nào khác và tự thêm một file migration để rollback lại.
      up     20170210155150  ********** NO FILE ***********
      
  2. Bậy giờ bạn có thể chuyển sang nhánh của mình và rebase với develop
  3. Khi xảy ra conflict, đầu tiên hãy unstage những thay đổi của file schema.rb
     git reset HEAD db/schema.rb
    
  4. Tiếp theo discard những thay đổi của file schema.rb ở trên nhánh của mình
    git checkout db/schema.rb
    
  5. Build lại schema
    rake db:migrate
    
  6. Kiểm tra sự khác biệt git diff của file schema.rb
    • Trong trường hợp những file migration bạn thêm vào sớm hơn trên develop, version của file schema.rb sẽ không thay đổi vì nó tương ứng với file migration mới nhất (có timestamp lớn nhất).
  7. Đó là những gì bạn cần làm nếu gặp vấn đề khi rebase file schema.rb. Bây giờ hãy tiếp tục rebase những file conflict khác.

Background

Những điều bạn cần biết để hiểu rõ ràng hơn những thứ ở trên hoạt động:

  • schema.rb là file được xây dựng từ cơ sở dữ liệu, không phải trực tiếp từ migrations.
  • Khi rake db:migrate được chạy, nó sẽ check bảng schema_migrations trong database (bảng này chứa danh sách timestamp của các migrations đã được chạy trên cơ sở dữ liệu) và so sánh với db/migrations, sau đó nó sẽ chạy những migration nào chưa được chạy và thêm dấu thời gian vào bảng schema_migrations, và rebuild lại schema.
  • rake db:migrate:status chỉ show ra sự khác nhau giữa bảng schema_migrationsdb/migrations chứ không thay đổi gì cả.
  • Các schema nói chung đa phần đều xây dựng theo cùng một cách ngay cả khi một số file migration không đúng theo trật tự, bởi vì các chỉ mục mới được thêm vào theo thứ tự chữ cái chứ không phải theo thứ tự của migration.

Kết luận

Mong rằng bài viết sẽ hữu ích với các bạn. Cảm ơn. References


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.