2009-02-18 37 views
68

Tôi có một chi nhánh sẽ có sẵn cho những người đóng góp khác và phải liên tục cập nhật với chủ nhân.git rebase và git push: không nhanh về phía trước, tại sao lại sử dụng?

Thật không may, mỗi khi tôi thực hiện 'git rebase' và sau đó cố gắng đẩy, nó dẫn đến thông báo 'không tiến nhanh' và phá thai. Cách duy nhất để đẩy ở đây là sử dụng --force. Điều đó có nghĩa là tôi nên sử dụng 'git merge' thay vì rebasing nếu nhánh của tôi đã được công khai và những người khác đang làm việc trên nó?

Trả lời

99

Một vài lưu ý về cách git công trình (không kỹ thuật):

Khi bạn rebase, git mất các cam kết trong câu hỏi, và "recommits" họ trên đầu trang của một lịch sử sạch. Điều này là để ngăn chặn lịch sử hiển thị:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge 
Commit SHA1: aaaa -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg 

Sau một rebase, nó có thể giống như thế này (hoặc tương tự):

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

Vấn đề là mới cam kết bạn đang cố gắng đẩy ra có KHÔNG phải là hậu duệ của cam kết trên đầu nhánh bạn đang đẩy tới.

Bây giờ, bạn biết rằng thông tin tương tự là trong các cam kết, nhưng git chịu trách nhiệm không chỉ ghi đè những cam kết đó (bbbb-gggg trong ví dụ trên).


Shared Repo Mẫu

Nếu bạn đang sử dụng một kho lưu trữ chia sẻ, sau đó mọi chuyện như thế này có thể nhận được hùng mạnh khó hiểu. Hãy để tôi giải thích lý do. Nói một nhà phát triển khác đã kéo chi nhánh xuống và họ đã cam kết aaaa -> gggg trong chi nhánh của họ. Sau đó, họ thực hiện một cam kết iiii

Trong khi đó, bạn rebased và buộc một sự thúc đẩy, làm cho cây trông như thế này:

Description: tree -> rebase 
Commit SHA1: aaaa -> hhhh 

Khi các nhà phát triển khác cố gắng để thúc đẩy, anh nhận được một " chuyển tiếp không nhanh ". Khi anh ấy làm một hợp nhất, sau đó cả hai lịch sử được liên kết lại với nhau, và bạn kết thúc với một mớ hỗn độn

Something như thế này (lộn xộn):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg -> iiii -> jjjj 

TRÊN Nói cách khác, nếu những người khác đang kéo VÀ đẩy , tốt hơn là bạn gắn bó với git merge, hoặc AVOID PUSHING cho đến sau khi rebase (và chỉ rebase công việc của bạn).


hiển thị công khai Repository mẫu

Có lẽ bạn đang sử dụng một mô hình khác nhau (gittish hơn), nơi bạn chỉ muốn mọi người để có thể kéo từ repo của bạn. Trong trường hợp này, git push --force không phải là quá xấu, bởi vì sau đó họ có thể đối phó với việc theo kịp với nó. Họ có thể rebase thay đổi của họ để được trên đầu trang của các thay đổi của bạn trước khi đưa ra các bản vá lỗi cho bạn.Nó ngăn cản repo của bạn nhận được tất cả các messed lên.

Tuy nhiên, có thể có cách tốt hơn cho bạn. git push --mirror

From http://www.kernel.org/pub/software/scm/git/docs/git-push.html

Thay vì đặt tên mỗi ref để đẩy, quy định rằng tất cả các refs dưới $ GIT_DIR/refs/(bao gồm nhưng không giới hạn ở refs/heads/, refs/remotes /, và refs/tags /) là được nhân đôi vào kho lưu trữ từ xa. Các tham số cục bộ mới được tạo sẽ được đẩy đến đầu từ xa, tại địa phương các cập nhật được cập nhật sẽ được cập nhật trên kết thúc từ xa và các thông số đã xóa sẽ được xóa khỏi đầu từ xa. là mặc định nếu cấu hình tùy chọn remote..mirror được đặt.


Một trong những điều tuyệt vời về git là nó rất linh hoạt và cho phép đối với nhiều loại khác nhau của quy trình công việc. Nhưng đó là sức mạnh thực sự nằm trong thực tế là nó là một mô hình phân tán, vì vậy tôi tin rằng ROI nhiều nhất có thể được gặt hái bằng cách sử dụng nó theo cách đó.

+7

Err, trên thực tế, việc hợp nhất tạo các cam kết hợp nhất, điều này thiếu rõ ràng không cần thiết. Thay vào đó, nó rất tuyệt vời đối với 'git fetch, git rebase origin/master', giải quyết tất cả xung đột cục bộ của bạn với nhánh master (tập trung), và sau đó đẩy các commit thuần túy chỉ di chuyển về phía trước. 'git pull --rebase' có luồng công việc tương tự. Đây là một tùy chọn mạnh mẽ, nhưng bạn phải cẩn thận với nó, vì việc xóa bỏ những thứ sai có thể viết lại các cam kết đã có trong nguồn gốc/chủ. Ví dụ. không rebase các chi nhánh khác, trừ khi họ đang rebased trên nguồn gốc hiện tại/chủ đầu tiên. – Kzqai

+0

Đồng ý, hợp nhất các cam kết nên tránh khi thực hiện lệnh git pull. Tuy nhiên, tôi nghĩ rằng họ là tốt để giữ khi cố ý sáp nhập một chi nhánh tính năng vào tổng thể. – ndbroadbent

+3

Tôi thích giải thích lý do tại sao có sự cố, đẩy chi nhánh bị từ chối. Nhưng tôi không chắc chắn những gì --mirror đạt được. Đọc mô tả - "chỉ định rằng * tất cả refs * sẽ được nhân đôi" - làm phiền tôi. Tôi không muốn * tất cả refs * nhân đôi, chỉ là một nhánh. :) Việc đặt tên chi nhánh sẽ chỉ phản ánh một nhánh? Nó không rõ ràng với tôi từ các tài liệu git. –

2

Không, việc rebase hoàn toàn hợp pháp với các kho lưu trữ công cộng và thậm chí có thể được mong muốn giữ lịch sử lưu loát. Chỉ cần nhớ rằng bạn không được sử dụng rebase để viết lại lịch sử của các cam kết được xuất bản từ xa. Đó là, rebase chỉ có thể được áp dụng cho chính bạn, địa phương, cam kết mà bạn chưa bao giờ được xuất bản. Bạn sử dụng rebase để đặt cam kết của bạn trên đầu trang của họ khi lấy và sau đó, có lẽ, điều chỉnh chúng ở đó. Một lý do khác mà bạn có thể nhận được thông báo như vậy là nhánh bạn đang đẩy đã được cập nhật và bạn cần phải đồng bộ hóa - tìm nạp và rebase cam kết của bạn trên đầu trang của những gì bạn đã tìm nạp.

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