Merge và Rebase là 2 công cụ để trộn 2 branch trong Git, mục đích sử dụng cho những tính huống khác nhau.
Một tình huống phổ biến khi sử dụng merge
- Tạo nhánh
my-new-feature
từ nhánh master
- Commit nhánh
my-new-feature
với một số thay đổi
- Tạo Pull Request:
my-new-feature
vào master
Sau khi my-new-feature
được merge
vào master
, chúng ta sẽ có
Đó là trường hợp lý tưởng rất ít khi xảy ra, 99.999999% là my-new-feature
có vài điểm cần bổ sung sau khi review code, bug chẳng hạn, sai chính tả chẳng hạn.
- Chúng ta bổ sung 2 commit C6 và C7 vào nhánh
my-new-feature
- Trong lúc đó,
master
cũng có thêm 2 commit C8, C9 được merge
vào bởi 2 bạn đồng nghiệp
- Cuối cùng PR của chúng ta cũng được
merge
Cái history lúc này (vẫn ok chứ không vấn đề gì)
Tuy nhiên, cũng là một tính huống rất hay gặp luôn, chúng ta ôm nhánh my-new-feature
gần một tuần mà chưa xong, và chúng ta muốn có C8, C9 đã được merge, và một cách chủ quan duy ý chí, dân dev chúng ta muốn có một cái history thật sạch đẹp, theo kiểu từng commit C4, C5, C6, C7,… là từng công việc rất cụ thể và độc lập, chúng ta không muốn gom hết một lượt đến cuối sprint rồi commit toàn bộ file là điều khiến người review code vô cùng mệt não.
Rebase giúp được gì ở tình huống này?
Năm 2016 Github giới thiệu một cách merge PR mới: Rebase and merge (Gitlab sẽ là Rebase front door). Nó cho phép chúng ta thực hiện một thao tác rebase trên commit PR rồi mới thực hiện việc merge. 2 thao tác này hoàn toàn độc lập và luôn đúng theo thứ tự rebase trước, merge sau, chứ ko có ngược lại.
Tương tự như nút Rebase and merge
, nếu dùng command
git checkout my-new-feature
git rebase master
git checkout master
git merge my-new-feature --ff
Bằng cách đó, history lúc này là một đường thẳng tắp
Rebase không phải để thay thế merge, rebase
dùng để thực hiện trên nhánh feature – private branch của chúng ta, merge thực hiện trên master – share branch với đồng nghiệp
Việc rebase
-> merge
như thế sẽ tránh mất đi những commit C4, C5, C6, C7 trên history của nhánh master
, như khi chỉ dùng một lệnh merge
. Chúng ta bê nguyên cái history của nhánh my-new-feature
lên luôn.
Vấn đề thứ 2, làm sao để sync nhánh my-new-feature
với master
(có C8, C9)?
/* lấy những thay đổi mới */
git fetch
/* checkout nhánh chúng ta muốn sync với master */
git checkout my-new-feature
/* thực hiện sync với master */
git rebase origin/master
Giữ nhánh my-new-feature
cập nhập với những thay đổi mới nhất ở nhánh master
để tránh quá nhiều conflict xảy ra khi tạo PR
Nút Rebase and merge không được yêu thích lắm, vì nó tạo quá nhiều conflict, nên chúng ta vẫn thường ưu ái merge hơn.
Để có một history thẳng hàng, đầy đủ tốn khá nhiều mồ hôi chứ không dễ như ăn bánh.