Blog PostSeptember 22, 2025

Bí kíp luyện Git cơ bản cho người mới (P4): Tầm nhìn của bậc thầy

Bí kíp luyện Git cơ bản cho người mới (P4): Tầm nhìn của bậc thầy

Người bạn đồng hành trên con đường trở thành cao thủ Git

Chào mừng bạn đến với cuộc hành trình chinh phục Git. Nếu bạn đang ở đây, có lẽ bạn đã nghe nói về Git như một công cụ "thần thánh" mà mọi lập trình viên đều phải biết, hoặc có thể bạn đã từng trải qua những đêm dài mất ngủ vì lỡ tay xóa mất file quan trọng hay ghi đè lên công sức của đồng đội. Dù lý do là gì, bạn đã đến đúng nơi.

Cuốn "bí kíp" này không phải là một tài liệu tham khảo khô khan liệt kê hàng trăm câu lệnh. Thay vào đó, nó được viết dưới dạng một câu chuyện, một lộ trình tuyến tính sẽ dẫn dắt bạn đi từng bước, từ việc hiểu được "nỗi đau" mà Git sinh ra để giải quyết, cho đến việc sử dụng thành thạo những kỹ thuật phức tạp nhất. Chúng ta sẽ cùng nhau theo chân một lập trình viên tên Bình, chứng kiến những vấn đề anh gặp phải và khám phá cách Git, với triết lý và công cụ của mình, trở thành người hùng giải quyết những vấn đề đó.

Bạn đang đọc phần 4 của cuốn bí kíp này bao gồm nội dung ở các chương 9 đến 12. Những chương này sẽ cung cấp cho bạn kiến thức để trở thành một chuyên gia Git (thứ mà đứa đang viết script này cũng ao ước làm được). Bạn sẽ được học về các câu lệnh nâng cao, chiến lược phân nhánh, cách viết nội dung commit và góc nhìn về con đường phía trước.

Nếu bạn đang cảm thấy lạ lẫm, hãy quay lại Phần 1 của cuốn bí kíp tại đây.


Chương IX: Công cụ của Bậc thầy - Các Kỹ thuật Nâng cao

Bạn đã nắm vững các quy trình làm việc cơ bản và cộng tác. Bây giờ là lúc trang bị thêm những công cụ tinh xảo hơn, giúp bạn làm việc hiệu quả, gọn gàng và chuyên nghiệp. Phần này sẽ giới thiệu về git stash để tạm cất công việc, git tag để đánh dấu các phiên bản phát hành, và git cherry-pick để chọn lựa những commit riêng lẻ.

1. git stash: Chiếc túi Thần kỳ

Vấn đề

Bình đang làm việc dở dang trên nhánh feature/dragon-powers. Anh đã thay đổi 3 file nhưng chưa sẵn sàng để commit. Bỗng nhiên, một bug khẩn cấp xuất hiện trên main và anh phải chuyển nhánh ngay lập tức để sửa. Nhưng Git không cho phép anh switch nhánh khi đang có những thay đổi chưa được commit trong Working Directory, vì việc chuyển nhánh có thể ghi đè lên những thay đổi đó. Anh không muốn tạo một commit tạm bợ, dở dang chỉ để có thể chuyển nhánh. Anh cần một cách để "tạm cất" công việc của mình đi một cách nhanh chóng, giải quyết việc khẩn cấp, rồi sau đó quay lại và lấy công việc ra làm tiếp.

Giải pháp của Git: git stash

git stash (cất giữ) hoạt động như một chiếc túi thần kỳ. Nó lấy tất cả những thay đổi chưa được commit của bạn (cả trong Working Directory và Staging Area), gói chúng lại và cất vào một nơi an toàn, sau đó trả lại cho bạn một Working Directory sạch sẽ, giống hệt như commit cuối cùng.  

Các lệnh stash phổ biến:

  • git stash hoặc git stash push: Cất những thay đổi hiện tại vào "ngăn xếp" stash.

  • git stash list: Liệt kê tất cả các "gói" thay đổi bạn đã cất đi. Mỗi gói có một định danh như stash@{0}, stash@{1},....  

  • git stash apply [stash@{n}]: Lấy gói thay đổi ra và áp dụng lại vào Working Directory của bạn. Gói đó vẫn được giữ lại trong danh sách stash. Nếu không chỉ định, nó sẽ lấy gói gần nhất (stash@{0}).  

  • git stash pop [stash@{n}]: Tương tự như apply, nhưng sau khi áp dụng thành công, nó sẽ xóa gói đó khỏi danh sách stash.  

  • git stash drop [stash@{n}]: Xóa một gói cụ thể khỏi danh sách stash mà không áp dụng nó.

  • git stash clear: Xóa tất cả các gói trong stash.

Thực hành stash

  1. Chuyển sang một nhánh bất kỳ (ví dụ: git switch -c temp-work).

  2. Sửa 2 file bất kỳ, ví dụ story.txtnotes.txt.

  3. Chạy git status để thấy các thay đổi.

  4. Bây giờ, hãy cất chúng đi: git stash.

  5. Chạy git status lần nữa. Working Directory của bạn đã sạch sẽ! Bây giờ bạn có thể tự do chuyển nhánh.

  6. Giả sử bạn đã sửa xong việc khẩn cấp và quay lại nhánh temp-work.

  7. Lấy lại công việc của bạn: git stash pop.

  8. Các thay đổi trên 2 file đã quay trở lại y như cũ.

2. git tag: Đánh dấu Lịch sử

Vấn đề

Sau nhiều tuần làm việc, dự án của Bình đã đạt đến một cột mốc quan trọng. Anh đã hoàn thành phiên bản 1.0 và muốn đánh dấu chính xác commit này là "Phiên bản 1.0". Anh có thể ghi nhớ mã hash của commit đó, nhưng nó quá dài và khó nhớ (ví dụ f8d3a4c). Anh cần một cách để gán một cái tên thân thiện, có ý nghĩa (như v1.0.0) vào một commit cụ thể để dễ dàng tham chiếu sau này, đặc biệt là cho các bản phát hành (releases).  

Giải pháp của Git: git tag

git tag cho phép bạn tạo ra các "nhãn" cố định trỏ đến các commit cụ thể trong lịch sử. Một tag giống như một cái tên không bao giờ thay đổi cho một commit.  

Có hai loại tag chính:

  1. Lightweight Tag (Tag nhẹ): Giống như một "bookmark" đơn giản. Nó chỉ là một cái tên trỏ đến một commit, không chứa thông tin gì thêm. Thường dùng cho mục đích cá nhân, cục bộ.  

    Bash

    git tag <tên-tag> [mã-hash-commit]
    
  2. Annotated Tag (Tag có chú thích): Đây là một đối tượng đầy đủ trong Git. Nó chứa tên người tạo tag, email, ngày tháng, một thông điệp và có thể được ký bằng GnuPG. Đây là loại tag được khuyến khích sử dụng cho các bản phát hành chính thức vì nó chứa nhiều siêu dữ liệu quan trọng.  

    Bash

    git tag -a <tên-tag> -m "Thông điệp cho tag" [mã-hash-commit]
    
    • -a: Viết tắt của annotated.

    • -m: Thông điệp.

Lưu ý quan trọng: tag không tự động được đẩy lên remote khi bạn git push. Bạn phải đẩy chúng lên một cách tường minh.

  • git push origin <tên-tag>: Đẩy một tag cụ thể lên.

  • git push origin --tags: Đẩy tất cả các tag cục bộ của bạn lên remote.  

Thực hành tag

  1. Đảm bảo bạn đang ở nhánh main.

  2. Dùng git log để tìm commit mà bạn muốn đánh dấu là phiên bản 1.0.

  3. Tạo một annotated tag:

    Bash

    git tag -a v1.0.0 -m "Release version 1.0.0"
    

    (Nếu bạn không chỉ định mã hash, nó sẽ tự động tag commit HEAD hiện tại).

  4. Liệt kê các tag: git tag.

  5. Xem chi tiết của tag: git show v1.0.0. Bạn sẽ thấy thông tin người tạo tag và thông điệp.

  6. Đẩy tag này lên remote: git push origin v1.0.0.

3. git cherry-pick: Nhặt hạt Anh đào

Vấn đề

Bình đang làm việc trên một nhánh feature lớn và đã tạo ra 5 commit. Bất ngờ, anh nhận ra rằng commit thứ 2 trong số 5 commit đó thực chất là một bản vá lỗi quan trọng mà nhánh main cũng đang cần ngay lập tức. Anh không muốn merge toàn bộ nhánh feature vì nó chưa hoàn thiện. Anh chỉ muốn lấy duy nhất commit vá lỗi đó và áp dụng nó vào nhánh main.

Giải pháp của Git: git cherry-pick

git cherry-pick (nhặt hạt anh đào) là một lệnh cho phép bạn chọn một commit bất kỳ từ một nhánh bất kỳ và áp dụng nó lên trên đỉnh của nhánh hiện tại.  

Git sẽ lấy "bản vá" (patch) của commit được chọn (tức là những thay đổi mà commit đó đã tạo ra) và tạo một commit mới với những thay đổi y hệt trên nhánh hiện tại của bạn. Commit mới này sẽ có một mã hash mới.  

Cách hoạt động:

  1. Chuyển sang nhánh bạn muốn nhận commit (ví dụ: main).

  2. Tìm mã hash của commit bạn muốn "nhặt".

  3. Chạy lệnh:

    Bash

    git cherry-pick <mã-hash-commit>
    

Lưu ý: cherry-pick tạo ra các commit trùng lặp về nội dung, điều này có thể làm phức tạp lịch sử nếu lạm dụng. Nó nên được sử dụng trong các trường hợp đặc biệt như áp dụng hotfix cho nhiều nhánh release khác nhau, hoặc cứu vớt một vài commit hữu ích từ một nhánh đã bị hủy bỏ.  

Thực hành cherry-pick

  1. Tạo một nhánh mới: git switch -c feature/multiple-commits.

  2. Tạo 2 commit trên nhánh này:

    • Commit 1: Thêm "Dòng 1" vào notes.txt. Commit với thông điệp "feat: Add line 1".

    • Commit 2: Thêm "Dòng 2 (đây là bug fix)" vào notes.txt. Commit với thông điệp "fix: Add important line 2".

  3. Dùng git log để lấy mã hash của commit "fix".

  4. Chuyển về main: git switch main.

  5. Kiểm tra file notes.txt trên main (nó chưa có 2 dòng mới).

  6. Bây giờ, hãy "nhặt" commit vá lỗi:

    Bash

    git cherry-pick <mã-hash-của-commit-fix>
    
  7. Kiểm tra notes.txt trên main lần nữa. Bây giờ nó đã có "Dòng 2 (đây là bug fix)", nhưng không có "Dòng 1". Bạn đã thành công lấy một commit riêng lẻ mà không cần merge cả nhánh.


Chương X: Lựa chọn Binh pháp - Các Chiến lược Phân nhánh

Sử dụng branch là một chuyện, nhưng sử dụng chúng một cách có tổ chức, nhất quán trong một đội nhóm lại là một chuyện khác. Một chiến lược phân nhánh (branching strategy) là một bộ quy tắc và quy ước mà cả nhóm tuân theo để quản lý các nhánh, đảm bảo quy trình phát triển và phát hành sản phẩm diễn ra một cách mượt mà. Phần này sẽ giới thiệu ba chiến lược phổ biến nhất: Gitflow, GitHub Flow, và Trunk-Based Development.

Vấn đề: Sự Hỗn loạn có Tổ chức

Khi nhóm của Bình phát triển lớn hơn, các vấn đề mới nảy sinh. Mọi người đều tạo nhánh, nhưng không theo một quy tắc nào.

  • Có người đặt tên nhánh là feature-A, người khác là Binh/fix-bug, người khác lại là update-css. Rất khó để biết nhánh nào dùng để làm gì.

  • Khi nào thì nên merge vào main? Một tính năng cần được kiểm thử trước khi ra mắt, vậy nó nên được merge vào đâu để bộ phận kiểm thử (QA) có thể làm việc?

  • Nếu có nhiều phiên bản của sản phẩm đang được hỗ trợ cùng lúc (ví dụ: phiên bản 1.0 và 2.0), làm thế nào để vá một lỗi trên cả hai phiên bản?

Nhóm của Bình cần một "binh pháp", một bộ quy tắc chung để mọi người cùng tuân theo, giúp quản lý sự phức tạp này.

Giải pháp của Git: Các Mô hình Luồng công việc

Không có một chiến lược nào là hoàn hảo cho mọi đội nhóm. Việc lựa chọn phụ thuộc vào nhiều yếu tố như quy mô nhóm, độ phức tạp của dự án, và chu kỳ phát hành sản phẩm.  

1. Gitflow: Binh pháp Cổ điển và Cấu trúc

Gitflow là một trong những chiến lược đầu tiên được phổ biến rộng rãi, được đề xuất bởi Vincent Driessen. Nó rất có cấu trúc và phù hợp cho các dự án có chu kỳ phát hành được lên lịch rõ ràng (ví dụ: mỗi tháng một phiên bản) và cần hỗ trợ nhiều phiên bản cùng lúc.  

Các nhánh chính:

  • main (hoặc master): Luôn luôn ở trạng thái sẵn sàng để phát hành (production-ready). Mỗi commit trên main là một phiên bản mới và được đánh tag.

  • develop: Đây là nhánh tích hợp chính cho các tính năng. Khi một tính năng hoàn thành, nó sẽ được merge vào develop. Nhánh này chứa code mới nhất, đã hoàn thành nhưng có thể chưa được kiểm thử kỹ lưỡng cho việc phát hành.

Các nhánh hỗ trợ:

  • Feature branches (ví dụ: feature/user-login):

    • Tách ra từ: develop.

    • Merge vào: develop.

    • Mục đích: Phát triển các tính năng mới. Chúng không bao giờ tương tác trực tiếp với main.

  • Release branches (ví dụ: release/v1.2.0):

    • Tách ra từ: develop.

    • Merge vào: maindevelop.

    • Mục đích: Chuẩn bị cho một bản phát hành mới. Nhánh này là nơi để thực hiện các chỉnh sửa phút cuối, sửa các bug nhỏ và chuẩn bị metadata cho phiên bản. Không có tính năng mới nào được thêm vào đây.

  • Hotfix branches (ví dụ: hotfix/security-patch):

    • Tách ra từ: main.

    • Merge vào: maindevelop.

    • Mục đích: Sửa các lỗi nghiêm trọng, khẩn cấp trên phiên bản production. Chúng được tách trực tiếp từ main để có thể vá lỗi nhanh nhất mà không cần phải mang theo các tính năng mới từ develop.

Ưu điểm:

  • Cấu trúc rất rõ ràng, phân tách rạch ròi giữa các môi trường.

  • Lý tưởng cho việc quản lý nhiều phiên bản và các chu kỳ phát hành có kế hoạch.

  • Song song hóa công việc rất tốt.

Nhược điểm:

  • Phức tạp, có nhiều loại nhánh cần quản lý. Có thể là quá rườm rà cho các dự án nhỏ hoặc các dự án cần phát hành liên tục.

  • Có thể làm chậm chu kỳ phát hành và không phù hợp với CI/CD (Continuous Integration/Continuous Delivery) hiện đại.  

2. GitHub Flow: Binh pháp Tối giản và Linh hoạt

GitHub Flow là một chiến lược đơn giản hơn nhiều, được thiết kế cho các đội nhóm thực hành Phát hành Liên tục (Continuous Delivery). Nó phù hợp với các ứng dụng web, nơi chỉ có một phiên bản production tại một thời điểm.  

Quy trình:

  1. Nhánh main là nhánh duy nhất chứa code đã được triển khai và luôn ở trạng thái sẵn sàng triển khai.

  2. Để bắt đầu công việc mới (tính năng hoặc sửa lỗi), bạn tạo một feature branch mới từ main. Tên nhánh nên có tính mô tả (ví dụ: add-user-profile-page).

  3. Thực hiện các commit trên nhánh này và push thường xuyên lên remote để chia sẻ tiến độ.

  4. Khi bạn nghĩ rằng công việc đã sẵn sàng, bạn mở một Pull Request (hoặc Merge Request). Đây là một yêu cầu để merge nhánh của bạn vào main.

  5. Pull Request là nơi diễn ra việc thảo luận, code review (đánh giá code), và chạy các bài kiểm thử tự động (CI).

  6. Khi Pull Request được chấp thuận và tất cả các kiểm thử đều qua, nó sẽ được merge vào main.

  7. Ngay sau khi được merge vào main, nó sẽ được triển khai (deploy) ngay lập tức.

Ưu điểm:

  • Rất đơn giản và dễ hiểu.  

  • Lý tưởng cho CI/CD và Phát hành Liên tục.

  • Chu kỳ phản hồi nhanh nhờ vào Pull Request.

Nhược điểm:

  • Không phù hợp cho các dự án cần quản lý nhiều phiên bản phát hành.

  • Đòi hỏi một hệ thống kiểm thử tự động và quy trình CI/CD rất mạnh mẽ, vì mọi thứ merge vào main đều có thể ra production ngay lập tức.  

3. Trunk-Based Development (TBD): Binh pháp Tốc độ và Tích hợp

Trunk-Based Development (TBD) là chiến lược cốt lõi của DevOps và Tích hợp Liên tục (Continuous Integration). Mục tiêu của nó là giảm thiểu số lượng nhánh và thời gian tồn tại của chúng, khuyến khích các nhà phát triển tích hợp công việc của họ vào nhánh chính (trunk, tức là main) một cách thường xuyên.  

Quy trình:

  • Tất cả các nhà phát triển làm việc trên một nhánh duy nhất là main.

  • Thay vì tạo các feature branch sống trong nhiều ngày hoặc nhiều tuần, họ sẽ:

    • (Đối với nhóm nhỏ) Commit trực tiếp lên main.

    • (Đối với nhóm lớn hơn) Tạo các nhánh sống rất ngắn (short-lived branches), thường chỉ tồn tại vài giờ hoặc tối đa một vài ngày, sau đó merge ngay vào main.  

  • Vì các thay đổi được tích hợp liên tục, nguy cơ xảy ra merge conflict lớn được giảm thiểu.

  • Các tính năng chưa hoàn thiện được quản lý bằng Feature Flags (cờ tính năng). Tức là code cho tính năng mới vẫn được merge vào main, nhưng được "tắt" đi bằng một cờ. Chỉ khi nào tính năng hoàn thiện, cờ đó mới được bật lên cho người dùng thấy.  

Ưu điểm:

  • Thúc đẩy Tích hợp Liên tục và CI/CD ở mức độ cao nhất.

  • Giữ cho code luôn ở trạng thái gần với "sẵn sàng phát hành".

  • Giảm thiểu đáng kể merge conflict.

  • Chu kỳ code review nhanh hơn vì các thay đổi rất nhỏ.  

Nhược điểm:

  • Đòi hỏi kỷ luật cao từ đội ngũ phát triển.

  • Phụ thuộc rất nhiều vào một hệ thống kiểm thử tự động toàn diện và mạnh mẽ. Một commit lỗi trên main có thể ảnh hưởng đến cả nhóm.

  • Quản lý Feature Flags có thể trở nên phức tạp.

Tiêu chíGitflowGitHub FlowTrunk-Based Development
Độ phức tạpCaoThấpRất thấp
Nhánh chínhmain, developmainmain (trunk)
Thời gian sống của nhánhDài (feature, release)Trung bình (feature)Rất ngắn (vài giờ/ngày)
Chu kỳ phát hànhTheo lịch trình, chậm hơnLiên tục, nhanhLiên tục, nhanh nhất
Phù hợp vớiDự án lớn, cần hỗ trợ nhiều phiên bảnỨng dụng web, dự án cần CI/CDĐội ngũ có kỷ luật cao, DevOps, CI/CD
Quản lý tính năng chưa hoàn thiệnGiữ trong feature branchGiữ trong feature branchMerge vào main với Feature Flags

Xuất sang Trang tính

Thực hành: Bài tập lựa chọn

Không có bài tập gõ lệnh cho phần này. Thay vào đó, hãy suy nghĩ về các kịch bản sau và chọn chiến lược phân nhánh phù hợp nhất, giải thích tại sao.

  • Kịch bản 1: Bạn đang xây dựng một phần mềm desktop (ví dụ: một trình sửa ảnh) cho Windows và macOS. Bạn cần phát hành các phiên bản lớn (v1.0, v1.1, v2.0) và sau khi phát hành, bạn vẫn cần vá các lỗi bảo mật cho các phiên bản cũ hơn.

  • Kịch bản 2: Bạn là một phần của một startup 5 người, đang xây dựng một trang web thương mại điện tử. Mục tiêu của các bạn là đưa các tính năng mới đến tay người dùng nhanh nhất có thể, có thể là nhiều lần trong một ngày.

  • Kịch bản 3: Bạn làm việc trong một công ty công nghệ lớn với hàng trăm lập trình viên cùng làm việc trên một sản phẩm duy nhất. Công ty có văn hóa DevOps rất mạnh và yêu cầu mọi commit đều phải qua một hệ thống kiểm thử tự động khổng lồ trước khi được tích hợp.

Suy nghĩ về các kịch bản này sẽ giúp bạn hiểu sâu hơn về ưu và nhược điểm của từng chiến lược và cách áp dụng chúng vào thực tế.


Chương XI: Viết nên Sử thi - Cách viết Commit Message Tốt

Một commit không chỉ là một snapshot của code, nó còn là một đơn vị giao tiếp. Một thông điệp commit (commit message) tốt có thể giúp đồng đội (và chính bạn trong tương lai) hiểu được bối cảnh của sự thay đổi mà không cần phải đọc từng dòng code. Phần này sẽ cung cấp các quy tắc và thực hành tốt nhất để viết những commit message rõ ràng, súc tích và hữu ích, biến lịch sử Git của bạn từ một mớ hỗn độn thành một cuốn sử thi dễ đọc.

Vấn đề: Những Thông điệp Vô nghĩa

Hãy xem lịch sử commit của Bình trong những ngày đầu:

  • commit f7a5d3e: fix bug

  • commit 9e2b1c8: update

  • commit 3d4c5a6: changes

  • commit a1b2c3d: wip (Work in progress)

Khi một lỗi mới xuất hiện, Bình nhìn lại lịch sử này và hoàn toàn không có manh mối. fix bug đã sửa lỗi gì? update đã cập nhật cái gì và tại sao? Những thông điệp này không cung cấp bất kỳ giá trị nào. Chúng buộc người đọc phải tự mình phân tích toàn bộ các thay đổi trong commit để hiểu chuyện gì đã xảy ra. Đây là một sự lãng phí thời gian và làm giảm giá trị của việc sử dụng Git.  

Giải pháp: Cấu trúc và Quy ước

Một commit message tốt nên trả lời hai câu hỏi chính: cái gì đã được thay đổi và tại sao nó lại được thay đổi. "Làm thế nào" nó được thay đổi đã có trong code rồi.  

Cấu trúc 3 phần của một Commit Message

Một commit message chuẩn thường có 3 phần, được phân tách bởi các dòng trống :  

  1. Header (Tiêu đề): Dòng đầu tiên, bắt buộc.

  2. Body (Thân): Tùy chọn, giải thích chi tiết hơn.

  3. Footer (Chân trang): Tùy chọn, chứa các metadata.

<type>(<scope>): <subject>
<-- Dòng trống -->
[Optional body]
<-- Dòng trống -->
[Optional footer]

Các quy tắc vàng để viết Commit Message

Dựa trên kinh nghiệm của cộng đồng, đây là 7 quy tắc quan trọng nhất :  

  1. Phân tách Tiêu đề và Thân bằng một dòng trống: Git và nhiều công cụ khác sử dụng dòng đầu tiên làm tiêu đề tóm tắt. Dòng trống là cần thiết để chúng nhận diện đúng đâu là tiêu đề, đâu là thân.

  2. Giới hạn Tiêu đề trong 50 ký tự: Điều này giúp tiêu đề ngắn gọn, dễ đọc khi hiển thị trong git log --oneline hoặc trên giao diện GitHub. Nó cũng buộc bạn phải suy nghĩ về cách tóm tắt thay đổi một cách súc tích nhất.  

  3. Viết hoa chữ cái đầu của Tiêu đề: Ví dụ: Fix thay vì fix. Đây là một quy ước về phong cách.

  4. Không kết thúc Tiêu đề bằng dấu chấm: Tiêu đề được coi là một tiêu đề, không phải một câu hoàn chỉnh.

  5. Sử dụng Thể mệnh lệnh (Imperative Mood) trong Tiêu đề: Hãy viết như thể bạn đang ra lệnh cho codebase. Ví dụ: "Add feature" thay vì "Added feature" hay "Adds feature". Lệnh này nhất quán với các thông điệp do chính Git tạo ra (ví dụ: "Merge branch '...'").

  6. Ngắt dòng trong Thân ở 72 ký tự: Điều này giúp thông điệp dễ đọc trong terminal mà không cần cuộn ngang.

  7. Sử dụng Thân để giải thích "Cái gì" và "Tại sao", không phải "Làm thế nào": Giải thích vấn đề mà commit này giải quyết. Mô tả bối cảnh và lý do đằng sau sự thay đổi.

Ví dụ về một commit message TỆ:

fix bug

Ví dụ về một commit message TỐT:

fix: Prevent user from submitting form with invalid email

The form was previously allowing submission even if the email
field did not contain a valid email address format. This could
lead to invalid data in the user database.

This commit adds client-side validation using a regular expression
to check the email format before enabling the submit button.

Fixes: #42

Quy ước Conventional Commits

Để đi một bước xa hơn trong việc chuẩn hóa, cộng đồng đã tạo ra một quy ước gọi là Conventional Commits. Nó đề xuất một cấu trúc chặt chẽ cho tiêu đề, giúp con người và máy móc dễ dàng hiểu được ý nghĩa của một commit.  

Cấu trúc Tiêu đề: <type>[optional scope]: <description>

  • type: Cho biết loại thay đổi. Một số type phổ biến:

    • feat: Một tính năng mới (tương ứng với phiên bản MINOR trong Semantic Versioning).

    • fix: Sửa một lỗi (tương ứng với phiên bản PATCH).

    • docs: Chỉ thay đổi tài liệu.

    • style: Thay đổi về định dạng code (tab, khoảng trắng,...) không ảnh hưởng đến logic.

    • refactor: Viết lại code mà không sửa lỗi hay thêm tính năng.

    • perf: Cải thiện hiệu năng.

    • test: Thêm hoặc sửa các bài kiểm thử.

    • chore: Các công việc khác không ảnh hưởng đến code sản phẩm (ví dụ: cập nhật công cụ build).

  • scope (tùy chọn): Một danh từ đặt trong ngoặc đơn, chỉ định phần nào của codebase bị ảnh hưởng (ví dụ: api, auth, ui).

  • description: Mô tả ngắn gọn về thay đổi, bắt đầu bằng một động từ ở thể mệnh lệnh.

BREAKING CHANGE: Nếu một commit tạo ra một thay đổi lớn, phá vỡ tính tương thích ngược, nó phải được chỉ định rõ ràng bằng cách thêm dấu ! sau type(scope) hoặc thêm một dòng BREAKING CHANGE: ở footer.  

Tại sao nên dùng Conventional Commits?

  • Tự động tạo Changelog: Các công cụ có thể tự động đọc lịch sử commit và tạo ra một bản ghi các thay đổi (changelog) cho mỗi phiên bản mới.

  • Tự động xác định phiên bản: Dựa vào các type (fix, feat, BREAKING CHANGE), hệ thống có thể tự động quyết định sẽ tăng phiên bản theo quy tắc Semantic Versioning (ví dụ: từ 1.2.5 lên 1.2.6 nếu chỉ có fix, hoặc lên 1.3.0 nếu có feat).

  • Cải thiện giao tiếp: Giúp mọi người trong nhóm nhanh chóng hiểu được bản chất của các thay đổi mà không cần xem chi tiết.

Thực hành: Viết lại Lịch sử (một cách tốt hơn)

Hãy tưởng tượng bạn vừa thực hiện 3 thay đổi sau trên nhánh của mình:

  1. Thêm một nút đăng nhập vào thanh điều hướng.

  2. Sửa một lỗi hiển thị trên mobile khiến logo bị lệch.

  3. Cập nhật phiên bản của một thư viện trong file package.json.

Nhiệm vụ: Viết 3 commit message riêng biệt cho 3 thay đổi này theo quy ước Conventional Commits.

Gợi ý:

  • Thay đổi 1 là một tính năng mới, có thể thuộc scopeheader hoặc nav.

  • Thay đổi 2 là một bản vá lỗi, có thể thuộc scopeui hoặc header.

  • Thay đổi 3 là một công việc "lặt vặt" (chore), không ảnh hưởng trực tiếp đến code người dùng.

Ví dụ về các commit message có thể viết:

  • Commit 1: feat(header): Add login button to navigation bar

  • Commit 2: fix(ui): Correct logo alignment on mobile viewports

  • Commit 3: chore: Bump analytics library to version 3.2.0

Hãy tập thói quen suy nghĩ về thông điệp commit trước khi bạn gõ lệnh git commit. Một vài giây suy nghĩ có thể tiết kiệm hàng giờ cho bạn và đồng đội trong tương lai.


Chương XII: Con đường Phía trước - Tiếp tục Rèn luyện

Bạn đã đi một chặng đường dài và nắm vững những kiến thức cốt lõi cũng như các kỹ thuật nâng cao của Git. Cuộc hành trình trở thành một cao thủ Git không kết thúc ở đây; nó là một quá trình rèn luyện và áp dụng liên tục. Phần cuối cùng này sẽ cung cấp cho bạn những nguồn tài nguyên và định hướng để tiếp tục mài giũa kỹ năng của mình, từ việc thực hành trong môi trường tương tác đến việc đóng góp cho các dự án mã nguồn mở thực tế.

Vấn đề: Từ Lý thuyết đến Thực chiến

Việc đọc và làm theo các bài hướng dẫn là một bước khởi đầu tuyệt vời. Tuy nhiên, để thực sự biến kiến thức thành kỹ năng, bạn cần phải thực hành trong các kịch bản đa dạng và đôi khi là hỗn loạn của thế giới thực.

  • Làm thế nào để thực hành các lệnh Git phức tạp mà không sợ làm hỏng dự án thật?

  • Làm thế nào để áp dụng những gì đã học vào một quy trình làm việc nhóm thực sự?

  • Sau khi đã tự tin, đâu là nơi để bạn thử sức và tạo ra những đóng góp có ý nghĩa?

Giải pháp: Sân chơi An toàn và Thử thách Thực tế

1. Sân chơi Tương tác: Luyện tập không Rủi ro

Có rất nhiều công cụ trực tuyến tuyệt vời cho phép bạn thực hành Git trong một môi trường giả lập, trực quan và an toàn. Đây là nơi bạn có thể thử nghiệm những lệnh "nguy hiểm" như rebase hay giải quyết conflict mà không lo lắng.

  • Learn Git Branching: Đây là công cụ được đánh giá cao nhất và hiệu quả nhất để học về phân nhánh, hợp nhất và rebase. Nó cung cấp các thử thách tương tác, nơi bạn phải gõ các lệnh Git để làm cho cây lịch sử của bạn khớp với một mục tiêu cho trước. Nó trực quan hóa các nhánh và commit, giúp bạn hiểu sâu sắc về cách các lệnh hoạt động "dưới mui xe".  

  • Oh My Git!: Một trò chơi mã nguồn mở để học Git. Nó sử dụng một giao diện thẻ bài độc đáo để biểu diễn các lệnh, giúp người mới bắt đầu dễ dàng ghi nhớ. Khi bạn tiến bộ, game sẽ mở khóa một terminal tích hợp để bạn thử các lệnh nâng cao hơn.  

  • GitHub Skills: GitHub cung cấp các khóa học tương tác miễn phí ngay trên nền tảng của họ. Bạn sẽ được một con bot hướng dẫn thực hiện các quy trình làm việc thực tế như tạo Pull Request, giải quyết merge conflict, và sử dụng GitHub Actions, tất cả đều diễn ra trong một kho chứa thật.  

2. Đóng góp cho Mã nguồn Mở: Thử thách Đầu tiên

Cách tốt nhất để học là làm. Đóng góp cho các dự án mã nguồn mở (Open Source) là một cách tuyệt vời để áp dụng kỹ năng Git của bạn vào thực tế, làm việc với các quy trình chuyên nghiệp, và xây dựng portfolio của bạn.

Nhưng làm thế nào để bắt đầu khi có hàng triệu dự án ngoài kia?

  • Tìm kiếm các "Good First Issue": Nhiều dự án lớn trên GitHub có một nhãn đặc biệt cho các vấn đề (issues) mà họ cho là phù hợp với người mới bắt đầu. Những vấn đề này thường được mô tả rõ ràng và không đòi hỏi kiến thức sâu về toàn bộ codebase.

    • Bạn có thể tìm kiếm trực tiếp trên GitHub với truy vấn: is:issue is:open label:"good first issue".  

    • Sử dụng các trang web tổng hợp như Good First Issue hoặc(https://github.com/MunGell/awesome-for-beginners) để khám phá các dự án thân thiện với người mới bắt đầu thuộc nhiều ngôn ngữ lập trình khác nhau.  

Quy trình đóng góp đầu tiên của bạn có thể trông như sau:

  1. Tìm một "good first issue" mà bạn hứng thú.

  2. Đọc kỹ mô tả và các quy tắc đóng góp của dự án (thường trong file CONTRIBUTING.md).

  3. Để lại một bình luận trên issue đó, bày tỏ ý định muốn làm việc trên nó.

  4. Fork kho chứa của dự án về tài khoản GitHub của bạn. (Fork là tạo một bản sao của dự án mà bạn có toàn quyền).

  5. Clone kho chứa bạn vừa fork về máy tính.

  6. Tạo một nhánh mới cho thay đổi của bạn.

  7. Thực hiện các thay đổi, viết code, và tạo ra các commit với thông điệp rõ ràng.

  8. Push nhánh của bạn lên kho chứa đã fork trên GitHub.

  9. Tạo một Pull Request từ nhánh của bạn trên kho chứa đã fork đến nhánh main của dự án gốc.

  10. Chờ đợi phản hồi, thảo luận và có thể thực hiện thêm các thay đổi theo yêu cầu của người bảo trì dự án.

  11. Khi Pull Request của bạn được merge, xin chúc mừng! Bạn đã chính thức trở thành một người đóng góp cho mã nguồn mở.

Lời kết

Bạn đã đến cuối cuộc hành trình trong cuốn "Bí kíp Luyện Git". Xin chúc mừng! Bạn đã đi một chặng đường dài, từ việc thấu hiểu "nỗi đau" của việc quản lý file thủ công, cho đến việc tự tin sử dụng những công cụ mạnh mẽ và tinh vi nhất.

Bạn không chỉ học các câu lệnh, bạn đã học một tư duy, một phương pháp làm việc chuyên nghiệp. Bạn đã biết cách bảo vệ công việc của mình bằng các commit, khám phá những ý tưởng mới một cách an toàn với branch, cộng tác hiệu quả với remote, và sửa chữa mọi sai lầm với revertreset. Bạn đã học cách giao tiếp với đồng đội qua những commit message ý nghĩa và lựa chọn "binh pháp" phù hợp cho đội nhóm của mình.

Git là một công cụ sâu sắc và mạnh mẽ. Luôn có những điều mới để học hỏi. Nhưng với nền tảng vững chắc mà bạn đã xây dựng, bạn đã sẵn sàng đối mặt với bất kỳ thử thách nào trong quản lý mã nguồn. Con đường trở thành cao thủ Git chính là con đường của sự rèn luyện không ngừng.

Hãy tiếp tục thực hành, luôn tò mò, và đừng bao giờ ngại hỏi. Chúc bạn may mắn trên hành trình của mình và viết nên những "sử thi" mã nguồn của riêng bạn!

End of Article

Thank you for reading!