Git Flow, GitHub Flow và trunk-based: chọn quy trình Git nào
Git Flow là mô hình phân nhánh với hai nhánh tồn tại lâu dài là main và develop cùng các nhánh feature, release và hotfix tạm thời; phù hợp với sản phẩm có phiên bản theo kế hoạch. Với dịch vụ web triển khai thường xuyên, thường đơn giản hơn là GitHub Flow (nhánh ngắn từ main và pull request) hoặc trunk-based development với feature flags.
Git workflow là gì và vì sao việc chọn quan trọng
Git workflow là sự thống nhất trong nhóm về việc có những nhánh nào, tạo từ đâu, gộp vào đâu và thế nào thì được coi là sẵn sàng phát hành. Bản thân Git không bắt buộc điều gì trong số này, nên nếu không thống nhất, mỗi người sẽ làm theo cách riêng: sau một tháng kho có hàng chục nhánh, không ai biết bản nào đã được triển khai, và việc gộp biến thành những cuộc xung đột kéo dài hàng giờ.
Các mô hình nổi tiếng nhất là Git Flow, GitHub Flow (một biến thể của Feature Branch Workflow) và trunk-based development. Đây không phải là «cái cũ và cái mới», mà là công cụ cho những điều kiện khác nhau: bạn phát hành bản mới thường xuyên đến đâu, cùng lúc duy trì bao nhiêu phiên bản sản phẩm, và kiểm thử tự động phát triển ra sao.
Git Flow: mô hình với nhánh develop và release
Git Flow được Vincent Driessen mô tả năm 2010. Mô hình xây dựng trên hai nhánh tồn tại lâu dài:
- main (trong các dự án cũ là master) — chỉ chứa mã đã phát hành, mỗi commit ở đây tương ứng với một bản phát hành và được gắn thẻ;
- develop — nhánh tích hợp, nơi các tính năng đã xong được gộp vào để chuẩn bị cho bản phát hành tiếp theo.
Và ba loại nhánh tạm thời:
| Nhánh | Tạo từ | Gộp vào | Mục đích |
|---|---|---|---|
| feature/* | develop | develop | Phát triển một tính năng mới |
| release/* | develop | main và develop | Ổn định phiên bản: sửa lỗi, đặt số phiên bản, tài liệu |
| hotfix/* | main | main và develop | Sửa khẩn cấp cho phiên bản đã phát hành |
Git Flow bằng Git thuần
Chu trình của một tính năng và một bản phát hành trông như sau:
# tính năng
git switch develop
git switch -c feature/cart-discounts
# ... các commit ...
git switch develop
git merge --no-ff feature/cart-discounts
git branch -d feature/cart-discounts
# phát hành
git switch -c release/1.4.0 develop
# ... chỉnh số phiên bản và sửa lỗi ...
git switch main
git merge --no-ff release/1.4.0
git tag -a v1.4.0 -m "Release 1.4.0"
git switch develop
git merge --no-ff release/1.4.0
git branch -d release/1.4.0
Cờ --no-ff là yếu tố quan trọng của mô hình này: nó luôn tạo commit gộp ngay cả khi có thể chuyển con trỏ tới trước, nhờ đó lịch sử cho thấy rõ những commit nào thuộc cùng một tính năng hay bản phát hành.
Tiện ích mở rộng git-flow
Để khỏi phải gõ thủ công chuỗi lệnh này, có tiện ích git-flow (hiện thường cài bản fork được bảo trì, trong trình quản lý gói thường có tên git-flow-avh). Nó bổ sung các lệnh con:
git flow init -d
git flow feature start cart-discounts
git flow feature finish cart-discounts
git flow release start 1.4.0
git flow release finish 1.4.0
git flow hotfix start 1.4.1
git flow hotfix finish 1.4.1
git flow init hỏi tên nhánh và tiền tố (với -d sẽ dùng giá trị mặc định), còn các lệnh finish thực hiện mọi lần gộp cần thiết, gắn thẻ và xóa nhánh tạm. Nhiều ứng dụng GUI của Git cũng hỗ trợ Git Flow qua các nút bấm.
Ưu và nhược điểm của Git Flow
Ưu điểm: cấu trúc rõ ràng, trạng thái mã dễ hiểu (main là những gì người dùng đang có; develop là phiên bản tiếp theo), có giai đoạn ổn định riêng cho bản phát hành, và hỗ trợ hotfix thuận tiện. Mô hình này phù hợp với ứng dụng di động, phần mềm đóng gói, thư viện và phần sụn — nơi bản phát hành phải qua duyệt của cửa hàng ứng dụng hoặc được cài đặt tại chỗ của khách hàng.
Nhược điểm: nhiều nhánh và nhiều lần gộp, các nhánh feature sống lâu tích lũy khác biệt so với develop, và rất dễ quên lần gộp thứ hai của release hay hotfix. Với dịch vụ web triển khai vài lần mỗi ngày, nhánh release trở thành thủ tục rườm rà. Chính tác giả của mô hình, năm 2020, đã thêm ghi chú vào bài viết: với phần mềm được phát hành liên tục nên xem các cách đơn giản hơn như GitHub Flow.
GitHub Flow: nhánh ngắn và pull request
GitHub Flow là phiên bản gọn nhẹ của Feature Branch Workflow. Các quy tắc gói trong vài điểm:
- main luôn ở trạng thái hoạt động và sẵn sàng triển khai.
- Mọi công việc được làm trong một nhánh tạo từ main, đặt tên rõ nghĩa.
- Nhánh được đẩy lên thường xuyên và mở pull request (merge request) để thảo luận.
- Sau khi review và CI xanh, nhánh được gộp vào main.
- Những gì đã gộp vào main được triển khai ngay.
git switch main
git pull
git switch -c feature/new-payment
# ... các commit với thông điệp rõ ràng ...
git push -u origin feature/new-payment
# mở pull request, qua review và CI, gộp vào main
Ưu điểm: chỉ một nhánh tồn tại lâu dài, ít quy tắc, đường đi từ ý tưởng đến production ngắn, và code review diễn ra tự nhiên. Nhược điểm: không có chỗ sẵn cho việc duy trì nhiều phiên bản hay ổn định trước khi phát hành, và nếu không có kiểm thử tự động tốt thì «main luôn sẵn sàng» chỉ là mong muốn.
Một cách tiếp cận tương tự với thêm các nhánh môi trường (ví dụ staging và production) đôi khi được gọi là GitLab Flow. Nó hữu ích khi việc triển khai lên production không diễn ra ngay lập tức mà theo lịch hoặc sau khi kiểm tra thủ công.
Trunk-based development
Trong trunk-based development, tất cả lập trình viên tích hợp thay đổi vào một nhánh chung (trunk, tức là main) thường xuyên — ít nhất một lần mỗi ngày. Nếu có nhánh thì chúng chỉ tồn tại vài giờ, không phải vài tuần. Chức năng chưa hoàn thiện được đưa vào main nhưng bị ẩn sau feature flag:
if (featureFlags.isEnabled("new-checkout", user)) {
renderNewCheckout();
} else {
renderOldCheckout();
}
Ưu điểm lớn nhất là hầu như không có xung đột nặng: thay đổi nhỏ và được gộp khi mọi người còn nhớ ngữ cảnh. Mô hình hỗ trợ tích hợp liên tục theo đúng nghĩa đen và phù hợp với các nhóm trưởng thành, có CI nhanh và độ phủ test cao. Nhánh phát hành vẫn được phép, nhưng chúng được tạo từ trunk ngay trước khi phát hành, còn sửa lỗi thì commit vào trunk trước rồi chuyển sang nhánh phát hành bằng cherry-pick.
Nhược điểm: cần kỷ luật và hạ tầng — test nhanh, feature flag, giám sát. Người mới ngại commit vào main mỗi ngày, còn CI yếu biến trunk thành một nhánh hỏng liên tục. Các flag cũng phải được gỡ kịp thời, nếu không mã sẽ đầy những nhánh rẽ đã chết.
So sánh Git Flow, GitHub Flow và trunk-based
| Tiêu chí | Git Flow | GitHub Flow | Trunk-based |
|---|---|---|---|
| Nhánh tồn tại lâu dài | main và develop | main | main (trunk) |
| Vòng đời nhánh feature | Vài ngày đến vài tuần | Vài ngày | Vài giờ hoặc không dùng nhánh |
| Tần suất phát hành | Theo phiên bản đã lên kế hoạch | Mỗi khi gộp | Liên tục |
| Duy trì nhiều phiên bản | Có, qua thẻ và hotfix | Khó | Qua các nhánh release |
| Yêu cầu về CI và test | Trung bình | Cao | Rất cao |
| Nguy cơ xung đột lớn | Cao | Trung bình | Thấp |
| Ngưỡng làm quen | Phải học các quy tắc | Tối thiểu | Cần văn hóa nhóm và feature flags |
| Dự án điển hình | Ứng dụng di động, thư viện, phần mềm đóng gói | Dịch vụ web, mã nguồn mở, startup | Sản phẩm lớn triển khai thường xuyên |
Cách chọn git workflow cho nhóm
Hãy tự trả lời vài câu hỏi:
- Có cần hỗ trợ nhiều phiên bản đã phát hành không? Nếu khách hàng đang dùng 2.x và 3.x và cả hai đều cần bản sửa — chọn Git Flow hoặc trunk-based với nhánh release.
- Bạn triển khai bao lâu một lần? Mỗi quý — Git Flow không gây trở ngại. Mỗi ngày — hãy chọn GitHub Flow hoặc trunk-based.
- Bạn tin tưởng test đến mức nào? Nếu CI chậm và độ phủ thấp, hãy bắt đầu với GitHub Flow có review bắt buộc, rồi dần rút ngắn nhánh.
- Quy mô và kinh nghiệm nhóm ra sao? Với nhóm nhỏ hoặc người mới, GitHub Flow đơn giản nhất: một quy tắc «main luôn hoạt động» và pull request cho mọi thứ.
Lời khuyên thực tế: đừng chọn Git Flow chỉ vì «người ta vẫn làm vậy». Hãy bắt đầu với quy trình đơn giản nhất giải quyết được việc của bạn, và chỉ phức tạp hóa khi xuất hiện vấn đề cụ thể — ví dụ cần giai đoạn ổn định hay hỗ trợ các phiên bản cũ.
Quy tắc nào cũng đúng với mọi workflow
- Bảo vệ main trên máy chủ: cấm push trực tiếp, bắt buộc review và CI xanh trước khi gộp.
- Thống nhất tên nhánh:
feature/,fix/,hotfix/kèm mã công việc. - Giữ nhánh ngắn: nhánh sống càng lâu thì gộp càng đau. Thường xuyên kéo main vào nhánh của mình bằng merge hoặc rebase.
- Chọn một chiến lược gộp pull request (merge commit, squash hoặc rebase) và dùng thống nhất.
- Đánh dấu bản phát hành bằng thẻ chú thích theo quy tắc phiên bản ngữ nghĩa.
Hotfix trong từng mô hình: một lỗi, ba quy trình
Sự khác biệt giữa các cách tiếp cận rõ nhất khi xử lý một lỗi khẩn cấp trên production.
Trong Git Flow, tạo hotfix/1.4.1 từ main, sau khi sửa xong nhánh được gộp vào main kèm thẻ v1.4.1 và bắt buộc gộp cả vào develop (hoặc vào nhánh release hiện tại nếu có). Quên lần gộp thứ hai là lỗi kinh điển: ở bản phát hành sau, lỗi «sống lại».
git switch -c hotfix/1.4.1 main
git commit -am "Sửa tính toán giảm giá"
git switch main && git merge --no-ff hotfix/1.4.1
git tag -a v1.4.1 -m "Hotfix 1.4.1"
git switch develop && git merge --no-ff hotfix/1.4.1
Trong GitHub Flow, hotfix chỉ là một nhánh ngắn từ main với pull request được ưu tiên review. Sau khi gộp, nó được triển khai ngay bằng cơ chế deploy tự động thông thường, không có quy trình riêng.
Trong trunk-based, sửa lỗi được commit vào trunk trước, còn nếu production đang chạy một nhánh release thì commit đó được chuyển sang bằng git cherry-pick -x <hash>. Cờ -x thêm vào thông điệp liên kết tới commit gốc, để mối quan hệ hiển thị trong lịch sử. Nếu lỗi nằm ở một tính năng mới, thường chỉ cần tắt feature flag của nó mà không đụng tới code.
Trả lời thế nào khi được hỏi «bạn đã dùng Git workflow nào» trong phỏng vấn
Nhà tuyển dụng không kiểm tra việc bạn thuộc tên gọi, mà kiểm tra việc bạn hiểu các đánh đổi. Một câu trả lời tốt là nêu mô hình, mô tả cách nhánh và review vận hành trong đó, và giải thích vì sao nó phù hợp với dự án. Ví dụ: «Chúng tôi dùng GitHub Flow: nhánh từ main, pull request với review bắt buộc và CI, sau khi gộp thì tự động triển khai. Không chọn Git Flow vì chúng tôi phát hành vài lần mỗi tuần, và nhánh release chỉ làm chậm mọi thứ.» Điểm cộng là kể thêm bạn sẽ thay đổi điều gì nếu quy trình phải lớn lên.
Tóm lại
Git Flow là mô hình chặt chẽ với các nhánh develop, release và hotfix, tốt cho sản phẩm có phiên bản theo kế hoạch và hỗ trợ nhiều bản phát hành. GitHub Flow đơn giản hơn và phù hợp với đa số dự án web, còn trunk-based development mang lại tốc độ cao nhất nhưng đòi hỏi CI trưởng thành và feature flags. Hãy chọn git workflow dựa trên tần suất phát hành và chất lượng test, chứ không chạy theo xu hướng. Cả ba cách tiếp cận cùng các lỗi thường gặp được chúng tôi phân tích thực hành trong khóa học Git.
Câu hỏi thường gặp
Git Flow đã lỗi thời chưa?
Chưa, nhưng phạm vi sử dụng đã thu hẹp. Với dịch vụ web triển khai liên tục, nó quá phức tạp; còn với ứng dụng di động, thư viện và phần mềm đóng gói, nó vẫn tiện dụng.
Có cần nhánh develop nếu phát hành thường xuyên không?
Thường là không: develop lặp lại main và thêm một lần gộp không cần thiết. Khi phát hành thường xuyên, main và các nhánh feature ngắn là đủ.
Có dùng rebase trong Git Flow được không?
Được, có thể kéo develop vào nhánh feature cá nhân chưa đẩy lên bằng rebase; nhưng các lần gộp cuối cùng vào develop và main trong mô hình cổ điển thường dùng merge --no-ff để giữ cấu trúc lịch sử.
Feature flag tốt hơn nhánh feature sống lâu ở điểm nào?
Mã được tích hợp vào main ngay và không lệch khỏi phần còn lại của cơ sở mã; việc bật tính năng trở thành một quyết định riêng và có thể hoàn tác mà không cần rollback mã.
Chuyển từ Git Flow sang GitHub Flow thế nào?
Kết thúc các bản phát hành đang chạy, gộp develop vào main, cấu hình lại CI để triển khai từ main, rồi xóa develop. Từ đó chỉ tạo nhánh mới từ main.
Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Git с нуля до уверенного разработчика”.
Đến khóa học