1. Nhánh là gì và tại sao cần chúng?
Làm việc với branches trong Git — là một trong những khía cạnh then chốt của quản lý phiên bản, cho phép duy trì nhiều dòng phát triển song song trong cùng một repository. Branching làm cho Git trở thành một công cụ mạnh mẽ cho cộng tác, thử nghiệm và quản lý các phiên bản khác nhau của dự án.
gitGraph
commit id: "Initial setup"
commit id: "Add base features"
branch feature/new-idea
checkout feature/new-idea
commit id: "Implement new logic"
commit id: "Refactor the logic"
checkout main
commit id: "Urgent bugfix on main"
merge feature/new-idea
commit id: "Prepare for release"
main tách ra một nhánh mới,
feature/new-idea, để phát triển an toàn. Sau khi hoàn thành công việc nó được merge lại vào
main.
Hãy tưởng tượng bạn muốn chỉnh sửa lớn trong dự án hoặc thực hiện một thử nghiệm rủi ro. Nếu không có Git bạn sẽ làm thế nào? Có lẽ sẽ copy toàn bộ dự án vào thư mục mới và làm việc ở đó. Nếu kết quả tốt — chuyển vào thư mục chính. Nếu không — xóa bản copy.
Nhánh trong Git hoạt động theo cùng nguyên lý đó nhưng thanh lịch hơn nhiều. Hãy xem ví dụ viết một cuốn sách:
- Bạn có một bản thảo hoàn chỉnh (đó là nhánh chính của bạn
main). - Bạn muốn viết một kết thúc thay thế (tạo nhánh mới, ví dụ
feature/new-idea). - Bạn viết kết thúc mới mà không ảnh hưởng đến văn bản chính (làm việc trong nhánh mới).
- Nếu kết thúc mới hay hơn, bạn thay thế kết thúc cũ bằng nó (thực hiện merge nhánh —
merge). - Bản thảo cũ với kết thúc không cần thiết có thể bị xóa (xóa nhánh).
2. Tạo nhánh mới và làm việc trên đó
Bước 1. Mở menu quản lý nhánh.
Ở thanh trên cùng của IDE có widget hiển thị tên nhánh hiện tại (mặc định — main). Nhấp vào nó và chọn + New Branch.
Bước 2. Tên nhánh mới.
Tốt nhất là đặt tên nhánh theo nhiệm vụ bạn làm. Ví dụ feature/add-usage-examples.
Sau khi tạo nhánh IDE sẽ tự động chuyển sang nhánh đó. Bạn sẽ thấy tên mới ở cùng widget.
Bước 3. Thực hiện thay đổi và commit.
Bây giờ bạn đang ở trong "sandbox" của mình. Hãy thêm một phần mới với ví dụ sử dụng vào file README.md. Thực hiện thay đổi và làm commit, như bạn đã học ở bài trước.
3. Chuyển đổi giữa các nhánh
Các thay đổi với ví dụ sử dụng giờ được lưu an toàn trong nhánh feature/add-usage-examples. Hãy quay về nhánh chính main và xem ở đó có gì.
Bước 1. Nhấp lại vào widget tên nhánh hiện tại.
Bước 2. Trong danh sách Local hoặc Recent chọn nhánh main, và trong menu phụ xuất hiện nhấn Checkout.
Bước 3. Kiểm tra kết quả.
Sau khi chuyển, mở file README.md. Bạn sẽ thấy phần ví dụ sử dụng không có ở đây! Nó ở nhánh khác. Như vậy bạn có thể phát triển tính năng mới mà không ảnh hưởng đến phiên bản ổn định trong nhánh main.
4. Merge nhánh
Lệnh merge lấy tất cả commit từ nhánh feature/add-examples (ở đây là commit C3) và kết hợp chúng vào nhánh hiện tại main, tạo ra một commit merge mới.
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/add-examples
checkout feature/add-examples
commit id: "C3: Add new section"
checkout main
merge feature/add-examples
Vậy là bạn hoàn thành công việc trong nhánh feature/add-usage-examples và muốn thêm những thay đổi đó vào dự án chính.
Bước 1. Chuyển sang nhánh đích.
Đảm bảo bạn đang ở nhánh mà bạn muốn THÊM các thay đổi vào. Ở ví dụ này là main.
Bước 2. Thực hiện merge.
Nhấp lại vào widget quản lý nhánh. Trong danh sách chọn nhánh mà bạn muốn lấy thay đổi từ đó (feature/add-usage-examples), và trong menu phụ chọn Merge feature/add-usage-examples vào main.
Bước 3. Kiểm tra kết quả.
Bây giờ trong file README.md ở nhánh main đã xuất hiện phần ví dụ của bạn. Bạn đã merge thành công công việc của mình vào phiên bản chính của dự án!
5. Xung đột khi merge: đừng sợ, điều đó bình thường!
Đôi khi khi merge nhánh sẽ xảy ra xung đột. Điều này xảy ra khi cả hai nhánh đều chỉnh sửa cùng những dòng trong cùng một file. Git không thể tự quyết định phiên bản nào đúng và cần sự trợ giúp của bạn.
gitGraph
commit id: "C1: Common baseа"
branch feature/new-title
checkout main
commit id: "C2: Change in main"
checkout feature/new-title
commit id: "C3: Change in feature"
main và
feature/new-title, có các commit mới (C2 và C3) dựa trên cùng một tổ tiên chung (C1). Điều này chắc chắn sẽ dẫn đến xung đột khi merge.
Hãy mô phỏng xung đột:
- Đảm bảo bạn đang ở nhánh
mainvà không có thay đổi chưa lưu. - Tạo ngay một nhánh mới
feature/new-title, nhưng chưa chuyển sang nó. Đảm bảo tích Checkout branch bị bỏ. - Bây giờ, đang ở nhánh
main, thay đổi dòng đầu tiên trongREADME.mdthành "My Awesome Project" và làmcommit. - Chuyển sang nhánh
feature/new-title. Bạn sẽ thấy dòng đầu tiên trongREADME.mdvẫn là bản cũ: đó là trạng thái file khi tạo nhánh. Thay cùng một dòng này thành "My Super Project" và làmcommit. - Quay về nhánh
mainvà thực hiện merge vớifeature/new-title.
Bây giờ Git sẽ thấy rằng cả hai nhánh đều có lịch sử mới, tách ra từ tổ tiên chung. Cùng một dòng bị thay đổi trong cả hai lịch sử, nên Git không thể chọn phiên bản nào đúng và sẽ hiển thị cửa sổ để bạn giải quyết xung đột.
Merge Revision
Bạn thấy gì ở đây:
- Bên trái (Your changes): phiên bản file từ nhánh hiện tại của bạn (
main). - Bên phải (Changes from branch...): phiên bản file từ nhánh mà bạn đang merge.
- Ở giữa (Result): phiên bản cuối cùng của file mà bạn phải ghép lại.
Bạn có thể nhấn vào các mũi tên >> hoặc << để chấp nhận hoàn toàn phiên bản này hay phiên bản kia.
Khi kết quả ở bảng giữa làm bạn hài lòng, nhấn Apply. IDE sẽ tự tạo commit merge và xung đột sẽ được giải quyết.
Tại sao lại không có xung đột?
Có thể xảy ra trường hợp bạn làm đúng các bước nhưng không có xung đột. Thông thường điều này do Git có thể thực hiện fast-forward merge, vì lịch sử của một nhánh đơn giản chỉ tiếp nối lịch sử của nhánh kia. Để chắc chắn có xung đột, lịch sử của các nhánh phải tách ra theo các hướng khác nhau từ tổ tiên chung.
Ví dụ:
- Bạn có một commit nào đó trên
main(giả sử C1). - Bạn làm commit mới trên
mainvới nội dung "My Awesome Project". Nhánhmaingiờ trỏ tới commit C2 (main -> C1 -> C2). - Bạn tạo nhánh
feature/new-titletừ vị trí hiện tại của main. Nghĩa là nhánh mới cũng bắt đầu từ commit C2. - Bạn làm commit trên
feature/new-titlevới nội dung "My Super Project". Nhánh này "chạy trước" và giờ trỏ tới commit C3 (feature/new-title -> C1 -> C2 -> C3). - Bạn quay về
main(vẫn ở commit C2) và yêu cầu merge feature/new-title.
Git nhìn vào tình huống và thấy rằng nhánh main là tổ tiên trực tiếp của nhánh feature/new-title. Trong lịch sử main không có commit mới nào trong khi bạn làm việc ở nhánh khác. Git nghĩ: "À, ở đây chỉ cần tua main tới commit C3. Không có xung đột." Và nó chỉ di chuyển con trỏ main tới commit C3.
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/new-title
checkout feature/new-title
commit id: "C3"
checkout main
merge feature/new-title
6. Xem lịch sử thay đổi
Để hiểu rõ hơn chuyện gì đang xảy ra trong dự án của bạn, hữu ích khi nhìn vào lịch sử của nó.
Mở tab Git ở phần dưới cùng của IDE và chọn Log. Bạn sẽ thấy biểu diễn đồ họa của tất cả các nhánh và commit. Điều này giúp theo dõi trực quan nhánh nào tách ra từ nhánh nào và nơi chúng đã được merge.
Ở đây bạn có thể click vào bất kỳ commit nào để xem những thay đổi đã vào commit đó, ai và khi nào làm. Đây thực sự là cỗ máy thời gian cho code!
GO TO FULL VERSION