Cách giải quyết xung đột trong Git

Điều mà mọi nhà phát triển đều ghét phải nhìn thấy khi merge code đó là: xung đột. Không có cách nào để tự động giải quyết các xung đột hợp nhất khi làm việc với Git (hoặc các hệ thống kiểm soát phiên bản khác).

Nhưng khi nói chuyện với các nhà phát triển, tôi thường nghe rằng có cảm giác lo lắng hoặc khó chịu xung quanh chủ đề xung đột khi merge code này.

Xử lý xung đột thường vẫn là một nơi bí ẩn, tăm tối: một tình huống mà mọi thứ đang bị phá vỡ một cách tồi tệ và không rõ làm cách nào để thoát ra khỏi nó (mà không làm cho mọi thứ trở nên tồi tệ hơn).

Mặc dù đúng là xung đột hợp nhất (merge conflict) là một phần không thể tránh khỏi trong cuộc sống của một nhà phát triển, nhưng sự khó chịu trong những tình huống này là hoàn toàn tùy chọn.

Mục đích của tôi với bài viết này là mang lại sự rõ ràng cho chủ đề này: làm thế nào và khi nào các xung đột thường xảy ra, chúng ta sẽ thực sự làm gì để giải quyết chúng.

Khi bạn hiểu đúng những điều này, bạn sẽ có thể giải quyết các xung đột hợp nhất một cách thoải mái và tự tin hơn nhiều.

Xung đột xảy ra như thế nào và khi nào

Cái tên đã nói lên điều đó: "xung đột hợp nhất" có thể xảy ra trong quá trình tích hợp các commit từ một nguồn khác.

Tuy nhiên, hãy nhớ rằng "tích hợp" không chỉ giới hạn ở "hợp nhất các nhánh". Nó cũng có thể xảy ra khi phục hồi hoặc phục hồi tương tác, khi thực hiện một cherry-pick hoặc pull, hoặc thậm chí khi áp dụng lại một Stash.

Tất cả các hành động này thực hiện một số loại tích hợp - và đó là khi xung đột hợp nhất có thể xảy ra.

Merge conflict trong Git
Merge conflict trong Git

Nhưng tất nhiên, những hành động này không dẫn đến xung đột hợp nhất mọi lúc. Tốt nhất, bạn chỉ nên thấy mình hiếm khi rơi vào những tình huống này. Nhưng chính xác thì xung đột xảy ra khi nào?

Trên thực tế, khả năng hợp nhất của Git là một trong những lợi thế lớn nhất của nó: việc hợp nhất các nhánh hoạt động dễ dàng hầu như mọi lúc, bởi vì Git thường có thể tự tìm ra và giải quyết mọi thứ.

Nhưng có những tình huống xảy ra những thay đổi trái ngược nhau - và nơi công nghệ không thể quyết định điều gì là đúng hay sai. Những tình huống này chỉ cần một quyết định từ con người.

Điều cổ điển thực sự là khi cùng một dòng mã được thay đổi trong hai lần commit, trên hai nhánh khác nhau. Git không có cách nào để biết bạn thích thay đổi nào!

Có một số tình huống tương tự khác - ví dụ như khi một tệp được sửa đổi trong một nhánh và bị xóa trong một nhánh khác - nhưng chúng ít phổ biến hơn một chút.

Làm thế nào để biết khi nào xung đột xảy ra

Đừng lo lắng: Git sẽ cho bạn biết rất rõ ràng khi xung đột đã xảy ra.

Đầu tiên, nó sẽ cho bạn biết ngay lập tức khi xảy ra tình huống này, chẳng hạn như khi merge hoặc rebase không thành công do xung đột:

$ git merge develop
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
CONFLICT (modify/delete): error.html deleted in HEAD and modified in develop. Version develop of error.html left in tree.
Automatic merge failed; fix conflicts and then commit the result.

Như bạn có thể thấy từ ví dụ trên, khi tôi cố gắng thực hiện hợp nhất, tôi đã tạo ra xung đột hợp nhất - và Git thông báo vấn đề rất rõ ràng và kịp thời:

  • Đã xảy ra xung đột trong tệp "index.html".
  • Một xung đột khác trong tệp "error.html" đã xảy ra.
  • Và cuối cùng, do xung đột, hoạt động hợp nhất không thành công.

Đây là những tình huống mà chúng ta phải đào sâu vào mã và xem những gì phải làm.

Trong trường hợp không chắc rằng bạn đã bỏ qua những thông báo cảnh báo này khi xung đột xảy ra, Git cũng sẽ thông báo cho bạn bất cứ khi nào bạn chạy git status:

$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	deleted by us:   error.html
	both modified:   index.html

Nói cách khác: đừng lo lắng về việc không nhận thấy xung đột hợp nhất. Git đảm bảo rằng bạn không thể bỏ qua chúng.

Cách hoàn tác xung đột trong Git và bắt đầu lại

Xung đột hợp nhất đi kèm với một không khí khẩn trương nhất định. Và đúng như vậy: bạn sẽ phải giải quyết chúng trước khi bạn có thể tiếp tục công việc của mình.

Nhưng mặc dù bỏ qua chúng không phải là một lựa chọn, "giải quyết xung đột hợp nhất" không nhất thiết có nghĩa là bạn phải giải quyết chúng. Bạn cũng có thể hoàn tác chúng!

Điều này có thể đáng để lặp lại: bạn luôn có tùy chọn để hoàn tác xung đột hợp nhất và quay lại trạng thái trước đó. Điều này đúng ngay cả khi bạn đã bắt đầu giải quyết các tệp xung đột và thấy mình đang đi vào ngõ cụt.

Trong những tình huống này, bạn nên nhớ rằng bạn luôn có thể bắt đầu lại và trở về trạng thái trong sạch trước khi xung đột xảy ra.

Với mục đích này, hầu hết các lệnh đi kèm với một tùy chọn --abort, ví dụ git merge --abortgit rebase --abort:

$ git merge --abort
$ git status
On branch main
nothing to commit, working tree clean

Điều này sẽ cung cấp cho bạn sự tự tin rằng bạn thực sự không thể lộn xộn. Bạn luôn có thể hủy bỏ, trở lại trạng thái sạch sẽ và bắt đầu lại.

Xung đột thực sự trông như thế nào trong Git

Bây giờ, hãy xem xung đột thực sự trông như thế nào dưới code. Điều này sẽ làm sáng tỏ những người gây ra lỗi nhỏ đó, đồng thời, giúp bạn mất đi sự tôn trọng đối với họ và tự tin vào bản thân.

Ví dụ: hãy xem nội dung của tệp "index.html" (hiện đang bị xung đột) trong trình chỉnh sửa:

Git đủ tốt để đánh dấu khu vực có vấn đề trong tệp, bao quanh nó bằng <<<<<<< HEAD>>>>>>> [other/branch/name]. Nội dung xuất phát sau điểm đánh dấu đầu tiên bắt nguồn từ nhánh làm việc hiện tại của chúng ta. Cuối cùng, một dòng với các ký tự ======= phân tách hai thay đổi trái ngược nhau.

Cách giải quyết xung đột trong Git

Công việc của chúng ta với tư cách là nhà phát triển bây giờ là làm sạch những dòng này: sau khi chúng ta hoàn thành, tệp phải trông chính xác như chúng ta muốn.

Có thể cần phải nói chuyện với đồng đội đã viết các thay đổi "khác" và quyết định mã nào thực sự chính xác. Có thể là của chúng ta, có thể là của họ - hoặc có thể là sự pha trộn giữa hai thứ.

Quá trình này - dọn dẹp tệp và đảm bảo rằng nó chứa những gì chúng ta thực sự muốn - không liên quan đến bất kỳ phép thuật nào. Bạn có thể thực hiện việc này đơn giản bằng cách mở trình soạn thảo văn bản hoặc IDE và bắt đầu thực hiện các thay đổi của mình.

Sau khi dọn dẹp tệp - theo cách thủ công hoặc trong Git GUI hoặc Công cụ hợp nhất - chúng ta phải commit điều này giống như bất kỳ thay đổi nào khác:

  • Bằng cách sử dụng lệnh git add <filename> trên tệp bị xung đột (trước đó), chúng ta thông báo cho Git rằng xung đột đã được giải quyết.
  • Khi tất cả các xung đột đã được giải quyết và được thêm vào vùng tổ chức, bạn cần hoàn thành việc giải quyết bằng cách tạo một commit thường xuyên.

Có thể giảm thiểu xung đột bằng cách các thành viên trong nhóm tránh làm việc trên cùng một branch. Thay vào đó mỗi người nên có branch riêng cho từng tính năng của hệ thống.

Bạn có thể tham khảo thêm ở hướng dẫn làm việc hiệu quả với branch ở bài viết sau:

Sử dụng branch hiệu quả trong Git
Trong bài viết này, tôi sẽ giới thiệu với bạn mô hình sử dụng Git hiệu quả mà tôi đã và đang sử dụng trong các dự án nhiều năm trở lại đây.

Ngoài ra, các thành viên trong team nên hạn chế làm cùng một chức năng. Nếu chức năng lớn thì chia nhỏ ra và mỗi người tạo một branch cho các chức năng nhỏ này.

Việc gặp xung đột khi merge code là điều không thể tránh khỏi. Qua bài viết này mình hi vọng sẽ giúp các bạn hạn chế xảy ra các xung đột và giải quyết xung đột nếu có một cách dễ dàng nhất.

Git
Bài Viết Liên Quan:
Git Cheat Sheet - 50 lệnh Git bạn nên biết
Trung Nguyen 26/03/2021
Git Cheat Sheet - 50 lệnh Git bạn nên biết

Git có nhiều lệnh khác nhau mà bạn có thể sử dụng. Hướng dẫn này giới thiệu với bạn 50 lệnh Git được mọi người sử dụng thường xuyên nhất.

Sử dụng branch hiệu quả trong Git
Trung Nguyen 25/03/2021
Sử dụng branch hiệu quả trong Git

Trong bài viết này, tôi sẽ giới thiệu với bạn mô hình sử dụng Git hiệu quả mà tôi đã và đang sử dụng trong các dự án nhiều năm trở lại đây.

Git là gì? Hướng dẫn cho Người mới bắt đầu về Git
Trung Nguyen 25/03/2021
Git là gì? Hướng dẫn cho Người mới bắt đầu về Git

Git là một hệ thống kiểm soát phiên bản (version control) mà các nhà phát triển sử dụng trên toàn thế giới.