Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn vừa được nhận vào một công ty công nghệ ở TP.HCM. Ngày đầu tiên, mentor đưa cho bạn một dòng lệnh: git clone. Đó là cửa ngõ để bạn bước vào toàn bộ hệ sinh thái DevOps. Nghe có vẻ phóng đại, nhưng hãy nghĩ kỹ: mọi thứ chúng ta sẽ học trong khóa này — CI/CD tự động build khi có commit mới, Infrastructure as Code lưu hạ tầng dưới dạng file .tf, GitOps đồng bộ cluster Kubernetes theo trạng thái trong repo — tất cả đều đứng trên một nền móng duy nhất: version control (quản lý phiên bản), và cụ thể hơn là Git.
Không có version control thì không có gì cả. Không có nơi nào để pipeline "lắng nghe" thay đổi. Không có "single source of truth" (nguồn chân lý duy nhất) để so sánh trạng thái thực tế với trạng thái mong muốn. Không có lịch sử để truy vết ai đã đổi gì, khi nào, vì sao. Git không chỉ là công cụ lưu code — nó là giao diện cộng tác giữa con người với con người, và giữa con người với máy móc tự động hóa.
Nhưng biết mấy lệnh git add, git commit, git push là chưa đủ. Điều tạo ra khác biệt giữa một team hỗn loạn và một team vận hành trơn tru chính là workflow — quy ước chung về cách nhánh (branch) được tạo, hợp nhất (merge) và release. Chọn sai workflow, bạn sẽ dành nửa thời gian để giải quyết merge conflict và chờ review. Chọn đúng, code chảy từ ý tưởng ra production mượt như nước. Bài này dạy bạn nền tảng Git dưới góc nhìn DevOps và bốn workflow phổ biến nhất, để bạn biết đội mình nên dùng cái nào.
Khái niệm cốt lõi
Git là "single source of truth" như thế nào
Git là hệ thống version control phân tán (distributed): mỗi lập trình viên có một bản sao đầy đủ của toàn bộ lịch sử repo trên máy mình, không phụ thuộc vào server trung tâm để làm việc. Nhưng trong thực tế vận hành, cả team quy ước một repo trung tâm (thường trên GitHub, GitLab hay Bitbucket) làm điểm quy chiếu chung. Đó chính là "single source of truth".
Vì sao khái niệm này quan trọng với DevOps? Bởi vì mọi hệ thống tự động hóa đều cần một điểm neo để biết "trạng thái đúng" là gì. Pipeline CI/CD hỏi Git: "Có commit mới trên nhánh main không?" IaC hỏi Git: "File Terraform mô tả hạ tầng hiện tại trông thế nào?" GitOps controller hỏi Git: "Cluster nên chạy đúng những manifest nào?" Khi Git là nguồn chân lý, thay đổi hạ tầng và ứng dụng trở thành một hành động duy nhất, có thể kiểm toán: một commit.
Branch, merge, và commit — ba khối xây dựng
Ba khái niệm bạn phải nắm chắc:
- Commit: một ảnh chụp (snapshot) trạng thái code tại một thời điểm, kèm thông điệp mô tả. Mỗi commit có một mã hash duy nhất và trỏ về commit cha. Chuỗi commit tạo thành lịch sử.
- Branch: một con trỏ di động trỏ tới một commit. Tạo branch nghĩa là bạn có một dòng phát triển song song, tách khỏi nhánh chính, để làm việc mà không ảnh hưởng người khác. Branch trong Git rất "rẻ" — chỉ là một file 41 byte — nên đừng ngại tạo.
- Merge: hợp nhất hai dòng phát triển lại. Khi hai người cùng sửa một đoạn code, Git không tự quyết được và báo merge conflict — bạn phải giải quyết thủ công.
Merge vs Rebase — cuộc tranh luận muôn thuở
Có hai cách đưa thay đổi từ nhánh này vào nhánh khác:
- Merge: tạo một "merge commit" mới nối hai nhánh. Lịch sử giữ nguyên đúng như đã xảy ra, nhưng đồ thị commit trông rối như mạng nhện khi team đông.
- Rebase: "phát lại" các commit của bạn lên trên đầu nhánh đích, tạo lịch sử thẳng tắp, dễ đọc. Nhược điểm: nó viết lại lịch sử, nên tuyệt đối không rebase nhánh đã push chung với người khác.
Pull Request / Merge Request — trái tim của cộng tác
Pull Request (PR, thuật ngữ GitHub) hay Merge Request (MR, thuật ngữ GitLab) là nơi một nhánh xin được hợp nhất vào nhánh chính. Đây không chỉ là thao tác kỹ thuật — nó là điểm kiểm soát chất lượng: nơi đồng nghiệp review code, nơi pipeline CI chạy test tự động, nơi các quy tắc bảo vệ nhánh (branch protection) buộc phải xanh hết mới được merge. Với DevOps, PR chính là cánh cổng mà mọi thay đổi phải đi qua trước khi chạm production.
Tình huống thực tế
Ví dụ 1 — Startup fintech dùng Git Flow rồi "chết ngộp"
Một startup fintech ở Hà Nội, khoảng 12 kỹ sư, khi mới thành lập đã áp dụng Git Flow — mô hình nổi tiếng với các nhánh develop, feature/, release/, hotfix/* và main. Ban đầu nghe rất bài bản. Nhưng sau 8 tháng, họ nhận ra một feature từ lúc code xong đến lúc lên production mất trung bình 9 ngày: phải merge vào develop, chờ gom đủ tính năng, cắt nhánh release, test, rồi mới merge vào main. Nhánh develop và main thường xuyên lệch nhau khiến hotfix bị conflict.
Vấđề không phải Git Flow tệ — nó được thiết kế cho phần mềm phát hành theo phiên bản đóng gói (như app desktop, thư viện có version rõ ràng). Nhưng startup này deploy web app nhiều lần mỗi ngày. Họ chuyển sang GitHub Flow đơn giản hơn (chỉ có main và các nhánh feature ngắn), và thời gian từ code đến production giảm xuống còn dưới 1 ngày.
Bài học: workflow phải khớp với nhịp release của sản phẩm. Đừng chọn theo độ "nổi tiếng" mà theo bối cảnh.
Ví dụ 2 — Team game mobile Đông Nam Á và trunk-based development
Một studio game mobile phục vụ thị trường Đông Nam Á, với 40 developer làm chung một client Unity, thử áp dụng nhánh feature dài ngày. Kết quả: có nhánh sống tới 3 tuần, khi merge tạo ra hơn 200 file conflict, mất cả hai ngày để giải quyết — hiện tượng dân trong nghề gọi là "merge hell".
Họ chuyển sang trunk-based development: mọi người commit trực tiếp lên nhánh main (trunk) ít nhất một lần mỗi ngày, nhánh feature nếu có thì chỉ sống vài giờ. Những tính năng chưa hoàn thiện được che bằng feature flag (cờ tính năng — bật/tắt code lúc chạy, sẽ học ở Bài 46) thay vì giấu trong nhánh riêng. Nhờ tích hợp liên tục, conflict trở nên nhỏ và dễ xử lý vì mọi người luôn làm việc trên nền code mới nhất.
Bài học: nhánh càng sống lâu, chi phí merge càng tăng theo cấp số nhân. Tích hợp sớm và thường xuyên là cốt lõi của "CI" trong CI/CD.
Ví dụ 3 — Ngân hàng và GitLab Flow với environment branches
Một ngân hàng số dùng GitLab, với ràng buộc tuân thủ nghiêm ngặt: mọi thay đổi lên production phải qua UAT (User Acceptance Testing) và có phê duyệt. Họ dùng GitLab Flow với các nhánh môi trường: main → staging → production. Code merge vào main sẽ tự deploy lên môi trường staging; khi QA duyệt, một MR từ staging sang production sẽ kích hoạt deploy production. Mỗi lần "thăng cấp" một môi trường là một MR có dấu vết kiểm toán rõ ràng — đúng thứ mà bộ phận compliance cần.
Bài học: khi có ràng buộc quy trình và tuân thủ, environment branches biến chính lịch sử Git thành bằng chứng cho việc "cái gì đã lên môi trường nào, ai duyệt".
Hướng dẫn từng bước
Dưới đây là quy trình chuẩn theo GitHub Flow — workflow tôi khuyên đa số team web/app hiện đại nên bắt đầu:
- Đồng bộ nhánh chính: Trước khi làm gì, kéo code mới nhất về.
git checkout main
git pull origin main
- Tạo nhánh feature có tên rõ ràng: Đặt tên mô tả được việc mình làm.
git checkout -b feature/them-thanh-toan-momo
- Commit nhỏ, thường xuyên, thông điệp rõ: Mỗi commit là một đơn vị logic hoàn chỉnh. Ưu tiên chuẩn Conventional Commits.
git add .
git commit -m "feat: them nut thanh toan MoMo vao trang checkout"
- Push nhánh lên remote:
git push -u origin feature/them-thanh-toan-momo
- Mở Pull Request: Trên GitHub, mở PR từ nhánh của bạn vào
main. Viết mô tả rõ: làm gì, vì sao, test thế nào. Lúc này CI tự động chạy test.
- Review và sửa: Đồng nghiệp comment, bạn commit thêm để sửa. Trước khi merge, nếu
mainđã có commit mới, hãy đồng bộ lại — dùng rebase để lịch sử sạch:
git fetch origin
git rebase origin/main
Nếu có conflict, sửa xong rồi git rebase --continue.- Merge và dọn dẹp: Khi CI xanh và có approve, merge PR (nên dùng "Squash and merge" để gộp thành một commit sạch trên
main). Sau đó xóa nhánh feature — nó đã hoàn thành sứ mệnh.
Lỗi thường gặp & mẹo
- Nhánh sống quá lâu: Sai lầm phổ biến nhất. Nhánh feature nên sống vài ngày, không phải vài tuần. Chia nhỏ công việc; dùng feature flag để merge code chưa hoàn chỉnh một cách an toàn.
- Commit "khổng lồ" gom tất cả: Một commit sửa 50 file với message "update code" là ác mộng khi review và khi cần
git revert. Hãy commit theo từng đơn vị logic.
- Message commit vô nghĩa: "fix", "asdf", "final v2 real" — đừng. Message tốt giải thích vì sao, không phải cái gì (diff đã nói cái gì rồi). Áp dụng Conventional Commits (
feat:,fix:,chore:) còn giúp tự động sinh changelog.
- Rebase nhánh public: Đừng bao giờ rebase một nhánh đã được người khác pull về. Bạn viết lại lịch sử, và họ sẽ gặp phân kỳ khủng khiếp. Rebase chỉ dành cho nhánh riêng của bạn.
git push --forcebừa bãi: Force push có thể xóa commit của đồng nghiệp. Nếu buộc phải, dùnggit push --force-with-lease— nó chỉ ghi đè khi remote đúng như bạn nghĩ, an toàn hơn nhiều.
- Commit thông tin nhạy cảm: Commit nhầm file
.env, API key, mật khẩu là lỗi nghiêm trọng — xóa ở commit sau không làm nó biến mất khỏi lịch sử. Luôn có.gitignoređầy đủ ngay từ đầu, và cân nhắc công cụ quét secret trước khi commit (sẽ học sâu ở phần bảo mật).
- Mẹo bảo vệ nhánh: Bật branch protection trên
main: cấm push trực tiếp, bắt buộc PR, bắt buộc CI xanh và ít nhất một approve. Đây là hàng rào bảo vệ production đầu tiên của bạn.
Bài tập thực hành
- So sánh bốn workflow: Lập một bảng ngắn so sánh Git Flow, GitHub Flow, GitLab Flow và Trunk-based development theo bốn tiêu chí: độ phức tạp, tần suất release phù hợp, số nhánh dài hạn, và loại sản phẩm phù hợp. Rồi tự trả lời: dự án hiện tại của bạn (hoặc dự án bạn mơ ước làm) nên dùng cái nào? Vì sao?
- Thực hành vòng đời một feature: Tạo một repo trên GitHub. Thực hiện đầy đủ 7 bước ở phần Hướng dẫn: tạo nhánh feature, commit theo Conventional Commits, push, mở PR, và merge bằng "Squash and merge". Chụp lại đồ thị commit sau khi hoàn tất.
- Tự tạo và giải quyết conflict: Tạo hai nhánh cùng sửa một dòng trong cùng một file, rồi merge chúng để cố tình gây conflict. Giải quyết conflict thủ công. Sau đó làm lại nhưng dùng
rebasethay vìmergevà quan sát sự khác biệt trong lịch sử commit bằnggit log --graph --oneline.
- Thiết lập branch protection: Trên repo của bạn, bật branch protection cho
mainyêu cầu PR và cấm push trực tiếp. Thửgit pushthẳng lênmainvà quan sát Git từ chối như thế nào.
Tóm tắt
Git là nền móng của toàn bộ DevOps: không có version control thì không có CI/CD, không có IaC, không có GitOps. Nó đóng vai trò single source of truth — điểm quy chiếu để con người cộng tác và để máy móc tự động hóa. Nhưng công cụ chỉ mạnh khi đi kèm một workflow phù hợp.
Bốn workflow phổ biến: Git Flow bài bản nhưng nặng nề, hợp phần mềm phát hành theo phiên bản; GitHub Flow đơn giản với main và nhánh feature ngắn, hợp đa số web/app deploy liên tục; GitLab Flow thêm environment branches, hợp môi trường có ràng buộc tuân thủ; Trunk-based development tích hợp cực nhanh vào một trunk duy nhất, hợp team lớn muốn tốc độ cao và kết hợp feature flag.
Nguyên tắc cốt lõi xuyên suốt: nhánh sống càng ngắn càng tốt, commit nhỏ và có ý nghĩa, tích hợp sớm và thường xuyên, mọi thay đổi đi qua Pull Request với CI và review làm hàng rào chất lượng. Nắm vững điều này, bạn đã sẵn sàng để những bài tiếp theo — nơi Git trở thành động cơ khởi động cho mọi automation.