Git rebase: Mọi thứ bạn cần biết

Tác giả sysadmin, T.M.Hai 13, 2022, 03:54:08 CHIỀU

« Chủ đề trước - Chủ đề tiếp »

0 Thành viên và 1 Khách đang xem chủ đề.

Git rebase: Mọi thứ bạn cần biết


Lệnh Git rebase di chuyển một nhánh đến một vị trí mới ở đầu nhánh khác. Không giống như lệnh hợp nhất Git, rebase liên quan đến việc viết lại lịch sử dự án của bạn. Đó là một công cụ tuyệt vời, nhưng đừng rebase cam kết mà các nhà phát triển khác đã làm việc dựa trên.


Lệnh Git rebasekết hợp hai nhánh mã nguồn thành một. Lệnh Git mergecũng làm điều đó. Chúng tôi giải thích rebasenó làm gì, nó được sử dụng như thế nào và khi nào thì sử dụng mergethay thế.

1. Vụ nổ Git

Thất vọng với các hệ thống kiểm soát phiên bản khác cũng như các bản cập nhật và cam kết chậm chạp của chúng, Linus Torvalds, người nổi tiếng về nhân Linux, đã dành một tháng vào năm 2005 để viết của riêng mình. Anh đặt tên cho nó là Git.

Các trang web như GitHub,  GitLab và  BitBucket  đã cùng nhau quảng bá và hưởng lợi từ Git. Ngày nay, Git được sử dụng trên toàn cầu, với  98% khổng lồ trong số 71 nghìn người trả lời  trong một cuộc khảo sát năm 2022 sử dụng Git làm hệ thống kiểm soát phiên bản.

Một trong những quyết định thiết kế chính của Git là tốc độ. Đặc biệt, làm việc với các chi nhánh phải nhanh nhất có thể. Các nhánh là một phần cơ bản của hệ thống kiểm soát phiên bản. Một kho lưu trữ dự án sẽ có một nhánh chính hoặc nhánh chính. Đây là nơi đặt cơ sở mã của dự án. Quá trình phát triển, chẳng hạn như các tính năng mới, diễn ra ở các nhánh phụ tách biệt. Điều này ngăn không cho công việc được thực hiện trong các nhánh làm xáo trộn nhánh chính và nó cho phép quá trình phát triển đồng thời diễn ra ở các phần khác nhau của cơ sở mã.

Khi quá trình phát triển ở các nhánh phụ được hoàn thành, các thay đổi sẽ được chuyển sang nhánh chính bằng cách hợp nhất nhánh phát triển vào nhánh chính. Trong các phiên bản khác, các hệ thống điều khiển làm việc với các nhánh rất khó và tốn kém về mặt tính toán. Làm việc với các nhánh trong Git rất nhanh và rất nhẹ. Điều từng là một bài tập tẻ nhạt và thường bị tránh trong các hệ thống khác, đã trở nên tầm thường trong Git.

Lệnh Git rebaselà một cách khác để chuyển các thay đổi từ nhánh này sang nhánh khác. Các lệnh mergevà rebasecó các mục tiêu tương tự, nhưng chúng đạt được mục đích theo những cách khác nhau và mang lại kết quả hơi khác nhau.

2. Hợp nhất Git là gì?

Vậy lệnh Git merge để làm gì? Giả sử bạn đã tạo một nhánh được gọi dev-branchđể làm việc trên một tính năng mới.


Bạn thực hiện một số cam kết và kiểm tra tính năng mới của mình. Tất cả đều hoạt động tốt. Bây giờ bạn muốn gửi tính năng mới của mình đến masterchi nhánh. Bạn phải ở trong masternhánh để hợp nhất một nhánh khác với nhánh đó.

Chúng tôi có thể đảm bảo rằng chúng tôi đang ở trong master chi nhánh bằng cách kiểm tra rõ ràng trước khi hợp nhất.

Mã nguồn [Chọn]
git checkout master
Bây giờ chúng ta có thể yêu cầu Git hợp nhất dev-branchvào nhánh hiện tại, đó là masternhánh.

Mã nguồn [Chọn]
git merge dev-branch

Của chúng tôi mergeđược hoàn thành cho chúng tôi. Nếu bạn kiểm tra masternhánh và biên dịch nó, nó sẽ có tính năng mới được phát triển trong đó. Những gì Git đã thực sự thực hiện là hợp nhất ba chiều. nó so sánh các lần xác nhận gần đây nhất trong nhánh mastervà dev-branchvà lần xác nhận trong masternhánh ngay trước khi được dev-branchtạo. Sau đó, nó thực hiện một cam kết trên masternhánh.

Hợp nhất được coi là không phá hủy vì chúng không xóa bất cứ thứ gì và chúng không thay đổi bất kỳ lịch sử Git nào. Vẫn dev-branchtồn tại và không có cam kết nào trước đó bị thay đổi. Một cam kết mới được tạo để ghi lại kết quả của việc hợp nhất ba chiều.

Sau khi hợp nhất, kho lưu trữ Git của chúng tôi trông giống như một dòng thời gian với một dòng thay thế phân nhánh và sau đó quay lại dòng thời gian chính.


Chi dev-branchnhánh đã được hợp nhất vào masterchi nhánh.

Nếu bạn có nhiều nhánh trong một dự án, lịch sử của dự án có thể trở nên khó hiểu. Đây thường là trường hợp nếu một dự án có nhiều người đóng góp. Vì nỗ lực phát triển chia thành nhiều con đường khác nhau nên lịch sử phát triển là phi tuyến tính. Việc gỡ rối lịch sử cam kết thậm chí còn khó khăn hơn nếu các nhánh có nhánh riêng.

Lưu ý rằng nếu bạn có các thay đổi chưa được cam kết trong masternhánh, bạn sẽ cần thực hiện điều gì đó với những thay đổi này trước khi có thể hợp nhất mọi thứ với nhánh đó. Bạn có thể tạo một nhánh mới và thực hiện các thay đổi ở đó, sau đó thực hiện hợp nhất. Sau đó, bạn cần hợp nhất nhánh tạm thời của mình trở lại nhánh chính.

Điều đó hoạt động, nhưng Git có một lệnh đạt được điều tương tự mà không cần phải tạo các nhánh mới. Lệnh stashlưu trữ các thay đổi không được cam kết cho bạn và cho phép bạn gọi lại chúng bằng stash pop.

Bạn muốn sử dụng chúng như thế này:

Mã nguồn [Chọn]
stash

git merge dev-branch

stash pop

Kết quả cuối cùng là một nhánh được hợp nhất, với các thay đổi chưa được lưu của bạn được khôi phục.

3. Git rebase là gì?

Lệnh Git rebase đạt được mục tiêu của nó theo một cách hoàn toàn khác. Nó lấy tất cả các cam kết từ nhánh mà bạn sẽ khởi động lại và phát lại chúng vào cuối nhánh mà bạn đang khởi động lại.

Lấy ví dụ trước của chúng tôi, trước khi chúng tôi thực hiện bất kỳ hành động nào, kho lưu trữ Git của chúng tôi trông như thế này. Chúng tôi có một nhánh được gọi dev-branchvà chúng tôi muốn chuyển những thay đổi đó sang master nhánh đó.


Sau rebase, nó trông giống như một dòng thời gian thay đổi hoàn toàn tuyến tính duy nhất.


Đã dev-branch bị xóa và các xác nhận trong dev-branchđã được thêm vào nhánh chính. Kết quả cuối cùng giống như thể các cam kết trong dev-branchthực tế đã được cam kết trực tiếp với masterchi nhánh ngay từ đầu. Các cam kết không chỉ được xử lý trên masternhánh, chúng được "phát lại" và thêm mới.

Đây là lý do tại sao rebaselệnh được coi là phá hoại. Nhánh bị rebase không còn tồn tại dưới dạng một nhánh riêng biệt và lịch sử Git của dự án của bạn đã được viết lại. Bạn không thể xác định tại một số thời điểm sau đó cam kết nào ban đầu được thực hiện cho dev-branch.

Tuy nhiên, nó để lại cho bạn một lịch sử tuyến tính, đơn giản hóa. So với một kho lưu trữ có hàng chục hoặc thậm chí hàng trăm nhánh và hợp nhất, việc đọc nhật ký Git hoặc sử dụng GUI git đồ họa để xem biểu đồ của kho lưu trữ, một kho lưu trữ bị khởi động lại rất dễ hiểu.

4. Làm thế nào để Rebase lên một nhánh khác

Hãy thử một git rebase ví dụ. Chúng tôi đã có một dự án với một chi nhánh được gọi là new-feature. Chúng tôi muốn rebase chi nhánh đó trên masterchi nhánh như thế này.

Đầu tiên, chúng tôi kiểm tra xem masterchi nhánh không có thay đổi nổi bật nào.

Mã nguồn [Chọn]
git status
Chúng tôi kiểm tra các new-featurechi nhánh.

Mã nguồn [Chọn]
git checkout new-feature
Chúng tôi yêu cầu Git chuyển rebasenhánh hiện tại lên nhánh chính.

Mã nguồn [Chọn]
git rebase master
Chúng ta có thể thấy rằng chúng ta vẫn có hai nhánh.

Mã nguồn [Chọn]
git branch
Chúng tôi trao đổi trở lại chi masternhánh

git checkout master

Chúng tôi hợp nhất nhánh tính năng mới vào nhánh hiện tại, trong trường hợp của chúng tôi là nhánh master.

Mã nguồn [Chọn]
git merge new-feature

Thật thú vị, chúng tôi vẫn có hai nhánh sau lần hợp nhất cuối cùng.


Sự khác biệt là, bây giờ người đứng đầu new-featurenhánh và người đứng đầu nhánh masterđược đặt để trỏ đến cùng một cam kết và lịch sử Git không hiển thị đã từng là một new-featurenhánh riêng biệt, ngoài nhãn nhánh.


5. Git Rebase so với Hợp nhất: Bạn nên sử dụng cái nào?

Đó không phải là trường hợp rebaseso với merge. Cả hai đều là những lệnh mạnh mẽ và có thể bạn sẽ sử dụng cả hai. Điều đó nói rằng, có những trường hợp sử dụng rebasekhông thực sự hoạt động tốt. Gỡ lỗi do sử dụng mergesai gây ra thật khó chịu, nhưng gỡ lỗi do lỗi gây ra thì rebase thật kinh khủng.

Nếu bạn là nhà phát triển duy nhất sử dụng kho lưu trữ, bạn sẽ ít có khả năng làm điều gì đó rebasetai hại với kho lưu trữ hơn. Ví dụ, bạn vẫn có thể rebaseđi sai hướng và rebasenhánh chính của bạn vào new-featurenhánh của bạn. Để lấy master lại chi nhánh của bạn, bạn cần phải thực rebasehiện lại, lần này là từ new-featurechi nhánh của bạn đến masterchi nhánh của bạn. Điều đó sẽ khôi phục masterchi nhánh của bạn, mặc dù có một lịch sử kỳ quặc.

Không sử dụng rebasetrên các nhánh được chia sẻ nơi những người khác có khả năng làm việc. Những thay đổi của bạn đối với kho lưu trữ của bạn sẽ gây ra sự cố cho nhiều người khi bạn đẩy mã bị từ chối của mình vào kho lưu trữ từ xa.

Nếu dự án của bạn có nhiều người đóng góp, điều an toàn cần làm là chỉ sử dụng rebasetrên kho lưu trữ cục bộ của bạn chứ không phải trên các nhánh công cộng. Tương tự như vậy, nếu yêu cầu kéo là một phần của đánh giá mã của bạn, không sử dụng rebase. Hoặc ít nhất, không sử dụng rebasesau khi tạo yêu cầu kéo. Các nhà phát triển khác có thể đang xem xét các cam kết của bạn, điều đó có nghĩa là những thay đổi đó nằm trên một nhánh công cộng, ngay cả khi chúng không nằm trên nhánh đó master.

Điều nguy hiểm là bạn sẽ thực hiện rebasecác cam kết đã được đẩy đến một kho lưu trữ từ xa và các nhà phát triển khác có thể đã làm việc dựa trên các cam kết đó. Địa phương của bạn rebasesẽ làm cho những cam kết hiện có biến mất. Nếu bạn đẩy những thay đổi đó vào kho lưu trữ, bạn sẽ không nổi tiếng.

Những người đóng góp khác sẽ phải trải qua một mớ hỗn độn mergeđể đưa công việc của họ trở lại kho lưu trữ. Sau đó, nếu bạn kéo các thay đổi của chúng trở lại kho lưu trữ cục bộ của mình, thì bạn sẽ phải đối mặt với việc bỏ chọn một mớ hỗn độn các thay đổi trùng lặp.

6. Rebase hay không Rebase?

Rebasecó thể bị đặt ngoài vòng pháp luật trong dự án của bạn. Có thể có sự phản đối của địa phương, văn hóa. Một số dự án hoặc tổ chức coi đó rebaselà một hình thức dị giáo và là một hành động mạo phạm. Một số người tin rằng lịch sử Git phải là một bản ghi vĩnh viễn, bất khả xâm phạm về những gì đã xảy ra. Vì vậy, rebasecó thể khỏi bàn.

Tuy nhiên, được sử dụng cục bộ, trên các nhánh riêng, rebaselà một công cụ hữu ích.

Đẩy sau khi bạn đã khởi động lại và giới hạn nó ở các nhánh mà bạn là nhà phát triển duy nhất. Hoặc ít nhất, khi tất cả sự phát triển đã dừng lại và không ai khác dựa trên bất kỳ công việc nào khác dựa trên các cam kết của chi nhánh của bạn.

Làm điều đó và bạn sẽ tránh được bất kỳ vấn đề.