Git: Git merge (Hợp nhất Git)


Khóa học qua video:
Python C# Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Hợp nhất (Merge) là cách Git sắp xếp lại lịch sử rẽ nhánh. Lệnh git merge cho phép bạn lấy các dòng phát triển độc lập được tạo bởi git branch và tích hợp chúng vào một nhánh duy nhất.

Lưu ý rằng tất cả các lệnh được trình bày bên dưới hợp nhất vào nhánh hiện tại. Nhánh hiện tại sẽ được cập nhật để phản ánh việc hợp nhất, nhưng nhánh mục tiêu sẽ hoàn toàn không bị ảnh hưởng. Một lần nữa, điều này có nghĩa là git merge thường được sử dụng cùng với git checkout cho việc chọn nhánh hiện tại và git branch -d để xóa nhánh mục tiêu lỗi thời.

Cách thức hoạt động

Git merge sẽ kết hợp nhiều chuỗi xác nhận thành một lịch sử thống nhất. Trong các trường hợp sử dụng thường xuyên nhất, git merge được sử dụng để kết hợp hai nhánh. Các ví dụ sau trong tài liệu này sẽ tập trung vào mẫu hợp nhất nhánh này. Trong các tình huống này, git merge nhận hai con trỏ xác nhận, thường là các mẹo rẽ nhánh và sẽ tìm thấy một commit cơ sở chung giữa chúng. Khi Git tìm thấy một commit cơ sở chung, nó sẽ tạo một "commit hợp nhất" mới kết hợp các thay đổi của từng chuỗi cam kết hợp nhất được xếp hàng đợi.

Giả sử chúng ta có một tính năng nhánh mới dựa trên nhánh main. Bây giờ chúng ta muốn hợp nhất nhánh tính năng này vào main.

Gộp 2 nhánh

Gọi lệnh này sẽ hợp nhất tính năng nhánh đã chỉ định vào nhánh hiện tại, chúng ta sẽ giả sử main. Git sẽ tự động xác định thuật toán hợp nhất (thảo luận bên dưới).

Nút cam kết hợp nhất mới

Các commit hợp nhất là duy nhất so với các commit khác trong thực tế là chúng có hai commit cha. Khi tạo một commit hợp nhất, Git sẽ cố gắng tự động hợp nhất một cách kỳ diệu các lịch sử riêng biệt cho bạn. Nếu Git gặp một phần dữ liệu bị thay đổi trong cả hai lịch sử, nó sẽ không thể tự động kết hợp chúng. Trường hợp này là xung đột kiểm soát phiên bản và Git sẽ cần sự can thiệp của người dùng để tiếp tục. 

Chuẩn bị hợp nhất

Trước khi thực hiện hợp nhất, có một số bước chuẩn bị cần thực hiện để đảm bảo quá trình hợp nhất diễn ra suôn sẻ.

Xác nhận nhánh nhận

Thực thi git status để đảm bảo rằng HEAD đang trỏ đến đúng nhánh nhận hợp nhất. Nếu cần, thực hiện git checkout để chuyển sang nhánh nhận. Trong trường hợp của chúng ta, ta sẽ thực hiện git checkout main.

Tìm nạp các commit từ xa mới nhất

Đảm bảo rằng nhánh nhận và nhánh hợp nhất được cập nhật với các thay đổi từ xa mới nhất. Thực thi git fetch để lấy các xác nhận từ xa mới nhất. Khi quá trình tìm nạp hoàn tất, cần đảm bảo nhánh main có các bản cập nhật mới nhất bằng cách thực thi git pull.

Hợp nhất

Khi bước "chuẩn bị hợp nhất" được thực hiện, việc hợp nhất có thể được bắt đầu bằng cách thực hiện git merge trong đó  là tên của nhánh sẽ được hợp nhất vào nhánh nhận.

Hợp nhất chuyển tiếp nhanh

Hợp nhất chuyển tiếp nhanh có thể xảy ra khi có một đường dẫn tuyến tính từ đầu nhánh hiện tại đến nhánh mục tiêu. Thay vì “thực sự” hợp nhất các nhánh, tất cả những gì Git phải làm để tích hợp lịch sử là di chuyển (nghĩa là “tua nhanh”) đầu nhánh hiện tại đến đầu nhánh mục tiêu. Điều này kết hợp các lịch sử một cách hiệu quả, vì tất cả các commit có thể truy cập được từ nhánh mục tiêu hiện có sẵn thông qua nhánh hiện tại. Ví dụ: hợp nhất nhanh một số tính năng vào main sẽ giống như sau:

Các nút nút tính năng trước nút chính, sau khi chuyển tiếp nhanh, cả hai đều trên cùng một nút

Tuy nhiên, không thể hợp nhất chuyển tiếp nhanh nếu các nhánh đã phân kỳ. Khi không có đường dẫn tuyến tính đến nhánh mục tiêu, Git không có lựa chọn nào khác ngoài việc kết hợp chúng thông qua hợp nhất 3 chiều. Hợp nhất 3 chiều sử dụng một commit chuyên dụng để liên kết hai lịch sử lại với nhau. Danh pháp xuất phát từ thực tế là Git sử dụng ba lần xác nhận để tạo ra lần xác nhận hợp nhất: hai mẹo nhánh và tổ tiên chung của chúng.

Mặc dù bạn có thể sử dụng một trong hai chiến lược hợp nhất này, nhưng nhiều nhà phát triển thích sử dụng các hợp nhất chuyển tiếp nhanh (được hỗ trợ thông qua rebasing) cho các tính năng nhỏ hoặc sửa lỗi, trong khi dành riêng các hợp nhất 3 chiều để tích hợp các tính năng chạy lâu hơn. Trong trường hợp sau, commit hợp nhất kết quả đóng vai trò là sự kết hợp tượng trưng của hai nhánh.

Ví dụ đầu tiên của chúng ta thể hiện sự hợp nhất chuyển tiếp nhanh. Đoạn mã dưới đây tạo một nhánh mới, thêm hai lần xác nhận vào nhánh đó, sau đó tích hợp nhánh đó vào dòng chính bằng cách hợp nhất chuyển tiếp nhanh.

# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature

Đây là quy trình công việc phổ biến cho các nhánh chủ đề tồn tại trong thời gian ngắn được sử dụng nhiều hơn dưới dạng phát triển biệt lập hơn là một công cụ tổ chức cho các tính năng hoạt động lâu hơn.

Cũng lưu ý rằng Git không nên phàn nàn về git branch -d, vì tính năng mới hiện có thể truy cập được từ nhánh chính.

Trong trường hợp bạn yêu cầu một commit hợp nhất trong quá trình hợp nhất chuyển tiếp nhanh cho mục đích lưu giữ hồ sơ, bạn có thể thực hiện git merge với tùy chọn --no-ff.

git merge --no-ff <branch>

Lệnh này hợp nhất nhánh đã chỉ định vào nhánh hiện tại, nhưng luôn tạo ra một commit hợp nhất (ngay cả khi đó là hợp nhất chuyển tiếp nhanh). Điều này hữu ích để ghi lại tất cả các hợp nhất xảy ra trong kho lưu trữ của bạn.

Hợp nhất 3 chiều

Ví dụ tiếp theo rất giống, nhưng yêu cầu hợp nhất 3 chiều vì main xử lý trong khi tính năng đang được tiến hành. Đây là tình huống phổ biến đối với các tính năng lớn hoặc khi nhiều nhà phát triển đang làm việc đồng thời trên một dự án.

Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the main branch
git checkout main
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to main"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature

Lưu ý rằng Git không thể thực hiện hợp nhất nhanh, vì không có cách nào để di chuyển main lên new-feature mà không quay lui.

Đối với hầu hết các quy trình công việc, new-feature sẽ là một tính năng lớn hơn nhiều và mất nhiều thời gian để phát triển, đó là lý do tại sao các commit mới sẽ xuất hiện trên main trong thời gian chờ đợi. Nếu nhánh tính năng của bạn thực sự nhỏ như nhánh trong ví dụ trên, thì có lẽ tốt hơn hết là bạn nên khởi động lại nó trên main và thực hiện hợp nhất nhanh. Điều này ngăn các commit hợp nhất không cần thiết làm lộn xộn lịch sử dự án.

Giải quyết xung đột

Nếu cả hai nhánh bạn đang cố hợp nhất đều thay đổi cùng một phần của cùng một tệp, Git sẽ không thể tìm ra phiên bản nào sẽ sử dụng. Khi tình huống như vậy xảy ra, nó sẽ dừng ngay trước khi hợp nhất commit để bạn có thể giải quyết xung đột theo cách thủ công.

Phần tuyệt vời của quy trình hợp nhất của Git là nó sử dụng quy trình edit/state/commit quen thuộc để giải quyết xung đột hợp nhất. Khi bạn gặp xung đột hợp nhất, chạy lệnh git status sẽ cho bạn biết tệp nào cần được giải quyết. Ví dụ: nếu cả hai nhánh sửa đổi cùng một phần của hello.py, bạn sẽ thấy nội dung như sau:

On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py

Các xung đột được thể hiện như thế nào

Khi Git gặp xung đột trong quá trình hợp nhất, Git sẽ chỉnh sửa nội dung của các tệp bị ảnh hưởng bằng các chỉ báo trực quan đánh dấu cả hai bên của nội dung xung đột. Những điểm đánh dấu trực quan này là: <<<<<<<, ======= và >>>>>>>. Thật hữu ích khi tìm kiếm một dự án cho các chỉ số này trong quá trình hợp nhất để tìm ra nơi xung đột cần được giải quyết.

here is some content not affected by the conflict
<<<<<<< main
this is conflicted text from main
=======
this is conflicted text from feature branch
>>>>>>> feature branch;

Nói chung, nội dung trước điểm đánh dấu ======= là nhánh nhận và phần sau là nhánh hợp nhất.

Khi bạn đã xác định được các phần xung đột, bạn có thể truy cập và sửa lỗi hợp nhất theo ý thích của mình. Khi bạn đã sẵn sàng hoàn tất quá trình hợp nhất, tất cả những gì bạn phải làm là chạy  git add trên (các) tệp bị xung đột để thông báo cho Git rằng chúng đã được giải quyết. Sau đó, bạn chạy bình thường git commit để tạo commit hợp nhất. Đó chính xác là quy trình giống như thực hiện một ảnh chụp nhanh thông thường, điều đó có nghĩa là các nhà phát triển bình thường dễ dàng quản lý việc hợp nhất của riêng họ.

Lưu ý rằng xung đột hợp nhất sẽ chỉ xảy ra trong trường hợp hợp nhất 3 bên. Không thể có các thay đổi xung đột trong hợp nhất nhanh. 

Tổng kết

Bài viết này là tổng quan về lệnh git merge. Hợp nhất là một quá trình thiết yếu khi làm việc với Git. Chúng ta đã thảo luận về cơ chế bên trong đằng sau việc hợp nhất và sự khác biệt giữa hợp nhất chuyển tiếp nhanh và hợp nhất ba chiều, hợp nhất thực sự. Một số điểm chính là:

  1. Hợp nhất Git kết hợp các chuỗi xác nhận thành một lịch sử xác nhận thống nhất.
  2. Có hai cách chính mà Git sẽ hợp nhất: Fast Forward và Three way
  3. Git có thể tự động hợp nhất các cam kết trừ khi có những thay đổi xung đột trong cả hai chuỗi commit.

Tài liệu này đã tích hợp và tham chiếu các lệnh Git khác như: git branchgit pull và git fetch.

Nguồn: https://www.atlassian.com/git/tutorials/using-branches/git-merge

» Tiếp: Merging so với Rebasing
« Trước: Các bước chuyển từ Perforce sang Git
Khóa học qua video:
Python C# Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!