Phục hồi và ý nghĩa của việc khôi phục các cam kết đã đẩy


109

Người ta thường nói rằng, bạn không nên rebase các cam kết mà bạn đã đẩy. Ý nghĩa của điều đó là gì?

Câu trả lời:


80

Các cuốn sách ProGit có một lời giải thích tốt .

Câu trả lời cụ thể cho câu hỏi của bạn có thể được tìm thấy trong phần có tiêu đề " Mối nguy hiểm của việc phục hồi ". Trích dẫn từ phần đó:

Khi bạn căn cứ lại nội dung, bạn đang bỏ qua các cam kết hiện có và tạo các cam kết mới tương tự nhưng khác biệt. Nếu bạn đẩy các cam kết ở một nơi nào đó và những người khác kéo chúng xuống và dựa trên chúng, sau đó bạn viết lại các cam kết đó bằng git rebase và đẩy chúng lên một lần nữa, cộng tác viên của bạn sẽ phải hợp nhất lại công việc của họ và mọi thứ sẽ trở nên lộn xộn khi bạn cố gắng kéo công việc của họ trở lại với bạn.

Cập nhật:
Dựa trên nhận xét của bạn bên dưới, có vẻ như bạn đang gặp khó khăn với quy trình làm việc Git của mình. Dưới đây là một số tài liệu tham khảo có thể giúp ích:


Cảm ơn vì lời giải thích. Vì vậy, chỉ để làm cho hiểu biết của tôi rõ ràng hơn, sau khi tôi đẩy một số thay đổi nhất định, tôi không nên sử dụng git rebase(- tương tác?) Để viết lại lịch sử đó, đây chắc chắn là công thức thất bại. nhánh (từ nhánh X) và đẩy nó, hoàn toàn bình thường để rebase lại sau khi một nhà phát triển khác thay đổi nhánh chủ đề. Về cơ bản, tôi đã sử dụng mergemột thời gian khá lâu, nhưng chúng tôi ở cùng thuyền với, darwinweb.net/articles/86 và lịch sử gần như không sử dụng được.
Hemant Kumar

@Hemant: Rebasing cam kết sau khi đẩy lên repo công khai nói chung là một ý tưởng tồi. Nói như vậy, lời khuyên từ bài báo darwinweb mà bạn đã trích dẫn nghe có vẻ hợp lý nếu quy trình làm việc của bạn giống với quy trình của họ. Xem câu trả lời cập nhật của tôi để biết danh sách các tài liệu tham khảo khác có thể hữu ích.
Tim Henigan

Vui lòng cập nhật liên kết đến trang "ProGit" về "Nhóm được quản lý riêng" thành git-scm.com/book/en/…
Eimantas

Vì vậy, về mặt kỹ thuật, git cam kết vẫn giống nhau nhưng "trên tàu các cam kết hiện có và tạo những cam kết mới giống nhau nhưng khác" chỉ là cùng một cam kết với id sha1 khác nhau? Đó sẽ là cách rõ ràng duy nhất mà tôi có thể nghĩ về lý do tại sao các cộng tác viên sẽ phải hợp nhất lại công việc của chính họ!
Ciasto piekarz

@Ciastopiekarz, điều này là do bạn đang viết lại lịch sử trong repo ngược dòng và các repo cục bộ của nhà phát triển khác có thể có liên quan đến điều đó. Bây giờ các con trỏ của chúng đã cũ: ứng dụng khách git không có cách nào khác ngoài việc sử dụng các con trỏ cũ hơn và dựa vào con người để sắp xếp phần còn lại. Đây là sự hợp nhất lại và nó có thể RẤT lộn xộn với nhiều thay đổi khó hiểu phải được sắp xếp theo cách thủ công! Vì vậy, khuyến nghị không bao giờ căn cứ lại bất kỳ thứ gì đã được đẩy lên một đại diện ngược dòng. Đây là lời khuyên tốt và không nên bỏ qua trừ khi bạn là chuyên gia có kiến ​​thức sâu rộng.
Forbin

240

Để hiểu điều này, chúng ta cần hiểu một chút về cách hoạt động của git. Kho lưu trữ git là một cấu trúc cây, nơi các nút của cây được cam kết. Đây là một ví dụ về một kho lưu trữ rất đơn giản: Khi bạn ngã ba

nó có bốn cam kết trên nhánh chính và mỗi cam kết có một ID (trong trường hợp này là a, b, c và d). Bạn sẽ nhận thấy rằng d hiện là cam kết mới nhất (hoặc HEAD) của nhánh chính. nhập mô tả hình ảnh ở đây

Ở đây, chúng ta có hai nhánh: master và my-branch. Bạn có thể thấy rằng master và my-branch đều chứa các commit a và b, nhưng sau đó chúng bắt đầu phân kỳ: master chứa c và d, trong khi my-branch chứa e và f. b được cho là "cơ sở hợp nhất" của nhánh tôi so với cơ sở chính - hoặc thông thường hơn, chỉ là "cơ sở". Nó có ý nghĩa: bạn có thể thấy rằng chi nhánh của tôi dựa trên phiên bản trước của master.

Vì vậy, giả sử rằng chi nhánh của tôi đã cũ và bạn muốn cập nhật nó với phiên bản master mới nhất. Nói một cách khác, my-branch cần chứa c và d. Bạn có thể thực hiện hợp nhất, nhưng điều đó khiến nhánh chứa các cam kết hợp nhất kỳ lạ khiến việc xem xét yêu cầu kéo khó khăn hơn nhiều. Thay vào đó, bạn có thể thực hiện rebase.

nhập mô tả hình ảnh ở đây

Khi bạn rebase, git tìm thấy cơ sở của chi nhánh của bạn (trong trường hợp này là b), tìm tất cả các cam kết giữa cơ sở đó và HEAD (trong trường hợp này là e và f) và phát lại các cam kết đó trên HEAD của chi nhánh bạn đang phục hồi (trong trường hợp này là thạc sĩ). Git thực sự tạo ra các cam kết mới đại diện cho các thay đổi của bạn trông như thế nào trên trang chủ: trong sơ đồ, các cam kết này được gọi là e ′ và f ′. Git không xóa các cam kết trước đây của bạn: e và f được giữ nguyên, và nếu có vấn đề gì xảy ra với rebase, bạn có thể quay lại ngay như trước đây.

Khi nhiều người khác nhau đang làm việc trên một dự án một cách mô phỏng, các yêu cầu kéo có thể bị lỗi nhanh chóng. Yêu cầu kéo "cũ" là yêu cầu không còn cập nhật với dòng phát triển chính và cần được cập nhật trước khi có thể được hợp nhất vào dự án. Lý do phổ biến nhất khiến các yêu cầu kéo bị lỗi là do xung đột: nếu hai yêu cầu kéo cùng sửa đổi các dòng tương tự trong cùng một tệp và một yêu cầu kéo được hợp nhất, thì yêu cầu kéo không hợp nhất bây giờ sẽ có xung đột. Đôi khi, một yêu cầu kéo có thể cũ mà không có xung đột: có thể những thay đổi trong một tệp khác trong cơ sở mã yêu cầu những thay đổi tương ứng trong yêu cầu kéo của bạn để phù hợp với kiến ​​trúc mới hoặc có thể nhánh được tạo khi ai đó vô tình hợp nhất các bài kiểm tra đơn vị không thành công với chi nhánh chủ. Bất kể lý do là gì,


68

Rebasing viết lại lịch sử. Nếu không ai biết về lịch sử đó, thì điều đó hoàn toàn ổn. Tuy nhiên, nếu lịch sử đó được công chúng biết đến, thì việc viết lại lịch sử trong Git hoạt động giống như cách nó làm trong thế giới thực: bạn cần một âm mưu.

Các âm mưu thực sự khó giữ được với nhau, vì vậy tốt hơn hết bạn nên tránh gây trở ngại cho các chi nhánh công cộng ngay từ đầu.

Lưu ý rằng có những ví dụ về các âm mưu thành công: puchi nhánh của kho lưu trữ git của Junio ​​C. Hamano (kho lưu trữ chính thức của Git SCM) thường xuyên được phục hồi. Cách hoạt động của điều này là hầu hết mọi người sử dụng pucũng đăng ký vào danh sách gửi thư của nhà phát triển Git, và việc puchi nhánh được khôi phục lại được công bố rộng rãi trên danh sách gửi thư và trang web Git.


4
+1. Tôi nghĩ rằng punhánh của git.git là một ví dụ cực kỳ hữu ích về cách sử dụng rebase trong quy trình làm việc (công khai). Đối với những người không quen thuộc với nó, ý tưởng chung là căn cứ lại các nhánh chủ đề không có bất kỳ cam kết nào next(nhánh không ổn định ngay trước khi hợp nhất thành chủ), sau đó xây dựng lại punhánh bằng cách đặt lại nextvà hợp nhất tất cả các nhánh chủ đề. (Nguồn: Documentation / howto / duy trì-git.txt git.kernel.org/?p=git/git.git;a=blob;f=Documentation/howto/… )
Cascabel

25
1 cho "viết lại lịch sử trong Git hoạt động giống theo cách nó trong thế giới thực: bạn cần một âm mưu"
Sleeper Smith

"Thông báo công khai là không cần thiết vì pu là một nhánh bỏ đi, như đã mô tả ở trên." git-scm.com/docs/gitworkflows Chúng tôi làm điều gì đó tương tự tại nơi làm việc, "TEMP-something- new " là một nhánh vứt bỏ, là sự kết hợp của những thay đổi mới nhất, nó có thể là sự hợp nhất của nhiều nhánh tính năng, có thể bị xóa và được tạo lại tại bất kỳ thời điểm nào và không nên phát triển tiếp.
pilkch,

6

Một rebase thay đổi lịch sử của kho lưu trữ của bạn. Nếu bạn đẩy các cam kết ra thế giới, tức là cung cấp chúng cho những người khác, và sau đó bạn thay đổi quan điểm của mình về lịch sử cam kết, thì sẽ khó làm việc với bất kỳ ai có lịch sử cũ của bạn.

Tôi nghĩ rằng Rebase được coi là có hại là một tổng quan tốt.

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.