Git - Phân nhánh với Rebase
Trong Git, có hai cách để trộn hai nhánh với nhau đó là sử dụng merge và rebase
. ở bài trước mình đã giới thiệu về merge nhưng chưa nói về quy trình hoạt động, lý do như mình đã trình bày là ban đầu bạn cần hiểu một số lệnh thì lúc giải thích lý thuyết mới dễ hiểu, vì vậy thông qua bài này hy vọng bạn sẽ nắm nắm được ý nghĩa của hai lệnh này.
1. Git rebase là gì?
Như trong bài viết tìm hiểu lệnh merge, lệnh này sẽ merge hai branch lại với nhau và nó sẽ chọn commit mới nhất (snapshot mới nhất) để thực hiện. Nhưng với rebase thì cơ chế hoạt động có chút khác biệt, nó sẽ so sánh và lưu những thay đổi giữa hai nhánh vào một file tạm, sau đó thực hiện fast-forward merge
.
Từ khóa trong bài:
- Branch đang làm việc: Chính là branch mà bạn đang làm việc.
- Branch cần trộn: Chính là branch mà bạn muốn trộn vào branch hiện tại.
- Branch cần rebase: Chính là branch mà bạn muốn rebase vào branch hiện tại.
Giả sử ta có hai nhánh đó là nhánh master
và experiment
, trong đó nhánh master chính là branch hiện tại.
Bài viết này được đăng tại [free tuts .net]
Hình 1: Danh sách các commit của hai nhánh
Xem lại lệnh merge
Nếu chúng ta sử dụng merge để trộn hai branch với nhau thì nó sẽ thực hiện trộn trực tiếp giữa hai commit mới nhất (C3, C4) và commit cha chung gần nhất đó là (C2), kết quả là tạo ra một commit C5 nằm trên branch đang làm việc, và commit C5 này chính là thành quả của phép trộn (hình 2).
Hình 2: thực hiện merge
Rebase thì sao?
Với rebase thì lại khác, nó sẽ tạo ra một phiên bản mới (tạm thời) mang tên C3' và trộn nó vào C4, phương pháp này ta gọi là rebase (Hình 3).
Hình 3: Tập tin tạm thời C3'
Quy trình thực hiện rebase: Nó sẽ thực hiện bằng cách tìm tới commit cha gần nhất của hai nhánh (tức là nhánh đang làm việc và nhánh cần rebase), tìm sự khác biệt trong mỗi commit của nhánh đang làm việc so với nhánh cần rebase và lưu vào một file tạm (C3'), cuối cùng sẽ thực hiện một fast-forward merge để nhảy tới C3' (Hình 4).
Hình 4: Thực hiện fast-forward merge
Bây giờ snapshot C3' sẽ có địa chỉ giống như C5 ở trong ví dụ merge. Để rõ ràng hơn thì mình sẽ nói về điểm giống nhau và khác nhau giữa hai phương pháp này.
Giống nhau: Cả hai phương pháp đều cho kết quả như nhau, có nghĩa là C3' à C5 đều có chung một kết quả
Khác nhau:
- Merge: Thao tác merge là kết quả của phép trộn giữa ba commit, đó là commit cha chung và 2 commit mới nhất của 2 nhánh (hai điểm kết thúc), kết quả sẽ tạo ra một commit chứa kết quả của phép trộn. Vì vậy lịch sử tại nhánh đang làm việc sẽ bị gián đoạn tại C5 (nghĩa là giữa C4 và C5 không có lịch sử rõ ràng).
- Rebase: Cho lịch sử rõ ràng hơn, bởi nó sẽ duyệt qua từng commit của nhánh đang làm việc và thực hiện thay đổi, vì vậy nhìn vào ta sẽ thấy giống như một đường thẳng.
Khi làm việc bạn có thể chọn một trong hai đều được, nhưng có một số trường hợp bạn nên sử dụng rebase thì tốt hơn. Ví dụ bạn đang làm việc nhóm, mỗi thành viên làm trên một branch, và khi bạn merge với nhau thì các thành viên sẽ không thấy lịch sử thay đổi của dự án một cách rõ ràng, nhưng nếu bạn sử dụng rebase thì họ sẽ dễ dàng thấy hơn.
2. Rebase nâng cao
Phải có những điểm quan trọng khác nữa nên người ta mới tạo ra lệnh rebase này, nếu không thì chỉ cần merge là quá đủ.
Rebase --onto 3 tham số
Giả sử:
- Bước 1: Bạn đang làm việc trên branch
master
, tại đây bạn tạo mới một branchserver
- Bước 2: Bạn checkout sang branch
server
, tại đây bạn tạo một branchclient
, sau đó thực hiện một vài commit - Bước 3: Bạn checkout sang branch
client
và thực hiện một vài commit - Bước 4: Bạn checkout sang branch
server
và tiếp tục thực hiện một vài commit
Quy trình được mô phỏng dưới hình ảnh sau:
Hình 5: Mô phỏng quy trình làm việc
Theo như hình này thì HEAD sẽ trỏ tới branch server (HEAD tức là branch đang làm việc). Giả sử xếp muốn bạn thực hiện đẩy những gì mà bạn đã làm ở client
(C8, C9) để push live thì sao? Lúc này nếu bạn sử dụng merge thì theo nguyên tắc C3 cũng được merge, nhưng C3 lại nằm ở nhánh server
mà nhánh này thì chưa được kiểm tra kỹ lưỡng => cần phải có một giải pháp khác.
Ta sẽ sử dụng lệnh rebase --onto, với cú pháp như sau:
$ git rebase --onto master server client
Ý nghĩa của nó như sau: Hãy checkout nhánh client
, tìm ra bản vá từ commit chung của hai nhánh client
và server
, sau đó thiết lập master
chính là nhánh cha của client
(tức cha của client cũng chính là cha của master C2)
Hình 6: Sử dụng rebase -onto
Mô hình sẽ có dạng như sau:
Hình 07: Mô phỏng quá trình rebase
Bây giờ branch client
và branch server
là 2 branch tách biệt với nhau, vì vậy bạn có thể thực hiện thao tác merge bình thường để trộn client vào master
.
$ git checkout master $ git merge client
Rebae --onto 2 tham số
Giả sử bạn muốn kéo nhánh server
thì bạn chỉ cần thực hiện lệnh rebase --onto
với 2 tham số truyền vào.
$ git rebase master server
Sau đó bạn di chuyển con trỏ tới master và thực hiện merge.
$ git checkout master $ git merge server
3. Lời kết
Như vậy là mình đã giới thiệu xong về lệnh rebase và rebase --onto, qua bài này hy vọng bạn sẽ hiểu sự khác nhau giữa merge và rebase.
Tuy rebase rất hữu ích nhưng bạn không nên sử dụng nó trong trường hợp các commit của bạn có công khai ở remote repository, bỏi nếu bạn đã public công khai thì sẽ ảnh hưởng đến các thành viên khác.