2009-09-23 29 views
23

Tôi đang cố gắng để có hai chi nhánh với các tập tin nhị phân trong git - một "phát triển" và một "ổn định". Nhánh phát triển có thể có một số thay đổi của các tệp này trước khi tôi muốn "giải phóng" chúng vào nhánh ổn định (và nhánh ổn định có các tệp đó được đổi tên, trong trường hợp có liên quan).Git hợp nhất squash liên tục

Tôi có thể thực hiện kết hợp bình thường, hoạt động tốt, nhưng giữ lại quá nhiều lịch sử - khi kéo nhánh "ổn định", tất cả các cam kết trung gian từ nhánh "phát triển" cũng được kéo (vì chúng là commit của cha) . Nhưng chúng ta đang nói về các tệp nhị phân không có bất kỳ chiến lược hợp nhất hợp lý nào (ngoại trừ của chúng/của chúng ta), vì vậy lịch sử thực sự của các tệp trên nhánh phát triển là vô dụng. Khi tôi kéo chi nhánh "ổn định", tôi có được điều này:

 
      X-------------------G stable 
     /    /
    a---b---c---d---e---f---g development 

Bởi vì G có cha mẹ tại các chi nhánh phát triển, tôi nhận được toàn bộ lịch sử của chi nhánh phát triển (đối tượng dữ liệu cho c, d, e, f và g) trong kho lưu trữ của tôi, mà tôi không quan tâm (X giống như b, với một số đổi tên tệp được áp dụng).

Vì vậy, tôi đã cố gắng git merge --squash thay đổi từ chi nhánh phát triển đến nhánh ổn định. Việc hợp nhất đầu tiên như vậy và cam kết đi OK, kết quả được như mong đợi (log thay đổi tốt đẹp trong thông điệp cam kết, không liên quan đến các chi nhánh phát triển):

   X-------------------G stable 
     /     
    a---b---c---d---e---f---g development

Sau khi tôi kéo nhánh ổn định bị đè nén này, tôi có được điều này trong kho của tôi, đó là những gì tôi muốn:

 
a---b---X---G 

Nhưng việc hợp nhất thứ hai thất bại (vì git không có cách nào để biết có bao nhiêu tôi sáp nhập đã và đã nhầm lẫn).

  • Có thể bằng cách nào đó ghi lại quá trình hợp nhất mà không tạo "cam kết hợp nhất" với hai cha mẹ không?
  • Hoặc, có thể yêu cầu git chỉ hợp nhất một "phạm vi" nhất định của các sửa đổi, như trong SVN không?
  • Hoặc, có thể thực hiện việc hợp nhất thông thường mà không phải tải xuống tất cả các thay đổi từ nhánh khác khi kéo?
  • Hoặc tôi có nên cung cấp trình điều khiển hợp nhất tùy chỉnh cho các tệp được đề cập không, chỉ cần đổi tên phiên bản "của chúng thành" của chúng tôi, qua đó giải quyết xung đột? Tôi vẫn sợ rằng --squash sẽ luôn cố gắng hợp nhất toàn bộ lịch sử, với cha mẹ chung, chỉ giải quyết được một nửa vấn đề của tôi.

Cập nhật: rebasing

Nếu tôi hiểu rebasing một cách chính xác, tôi sẽ kết thúc với điều này:

 
           X stable 
          /
    a---b---c---d---e---f---g development 

nào được tôi tất cả các dữ liệu Tôi không quan tâm đến (c , d, e, f) và như một phần thưởng, tôi sẽ mất thông tin rằng b là một phiên bản ổn định trong chi nhánh.

Mỗi bản sửa đổi phát triển thêm khoảng 5MB vào kích thước kho lưu trữ (và đóng gói toàn bộ repo thu nhỏ chỉ khoảng 10%), nhánh "ổn định" gần như miễn phí (dữ liệu đã có sẵn). Tôi muốn kéo một bản sửa đổi mới từ nhánh ổn định để kéo chỉ 5MB mới, nhưng thay vì cập nhật từ X thành G tải xuống 25MB, bởi vì tôi bằng cách nào đó không thể nói rằng tôi không quan tâm đến nội dung của c, d , e và f.

Trả lời

23

Bắt đầu với

 X stable 
    /     
a---b---c---d---e---f---g development 

Bạn có thể sử dụng các bước sau đây để sao chép cam kết cuối cùng từ chi nhánh phát triển của bạn đến chi nhánh ổn định của bạn:

git checkout [email protected]{0} # get working tree from "development", detach HEAD 
git reset --soft stable # reposition detached HEAD on "stable" 
git commit # enter the appropriate commit message 
git branch temp # create a temporary branch "temp" at HEAD 
git checkout temp # get on the new temporary branch 
git branch -M stable # rename "temp" to "stable" 

để bạn kết thúc lên với:

 X-------------------G stable 
    /     
a---b---c---d---e---f---g development 

Nếu bạn tiếp tục làm việc trên "phát triển", ví dụ:

 X-------------------G stable 
    /     
a---b---c---d---e---f---g---h---i---j development 

bạn có thể lặp lại git cùng lệnh như trên và bạn sẽ kết thúc với:

 X-------------------G-----------J stable 
    /     
a---b---c---d---e---f---g---h---i---j development 
+1

Điều này có vẻ tuyệt vời, nhưng tôi không hiểu chính xác lý do tại sao cần tạo một nhánh tạm thời và sau đó đổi tên nó. Có phải vì bạn vẫn bị tách rời sau khi cam kết? –

+0

@ kim-sullivan: "chính xác tại sao": khi bạn thực hiện cam kết trong ví dụ trên, nó di chuyển 'HEAD' nhưng không' ổn định 'để trỏ đến cam kết mới - đầu vẫn bị "tách" và ' stable' vẫn trỏ đến phiên bản trước (X, trong ví dụ ban đầu của bạn). Làm chi nhánh và đổi tên (thanh toán là tùy chọn về mặt kỹ thuật, mặc dù không có nó, bạn sẽ cần phải cung cấp cho các đối số cho 'git branch -M', và bạn vẫn sẽ được tách ra, có khả năng không mong muốn). đến J (theo câu trả lời). – lindes

+4

Ngoài ra: Bạn có thể thấy chạy 'git log --graph --oneline --all --decorate' và' git status' tại mỗi điểm dọc theo chuỗi lệnh này để có thông tin. Và/hoặc xem nội dung của các tệp khác nhau trong .git /, có lẽ với 'grep. .git/HEAD .git/refs/heads/* ' – lindes

7

Đây không phải là nơi thích hợp để sử dụng merge --squash.Một nơi tốt để sử dụng nó là trong một nhánh chủ đề throwaway, mà bạn sẽ hợp nhất vào nhánh chính của bạn và sau đó thoát khỏi. Tất cả sự phát triển được thực hiện trong nhánh chủ đề được hiển thị như một cam kết trong nhánh chính. Trong trường hợp của bạn, bạn nên hợp nhất từ ​​nhánh phát triển một cách bình thường, và sau đó sử dụng git-rebase --interactive để bíp các cam kết bạn muốn.

Có thể bằng cách nào đó ghi lại quá trình hợp nhất mà không tạo "cam kết hợp nhất" với hai cha mẹ không?

Nếu tôi hiểu câu hỏi đúng, không. Tuyệt đối không phải.

Có thể yêu cầu git chỉ hợp nhất một "phạm vi" nhất định của các sửa đổi, như trong SVN không?

Có. git merge [commit hash]

Hoặc là nó có thể làm việc kết hợp với bình thường mà không cần phải tải về tất cả các refs từ chi nhánh khác khi kéo?

Xem câu trả lời cho câu hỏi trước.

Hoặc tôi nên cung cấp một trình điều khiển tùy chỉnh hợp nhất cho các tập tin trong câu hỏi, mà chỉ đơn giản đổi tên phiên bản "của họ" thành "chúng tôi", qua đó giải quyết những mâu thuẫn? Tôi vẫn sợ rằng - câu hỏi sẽ luôn luôn cố gắng để kết hợp toàn bộ lịch sử, lên đến cha mẹ chung, giải quyết chỉ một nửa vấn đề của tôi.

Không! Chỉ cần không sử dụng git merge --squash. Đây không phải là nơi thích hợp để sử dụng nó!

+0

Cảm ơn câu trả lời của bạn! Tôi không chắc chắn rằng rebasing là những gì tôi cần. Tôi cần phải ghi lại một số lịch sử trong nhánh "ổn định", vì vậy tôi có thể đi qua lại giữa "bản phát hành".Đây là những gì tôi muốn: ' D -> S D | D | D -> S D | D -> S' Nhưng tôi chỉ cần lịch sử từ chi nhánh S - Tôi không quan tâm đến lịch sử từ nhánh D. Vấn đề tôi cần giải quyết là làm thế nào để kéo nhánh S mà không kéo tất cả các ref của cha mẹ từ nhánh D (nếu tôi hiểu nó đúng, rebasing sẽ loại bỏ tất cả các commit trước đó mà không phải là thứ tôi muốn). ' D -> x D D D -> x D D -> S' –

+0

Vâng, tôi hiểu rằng bạn cần phải bảo tồn lịch sử hiện từ chi nhánh S. Không, rebasing không loại bỏ tất cả các commit trước đó; trước khi hợp nhất phát triển thành ổn định, hãy lưu ý [commit hash] và sau đó git rebase -i [commit hash] - sau đó bạn sẽ chỉ thực hiện các cam kết mà bạn vừa mới hợp nhất. Ngoài ra, theo như các bản phát hành có liên quan, tại sao không chỉ gắn thẻ các cam kết cụ thể dưới dạng bản phát hành? – artagnon

+0

Tôi xin lỗi tôi không hoàn toàn hiểu D -> S D | D sơ đồ quá tốt. Tôi hy vọng bình luận trước đó của tôi đã làm rõ mọi thứ. – artagnon

4

bạn có thể sử dụng git rebase -i (chế độ tương tác) để sqash tất cả các thay đổi của bạn, chỉ cần thay đổi dòng để m hoặc meld (Cập nhật: cho Git mới hơn releases gõ s hoặc squash)

bạn sẽ hơn có một cam kết duy nhất mà bạn có thể hợp nhất.nếu bạn muốn mỗi bước của bạn được dành riêng, bạn phải tạo một nhánh khác trên nhánh hacking của bạn trước khi thực hiện rebase, điều này có thể được thực hiện với git branch small-dirty-changes-i-don’t-want-anybody-to-see

tất cả điều này phải được thực hiện trước khi cố hợp nhất; từng bước:

# on branch "hacking": hack commit hack commit hack commit 

# create a reference to your history 
$ git branch dirty-history 

# sqash your commits by setting all lines to "meld" 
$ git rebase -i 

# checkout master or the branch you want to merge to 
$ git checkout master 

# merge your squashed commit 
$ git merge hacking 
# or: $ git pull hacking 
+0

Hm, tôi có thể rebase những thay đổi trên nhánh phát triển ("bẩn") một lần trong một thời gian (thực sự, trước khi sáp nhập ổn định và phát hành), vì vậy tôi không có tất cả những nhị phân trung gian tôi không quan tâm nhiều . Điều quan trọng duy nhất giữa các bản phát hành ổn định là băm và các thông điệp cam kết ... Băm là quan trọng để thử nghiệm (mà xây dựng đã được thử nghiệm và không được). Tôi sẽ phải suy nghĩ về nó một số chi tiết. –

+0

câu trả lời hay, tôi đoán "meld" ngày nay có nghĩa là "squash" (câu trả lời của bạn là từ năm 2009!) –

+1

Vâng, bây giờ là 's' /' squash'. – knittl

-1

Tôi mới đến git, nhưng có vẻ như --squash là thứ bạn muốn, bạn chỉ cần xử lý nhánh khác nhau.

$ git merge --squash development 
$ git branch -d development 
$ git checkout -b development 
# continue work on development branch 

này về cơ bản sẽ cắt ngắn lịch sử của chi nhánh phát triển, và việc hợp nhất tiếp theo sẽ chỉ là những gì bạn muốn. Nhìn vào trang người đàn ông có vẻ như git branch -f development có thể làm điều tương tự như xóa và tạo lại nhánh.

Như tôi đã nói, tôi khá mới với git, vì vậy tôi rất thích một số ý kiến ​​phản hồi về ý tưởng này.

0

top voted answer có hiệu quả khác nhau giữa các nhánh ổn định và phát triển và áp dụng tất cả các thay đổi bị thiếu trong ổn định dưới dạng một cam kết. Có một cách khác để thực hiện việc này:

$ git checkout stable 
$ git diff stable development | git apply --index - 
$ git commit 

Trước khi bạn cam kết, bạn có thể xem lại các tệp được dàn dựng. Nếu bạn muốn hủy bỏ quá trình sau khi bạn áp dụng các khác biệt, bạn chỉ có thể sử dụng lệnh cơ bản để loại bỏ những thay đổi từ chỉ mục và thư mục làm việc.

$ git reset --hard 

Bạn có thể lặp lại quá trình này bất kỳ lúc nào, vì bạn thực sự chỉ cần tìm các mẹo của cả hai nhánh mỗi lần bạn cần hợp nhất. Lưu ý rằng có giả thiết ở đây cũng áp dụng cho câu trả lời khác: không có cam kết nào trong nhánh ổn định khác với cam kết xuất phát từ chi nhánh phát triển. Nếu cùng một dòng được thay đổi một cách độc lập trong cả hai nhánh, không giống như việc hợp nhất thông thường, cách tiếp cận này sẽ không cho bạn xung đột. Thay vào đó, nó sẽ chỉ ghi đè lên những thay đổi trong nhánh ổn định với những thay đổi đang được phát triển.

Nếu bạn quan tâm về điều này, mỗi khi bạn cam kết ổn định, bạn có thể đặt phát triển hợp nhất cam kết phạm vi băm trong thông điệp cam kết. Bằng cách đó, bạn có một số bản ghi, nếu bạn cần quay lại.

Các vấn đề liên quan