Cách làm việc với các nhánh Git và di chuyển Rails


131

Tôi đang làm việc trên một ứng dụng rails với khá nhiều nhánh git và nhiều trong số chúng bao gồm di chuyển db. Chúng tôi cố gắng cẩn thận nhưng đôi khi một số đoạn mã trong master yêu cầu một cột bị xóa / đổi tên trong nhánh khác.

  1. Điều gì sẽ là một giải pháp tốt đẹp để "ghép" các nhánh git với trạng thái DB?

  2. Những "trạng thái" này thực sự sẽ là gì?

    Chúng tôi không thể sao chép cơ sở dữ liệu nếu kích thước vài GB.

  3. Và những gì sẽ xảy ra với sự hợp nhất?

  4. Giải pháp sẽ chuyển sang cơ sở dữ liệu noQuery?

    Chúng tôi hiện đang sử dụng MySQL, mongodb và redis


EDIT: Có vẻ như tôi đã quên đề cập đến một điểm rất quan trọng, tôi chỉ quan tâm đến môi trường phát triển nhưng với cơ sở dữ liệu lớn (kích thước vài GB).


Bạn đang làm gì mà bạn có một môi trường chạy nhánh chính của bạn có cơ sở dữ liệu có thể được sửa đổi bởi các nhánh khác? Tôi không hiểu quy trình làm việc của bạn là gì hoặc tại sao bạn nghĩ rằng bạn cần giữ các chi nhánh đồng bộ hóa với các cơ sở dữ liệu cụ thể.
Giô-na

3
Giả sử chúng ta có một bảng trong cơ sở dữ liệu của mình với các máy khách (tên, email, điện thoại) và trong một nhánh, chúng ta chia một trong các cột (tên -> first_name + last_name). Cho đến khi chúng ta hợp nhất nhánh với chủ, chủ và tất cả các nhánh khác dựa trên nó sẽ thất bại.
Kostas

Câu trả lời:


64

Khi bạn thêm một di chuyển mới trong bất kỳ chi nhánh nào, hãy chạy rake db:migratevà cam kết cả di chuyển db/schema.rb

Nếu bạn làm điều này, trong quá trình phát triển, bạn sẽ có thể chuyển sang một chi nhánh khác có một bộ di chuyển khác và chỉ cần chạy rake db:schema:load.

Lưu ý rằng điều này sẽ tạo lại toàn bộ cơ sở dữ liệu và dữ liệu hiện tại sẽ bị mất .

Bạn có thể chỉ muốn chạy sản xuất từ ​​một chi nhánh mà bạn rất cẩn thận, vì vậy các bước này không áp dụng ở đó (chỉ chạy rake db:migratenhư bình thường ở đó). Nhưng trong quá trình phát triển, sẽ không có vấn đề gì lớn để tạo lại cơ sở dữ liệu từ lược đồ, đó là những gì rake db:schema:loadsẽ làm.


5
Tôi nghĩ rằng điều này sẽ chỉ giải quyết vấn đề lược đồ, dữ liệu sẽ bị mất với mỗi lần di chuyển xuống không bao giờ được nhìn thấy nữa. Sẽ là một ý tưởng tốt để lưu một số loại bản vá dữ liệu db được lưu khi di chuyển ra khỏi một nhánh và một loại khác được tải khi di chuyển vào một nhánh khác? Các bản vá chỉ nên chứa dữ liệu sẽ bị mất trên đường xuống (di chuyển).
Kostas

4
Nếu bạn muốn tải dữ liệu, hãy sử dụng db/seeds.rb Nó không quá tàn phá để làm hỏng DB phát triển của bạn nếu bạn thiết lập một số dữ liệu hạt giống hợp lý ở đó.
Andy Lindeman

không cần nuke gì cả. xem giải pháp của tôi dưới đây. Chỉ cần lưu ý rằng bạn sẽ có nhiều trường hợp và khi bạn chuyển nhánh, dữ liệu không có ở đó. Điều này là hoàn toàn tốt nếu bạn đang phát triển với các bài kiểm tra.
Adam Dymitruk

Cảm ơn Andy, câu trả lời này cũng là câu hỏi của tôi. Và đồng ý sử dụng db/seeds.rbđể trích xuất dữ liệu db bị mất
pastullo

Đối với các ứng dụng phức tạp lớn, nơi bạn cần tái tạo các lỗi thực tế cục bộ, hoàn toàn không thể sử dụng tệp hạt giống, bạn cần dữ liệu thực từ sản xuất (hoặc dàn dựng). Và việc khôi phục cơ sở dữ liệu có thể mất nhiều thời gian, vì vậy đây không phải là giải pháp tốt cho trường hợp của tôi.
Joel_Blum

21

Nếu bạn có một cơ sở dữ liệu lớn mà bạn không thể sao chép, thì tôi khuyên bạn nên sử dụng các công cụ di chuyển bình thường. Nếu bạn muốn một quy trình đơn giản, đây là những gì tôi khuyên bạn nên:

  • Trước khi chuyển nhánh, rollback ( rake db:rollback) về trạng thái trước điểm nhánh. Sau đó, sau khi chuyển nhánh, chạy db:migrate. Điều này đúng về mặt toán học, và miễn là bạn viết downkịch bản, nó sẽ hoạt động.
  • Nếu bạn quên làm điều này trước khi chuyển đổi chi nhánh, nói chung bạn có thể chuyển đổi lại, khôi phục và chuyển đổi một cách an toàn, vì vậy tôi nghĩ như một quy trình công việc, điều đó là khả thi.
  • Nếu bạn có sự phụ thuộc giữa các lần di chuyển trong các ngành khác nhau ... tốt, bạn sẽ phải suy nghĩ kỹ.

2
Bạn phải nhớ rằng không phải tất cả các lần di chuyển đều có thể đảo ngược, điều đó nói rằng, bước đề xuất đầu tiên không được đảm bảo để thành công. Tôi nghĩ rằng ở môi trường phát triển, một ý tưởng tốt sẽ được sử dụng rake db:schema:loadrake db:seednhư @noodl đã nói.
pisaruk

@pisaruk Tôi biết bạn đã trả lời điều này sáu năm trước, nhưng đọc tôi tò mò không biết ví dụ về di cư không thể đảo ngược sẽ là gì. Tôi đang có một thời gian khó khăn để tưởng tượng một tình huống. Tôi đoán đơn giản nhất sẽ là một cột bị rớt chứa một loạt dữ liệu, nhưng điều này có thể được "đảo ngược" để có một cột trống hoặc một cột có một giá trị mặc định. Bạn có nghĩ về các trường hợp khác?
Luke Griffiths

1
Tôi nghĩ bạn đã trả lời câu hỏi của bạn! Vâng, một cột bị rơi là một ví dụ tốt. Hoặc di chuyển dữ liệu phá hoại.
ndp

13

Đây là tập lệnh tôi đã viết để chuyển đổi giữa các nhánh có chứa các lần di chuyển khác nhau:

https://gist.github.com/4076864

Nó sẽ không giải quyết tất cả các vấn đề bạn đã đề cập, nhưng được đặt tên chi nhánh sẽ:

  1. Quay trở lại bất kỳ di chuyển nào trên nhánh hiện tại của bạn không tồn tại trên nhánh đã cho
  2. Hủy bỏ mọi thay đổi đối với tệp db / lược đồ.rb
  3. Kiểm tra các chi nhánh nhất định
  4. Chạy mọi di chuyển mới hiện có trong nhánh đã cho
  5. Cập nhật cơ sở dữ liệu kiểm tra của bạn

Tôi thấy mình làm điều này một cách thủ công mọi lúc trong dự án của chúng tôi, vì vậy tôi nghĩ thật tuyệt khi tự động hóa quy trình.


1
Kịch bản này thực hiện chính xác những gì tôi muốn làm, tôi rất muốn thấy nó được đưa vào một móc kiểm tra tự động.
brysgo

1
Điều này chỉ trong, tôi đã chia rẽ ý chính của bạn và biến nó thành một cái móc sau thanh toán: gist.github.com/brysgo/9980444
brysgo

Trong kịch bản của bạn, bạn thực sự có ý muốn nói git checkout db/schema.rbhay bạn có ý git checkout -- db/schema.rbgì? (tức là có dấu gạch ngang kép)
user664833

1
Vâng vâng ... Tôi không biết về dấu gạch ngang đôi vào thời điểm đó. Nhưng lệnh sẽ hoạt động như nhau trừ khi bạn có một nhánh được gọi db/schema.rb. :)
Jon Lemmon

Lệnh git_rails đã phát triển của @ brysgo ( github.com/brysgo/git-rails ) hoạt động rất tốt. Cảm ơn bạn Jon :)
Zia Ul Rehman Mughal

7

Cơ sở dữ liệu riêng cho từng chi nhánh

Đó là cách duy nhất để bay.

Cập nhật ngày 16 tháng 10 năm 2017

Tôi đã trở lại điều này sau một thời gian và thực hiện một số cải tiến:

  • Tôi đã thêm một tác vụ cào không gian tên khác để tạo một nhánh và sao chép cơ sở dữ liệu trong một cú trượt, với bundle exec rake git:branch.
  • Bây giờ tôi nhận ra rằng nhân bản từ chủ không phải luôn luôn là những gì bạn muốn làm vì vậy tôi đã nói rõ hơn rằng db:clone_from_branchnhiệm vụ cần một biến SOURCE_BRANCHTARGET_BRANCHmôi trường. Khi sử dụng git:branchnó sẽ tự động sử dụng nhánh hiện tại là SOURCE_BRANCH.
  • Tái cấu trúc và đơn giản hóa.

config/database.yml

Và để giúp bạn dễ dàng hơn, đây là cách bạn cập nhật database.ymltệp của mình để xác định động tên cơ sở dữ liệu dựa trên nhánh hiện tại.

<% 
database_prefix = 'your_app_name'
environments    = %W( development test ) 
current_branch  = `git status | head -1`.to_s.gsub('On branch ','').chomp
%>

defaults: &defaults
  pool: 5
  adapter: mysql2
  encoding: utf8
  reconnect: false
  username: root
  password:
  host: localhost

<% environments.each do |environment| %>  

<%= environment %>:
  <<: *defaults
  database: <%= [ database_prefix, current_branch, environment ].join('_') %>
<% end %>

lib/tasks/db.rake

Đây là một nhiệm vụ Rake để dễ dàng sao chép cơ sở dữ liệu của bạn từ chi nhánh này sang chi nhánh khác. Điều này có một SOURCE_BRANCHvà một TARGET_BRANCHbiến môi trường. Dựa trên nhiệm vụ của @spalladino .

namespace :db do

  desc "Clones database from another branch as specified by `SOURCE_BRANCH` and `TARGET_BRANCH` env params."
  task :clone_from_branch do

    abort "You need to provide a SOURCE_BRANCH to clone from as an environment variable." if ENV['SOURCE_BRANCH'].blank?
    abort "You need to provide a TARGET_BRANCH to clone to as an environment variable."   if ENV['TARGET_BRANCH'].blank?

    database_configuration = Rails.configuration.database_configuration[Rails.env]
    current_database_name = database_configuration["database"]

    source_db = current_database_name.sub(CURRENT_BRANCH, ENV['SOURCE_BRANCH'])
    target_db = current_database_name.sub(CURRENT_BRANCH, ENV['TARGET_BRANCH'])

    mysql_opts =  "-u #{database_configuration['username']} "
    mysql_opts << "--password=\"#{database_configuration['password']}\" " if database_configuration['password'].presence

    `mysqlshow #{mysql_opts} | grep "#{source_db}"`
    raise "Source database #{source_db} not found" if $?.to_i != 0

    `mysqlshow #{mysql_opts} | grep "#{target_db}"`
    raise "Target database #{target_db} already exists" if $?.to_i == 0

    puts "Creating empty database #{target_db}"
    `mysql #{mysql_opts} -e "CREATE DATABASE #{target_db}"`

    puts "Copying #{source_db} into #{target_db}"
    `mysqldump #{mysql_opts} #{source_db} | mysql #{mysql_opts} #{target_db}`

  end

end

lib/tasks/git.rake

Tác vụ này sẽ tạo một nhánh git khỏi nhánh hiện tại (chính hoặc nếu không), kiểm tra nó và sao chép cơ sở dữ liệu của nhánh hiện tại vào cơ sở dữ liệu của nhánh mới. Đó là AF trơn tru.

namespace :git do

  desc "Create a branch off the current branch and clone the current branch's database."
  task :branch do 
    print 'New Branch Name: '
    new_branch_name = STDIN.gets.strip 

    CURRENT_BRANCH = `git status | head -1`.to_s.gsub('On branch ','').chomp

    say "Creating new branch and checking it out..."
    sh "git co -b #{new_branch_name}"

    say "Cloning database from #{CURRENT_BRANCH}..."

    ENV['SOURCE_BRANCH'] = CURRENT_BRANCH # Set source to be the current branch for clone_from_branch task.
    ENV['TARGET_BRANCH'] = new_branch_name
    Rake::Task['db:clone_from_branch'].invoke

    say "All done!"
  end

end

Bây giờ, tất cả những gì bạn cần làm là chạy bundle exec git:branch, nhập tên nhánh mới và bắt đầu tiêu diệt zombie.


4

Có lẽ bạn nên coi đây là một gợi ý rằng cơ sở dữ liệu phát triển của bạn quá lớn? Nếu bạn có thể sử dụng db / seed.rb và một tập dữ liệu nhỏ hơn để phát triển thì vấn đề của bạn có thể được giải quyết dễ dàng bằng cách sử dụng lược đồ.rb và seed.rb từ nhánh hiện tại.

Điều đó giả định rằng câu hỏi của bạn liên quan đến sự phát triển; Tôi không thể tưởng tượng được tại sao bạn cần thường xuyên chuyển đổi chi nhánh trong sản xuất.


Tôi không biết db/seeds.rb, tôi sẽ xem xét nó.
Kostas

3

Tôi đã đấu tranh với cùng một vấn đề. Đây là giải pháp của tôi:

  1. Đảm bảo rằng cả giản đồ.rb và tất cả các lần di chuyển đều được kiểm tra bởi tất cả các nhà phát triển.

  2. Cần có một người / máy để triển khai sản xuất. Hãy gọi máy này là máy hợp nhất. Khi các thay đổi được kéo đến máy hợp nhất, tự động hợp nhất cho lược đồ.rb sẽ thất bại. Không vấn đề. Chỉ cần thay thế nội dung bằng bất cứ nội dung nào trước đó cho lược đồ.rb (bạn có thể đặt một bản sao sang một bên hoặc lấy nó từ github nếu bạn sử dụng nó ...).

  3. Đây là bước quan trọng. Việc di chuyển từ tất cả các nhà phát triển sẽ có sẵn trong thư mục db / di chuyển. Hãy tiếp tục và chạy gói exec rake db: di chuyển. Nó sẽ mang cơ sở dữ liệu trên máy hợp nhất ngang bằng với tất cả các thay đổi. Nó cũng sẽ tạo lại lược đồ.rb.

  4. Cam kết và đẩy các thay đổi ra tất cả các kho lưu trữ (điều khiển từ xa và cá nhân, cũng là điều khiển từ xa). Bạn nên làm xong!


3

Đây là những gì tôi đã làm và tôi không chắc chắn rằng tôi đã bao gồm tất cả các cơ sở:

Trong phát triển (sử dụng postgresql):

  • sql_dump db_name> tmp / Branch1.sql
  • chi nhánh kiểm tra git2
  • dropdb db_name
  • createdb db_name
  • psql db_name <tmp / Branch2.sql # (từ chuyển đổi nhánh trước)

Điều này nhanh hơn rất nhiều so với các tiện ích cào trên cơ sở dữ liệu với khoảng 50 nghìn bản ghi.

Đối với sản xuất, duy trì nhánh chính là bất khả xâm phạm và tất cả các lần di chuyển được kiểm tra, shema.rb được hợp nhất đúng cách. Đi qua thủ tục nâng cấp tiêu chuẩn của bạn.


Đối với kích thước cơ sở dữ liệu đủ nhỏ và thực hiện điều này trong nền khi kiểm tra một nhánh trông giống như một giải pháp rất hay.
Kostas

2

Bạn muốn duy trì một "môi trường db" trên mỗi nhánh. Nhìn vào smudge / script script để chỉ ra các trường hợp khác nhau. Nếu bạn hết các phiên bản db, hãy để tập lệnh thoát khỏi một cá thể tạm thời để khi bạn chuyển sang một nhánh mới, nó đã ở đó và chỉ cần được đổi tên bởi tập lệnh. Các bản cập nhật DB sẽ chạy ngay trước khi bạn thực hiện các bài kiểm tra của mình.

Hi vọng điêu nay co ich.


Giải pháp này chỉ tốt cho các chi nhánh "tạm thời". Ví dụ: nếu chúng ta có một "cạnh" nhánh, chúng ta đã kiểm tra tất cả các loại công cụ điên rồ (có thể với các nhánh phụ khác) và sau đó hợp nhất nó với chủ, đôi khi cơ sở dữ liệu sẽ tách rời nhau (dữ liệu của chúng sẽ không giống nhau).
Kostas

Giải pháp này là tốt cho chính xác ngược lại. Đây là một giải pháp rất tốt nếu bạn phiên bản tập lệnh phiên bản cơ sở dữ liệu của bạn.
Adam Dymitruk

2

Tôi hoàn toàn trải nghiệm pita bạn đang có ở đây. Theo tôi nghĩ, vấn đề thực sự là tất cả các chi nhánh không có mã để khôi phục một số chi nhánh nhất định. Tôi đang ở trong thế giới django, vì vậy tôi không biết rõ về cái cào đó. Tôi đang đùa với ý tưởng rằng các cuộc di cư sống trong repo của chính họ mà không bị phân nhánh (git-subodule, mà tôi mới biết về nó). Bằng cách đó, tất cả các chi nhánh có tất cả các di cư. Phần dính là đảm bảo mỗi nhánh được giới hạn chỉ di chuyển mà họ quan tâm. Làm / theo dõi điều đó bằng tay sẽ là một pita và dễ bị lỗi. Nhưng không có công cụ di chuyển nào được xây dựng cho việc này. Đó là điểm mà tôi không có con đường phía trước.


Đây là một ý tưởng hay nhưng điều gì xảy ra khi một nhánh đổi tên một cột? Phần còn lại của các nhánh sẽ nhìn vào một cái bàn bị hỏng.
Kostas

ừm - đó là phần dính - nhánh nào quan tâm đến việc di chuyển. để bạn có thể "đồng bộ hóa" và nó biết, "hoàn nguyên di chuyển này" để cột quay trở lại.
JohnO

1

Tôi muốn đề xuất một trong hai lựa chọn:

lựa chọn 1

  1. Đưa dữ liệu của bạn vào seeds.rb. Một tùy chọn thú vị là tạo dữ liệu hạt giống của bạn thông qua đá quý FactoryGirl / Fabrication. Bằng cách này, bạn có thể đảm bảo rằng dữ liệu được đồng bộ hóa với mã nếu chúng tôi giả định rằng các nhà máy được cập nhật cùng với việc thêm / xóa các cột.
  2. Sau khi chuyển đổi từ nhánh này sang nhánh khác, hãy chạy rake db:reset, làm giảm / tạo / tạo cơ sở dữ liệu một cách hiệu quả.

Lựa chọn 2

Duy trì thủ công các trạng thái của cơ sở dữ liệu bằng cách luôn chạy rake db:rollback/ rake db:migratetrước / sau khi kiểm tra chi nhánh. Thông báo trước là tất cả các di chuyển của bạn cần phải được đảo ngược, nếu không điều này sẽ không hoạt động.


0

Về môi trường phát triển:

Bạn nên làm việc với rake db:migrate:redođể kiểm tra xem tập lệnh của bạn có thể đảo ngược hay không, nhưng hãy luôn nhớ rằng phải có một seed.rbdữ liệu với dân số.

Nếu bạn làm việc với git, bạn sẽ thay đổi seed.rb bằng thay đổi di chuyển và thực thi db:migrate:redođể bắt đầu (tải dữ liệu cho một phát triển mới trên máy khác hoặc cơ sở dữ liệu mới)

Ngoài ´changechange, với các phương thức lên xuống của bạn, mã của bạn luôn là các kịch bản bao trùm cho "thay đổi" trong thời điểm này và khi bắt đầu từ số không.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.