Module 04 Version Control 5 labs

Git, GitHub, GitLab và Collaboration Workflow

Nắm vững Git từ cơ bản đến nâng cao: branch strategy, merge conflict, Pull Request review workflow, protected branch rule và tag semantic versioning — nền tảng bắt buộc cho mọi DevOps/Cloud Engineer.

Công cụ thực hành Git, GitHub CLI (gh), GitLab CLI, VS Code, terminal
Nền tảng Windows / Linux (WSL2), GitHub, GitLab
Thời điểm phát hành 23/05/2026
Ngày biên soạn 23/05/2026
Người biên soạn Trần Văn Hòa — Microsoft Certified Trainer (MCT)

Mục tiêu học tập

1. Lý thuyết cốt lõi

1.1. Git — Distributed Version Control System

Git lưu trữ dữ liệu dưới dạng snapshot (không phải diff), mỗi commit là một pointer đến snapshot đó. Ba vùng làm việc: Working DirectoryStaging Area (Index)Repository (.git). Mỗi developer có toàn bộ lịch sử locally (distributed), không phụ thuộc server để commit hay xem log.

Các object cốt lõi trong Git

  • Blob — nội dung file (không lưu tên).
  • Tree — cấu trúc thư mục, trỏ đến blob hoặc tree con.
  • Commit — metadata (author, message, timestamp) + pointer đến tree + parent commit(s).
  • Tag — pointer có tên đến một commit cụ thể, thường dùng để đánh dấu release.
  • Branch — con trỏ di động (mutable pointer) đến commit mới nhất của nhánh đó.

1.2. Branch Strategy

StrategyPhù hợpCấu trúc branch
Git FlowPhần mềm có release cycle rõ ràngmain, develop, feature/*, release/*, hotfix/*
GitHub FlowỨng dụng web, deploy liên tụcmain + feature branches ngắn hạn
Trunk-BasedTeam mature, CI/CD mạnhmain + branch tồn tại <1–2 ngày + feature flags

DevOps hiện đại ưu tiên Trunk-Based Development vì giảm merge hell, tăng deployment frequency (DORA metric #1). Feature flag cho phép tách deploy khỏi release.

1.3. Merge Conflict — Nguyên nhân & Giải pháp

Conflict xảy ra khi hai nhánh chỉnh sửa cùng một vùng file mà Git không thể tự merge. Markers: <<<<<<< HEAD (nhánh hiện tại), ======= (phân cách), >>>>>>> feature-branch (nhánh được merge vào). Quy trình giải quyết: identify → edit manually → git addgit commit. Dùng git mergetool hoặc VS Code merge editor để trực quan hơn.

1.4. Pull Request & Code Review Workflow

PR/MR không chỉ là cơ chế merge code mà còn là công cụ knowledge sharing. Best practice: PR nhỏ (≤400 lines diff), mô tả rõ "What/Why/How", link issue, checklist test. CODEOWNERS file tự động assign reviewer theo thư mục/file. Required status checks (CI pass) + required reviews tạo guardrail trước khi merge vào main.

1.5. Protected Branch & Semantic Versioning

Protected branch trên GitHub/GitLab ngăn: force push, xóa branch, merge khi CI fail hoặc chưa đủ reviewer. Semantic Versioning (SemVer): MAJOR.MINOR.PATCH — MAJOR khi breaking change, MINOR khi tính năng mới backward-compatible, PATCH khi bug fix. Pre-release: 1.0.0-alpha.1, 1.0.0-rc.2. Git tag annotated (git tag -a v1.0.0 -m "...") tốt hơn lightweight tag vì lưu metadata.

1.6. GitHub vs GitLab — So sánh nhanh

Tiêu chíGitHubGitLab
CI/CD tích hợpGitHub ActionsGitLab CI/CD (YAML pipeline)
Self-hostedGitHub Enterprise ServerGitLab CE/EE (miễn phí CE)
PR/MRPull RequestMerge Request
Package registryGitHub PackagesGitLab Package Registry (built-in)

2. Thực hành (Labs)

LAB-016

Tạo repo và branch strategy

CLI · VS Code · Git

🎯 Mục tiêu: Khởi tạo Git repo, đẩy lên GitHub, áp dụng Git Flow branch strategy với các nhánh main, develop và feature.

🧰 Công cụ / nền tảng: Git ≥ 2.40, GitHub CLI (gh), VS Code, Bash/WSL2 hoặc PowerShell.

📦 Chuẩn bị: Cài Git, VS Code; tạo tài khoản GitHub; cài GitHub CLI và chạy gh auth login.

▶️ Các bước (Bash / WSL2):

# 1. Tạo thư mục và khởi tạo repo cục bộ
mkdir devops-m04-lab && cd devops-m04-lab
git init
git checkout -b main

# 2. Tạo file README và commit đầu tiên
echo "# DevOps M04 Lab" > README.md
git add README.md
git commit -m "chore: initial commit"

# 3. Tạo nhánh develop (integration branch)
git checkout -b develop
echo "# Develop branch" >> README.md
git add README.md
git commit -m "chore: setup develop branch"

# 4. Tạo feature branch từ develop
git checkout -b feature/user-login develop
echo "## Feature: User Login" >> README.md
git add README.md
git commit -m "feat: scaffold user-login feature"

# 5. Tạo repo trên GitHub và push tất cả branches
gh repo create devops-m04-lab --public --source=. --remote=origin
git push -u origin main
git push -u origin develop
git push -u origin feature/user-login

# 6. Kiểm tra
git branch -a
gh repo view --web

🖥️ PowerShell (Windows — không dùng WSL2):

# Tương đương trên PowerShell — chỉ thay mkdir/echo
New-Item -ItemType Directory -Name devops-m04-lab
Set-Location devops-m04-lab
git init
git checkout -b main
"# DevOps M04 Lab" | Out-File README.md -Encoding UTF8
git add README.md
git commit -m "chore: initial commit"

✅ Kết quả mong đợi: git branch -a hiển thị 3 nhánh (main, develop, feature/user-login); GitHub repo public với 3 remote branches; git log --oneline --graph --all cho thấy cây nhánh rõ ràng.

🧹 Cleanup: Giữ repo cho LAB-017/018/019/020 hoặc gh repo delete devops-m04-lab --confirm.

LAB-017

Xử lý merge conflict

CLI · VS Code · Git

🎯 Mục tiêu: Tạo conflict có chủ ý, nhận diện markers, giải quyết bằng CLI và VS Code Merge Editor, hoàn thành merge thành công.

🧰 Công cụ / nền tảng: Git, VS Code (extension GitLens tuỳ chọn), Bash/WSL2.

📦 Chuẩn bị: Repo từ LAB-016 với nhánh main và develop.

▶️ Các bước:

# 1. Trên nhánh develop, sửa dòng 1 của config.txt
git checkout develop
echo "APP_PORT=3000" > config.txt
git add config.txt && git commit -m "feat: set port 3000 on develop"

# 2. Trên nhánh feature/hotfix, sửa cùng dòng đó với giá trị khác
git checkout -b feature/hotfix-port
echo "APP_PORT=8080" > config.txt
git add config.txt && git commit -m "fix: change port to 8080"

# 3. Merge feature/hotfix-port vào develop → conflict!
git checkout develop
git merge feature/hotfix-port
# Output: CONFLICT (content): Merge conflict in config.txt

# 4. Xem trạng thái conflict
git status
cat config.txt
# Hiển thị:
# <<<<<<< HEAD
# APP_PORT=3000
# =======
# APP_PORT=8080
# >>>>>>> feature/hotfix-port

# 5a. Giải quyết bằng CLI: chọn port 8080 (phiên bản incoming)
echo "APP_PORT=8080" > config.txt
git add config.txt
git commit -m "merge: resolve port conflict — use 8080"

# 5b. Hoặc mở VS Code để dùng Merge Editor (GUI)
# code config.txt
# Nhấn "Accept Incoming Change" trong editor

# 6. Xác nhận merge thành công
git log --oneline -3
git show HEAD

🖥️ VS Code GUI:

Khi có conflict, Source Control panel hiển thị file với icon ⚠️. Click vào file → chọn "Open Merge Editor" → dùng 3-way view để chọn "Accept Current", "Accept Incoming" hoặc sửa thủ công trong Result pane → click "Accept Merge".

✅ Kết quả mong đợi: git log --oneline -3 hiển thị merge commit; cat config.txt không còn conflict markers; git diff develop feature/hotfix-port rỗng sau khi merge.

🧹 Cleanup: git branch -d feature/hotfix-port để xóa nhánh đã merge.

LAB-018

Pull Request review workflow

CLI · VS Code · Git

🎯 Mục tiêu: Tạo Pull Request từ CLI bằng gh, thêm CODEOWNERS, để lại review comment, approve và merge PR.

🧰 Công cụ / nền tảng: GitHub CLI (gh), Git, GitHub web (xem kết quả).

📦 Chuẩn bị: Repo từ LAB-016; đã push nhánh feature/user-login lên remote.

▶️ Các bước:

# 1. Tạo file CODEOWNERS (GitHub dùng để auto-assign reviewer)
mkdir -p .github
cat > .github/CODEOWNERS << 'EOF'
# Mọi file trong repo đều yêu cầu review từ @your-github-username
*   @your-github-username

# Thư mục src/ yêu cầu thêm team backend
src/   @your-github-username
EOF
git add .github/CODEOWNERS
git commit -m "chore: add CODEOWNERS"
git push origin feature/user-login

# 2. Tạo Pull Request từ CLI
gh pr create \
  --title "feat: implement user login" \
  --body "## Mô tả
Thêm flow đăng nhập user với JWT.

## Checklist
- [x] Unit tests pass
- [x] Không có hardcoded secret
- [x] Cập nhật README" \
  --base develop \
  --head feature/user-login \
  --reviewer "@your-github-username"

# 3. Xem danh sách PR
gh pr list

# 4. Xem chi tiết PR vừa tạo
gh pr view --web

# 5. Merge PR sau khi có approval (squash merge)
gh pr merge --squash --delete-branch

# 6. Xác nhận nhánh đã được xóa và develop có commit mới
git fetch origin
git log --oneline origin/develop -3

🖥️ GitHub Web:

Vào repo → tab "Pull requests" → chọn PR → "Files changed" để review từng dòng → click dòng muốn comment → "Add single comment" → "Review changes" → chọn "Approve" → "Merge pull request" → chọn "Squash and merge".

✅ Kết quả mong đợi: PR trạng thái "Merged" (màu tím); nhánh feature tự động xóa; git log --oneline origin/develop -3 chứa squash commit mới; CODEOWNERS file có mặt trong .github/.

🧹 Cleanup: git fetch --prune để xóa remote tracking branch đã bị xóa.

LAB-019

Protected branch rule

CLI · VS Code · Git

🎯 Mục tiêu: Cấu hình branch protection rule cho maindevelop: yêu cầu PR, ít nhất 1 approval, không cho phép force-push.

🧰 Công cụ / nền tảng: GitHub CLI (gh api), GitHub web, Git.

📦 Chuẩn bị: Repo từ LAB-016 với quyền Admin.

▶️ Các bước (GitHub API qua gh):

# Lấy thông tin owner và repo
OWNER=$(gh repo view --json owner -q .owner.login)
REPO=$(gh repo view --json name -q .name)
echo "Repo: $OWNER/$REPO"

# Tạo branch protection rule cho nhánh main
gh api \
  --method PUT \
  -H "Accept: application/vnd.github+json" \
  /repos/$OWNER/$REPO/branches/main/protection \
  -f required_status_checks='{"strict":true,"contexts":[]}' \
  -f enforce_admins=false \
  -f required_pull_request_reviews='{"required_approving_review_count":1,"dismiss_stale_reviews":true}' \
  -f restrictions=null \
  -F allow_force_pushes=false \
  -F allow_deletions=false

# Kiểm tra rule đã tạo
gh api /repos/$OWNER/$REPO/branches/main/protection | \
  jq '{required_pr_reviews: .required_pull_request_reviews.required_approving_review_count,
       allow_force_push: .allow_force_pushes.enabled,
       allow_delete: .allow_deletions.enabled}'

# Thử force-push trực tiếp vào main (phải bị từ chối)
git checkout main
echo "test" >> README.md
git add README.md && git commit -m "test: direct push"
git push --force origin main
# Expected: remote: error: GH006: Protected branch update failed

🖥️ GitHub Web GUI:

Repo → Settings → Branches → "Add branch protection rule" → Branch name pattern: main → Tích "Require a pull request before merging" → "Required approvals: 1" → "Do not allow bypassing the above settings" → "Require status checks to pass" → Save changes.

✅ Kết quả mong đợi: Force-push bị từ chối với error GH006; direct push không qua PR bị block; GitHub UI hiển thị khóa 🔒 bên cạnh nhánh main trong tab Branches.

🧹 Cleanup: Xóa protection rule nếu muốn tiếp tục push trực tiếp: gh api --method DELETE /repos/$OWNER/$REPO/branches/main/protection.

LAB-020

Tag release theo semantic versioning

CLI · VS Code · Git

🎯 Mục tiêu: Tạo annotated tag theo SemVer, push lên GitHub, tạo GitHub Release kèm release notes và changelog tự động.

🧰 Công cụ / nền tảng: Git, GitHub CLI (gh), Bash/WSL2.

📦 Chuẩn bị: Repo từ LAB-016 với ít nhất 2 commits trên main.

▶️ Các bước:

# 1. Xem lịch sử commit để quyết định version
git log --oneline -5

# 2. Tạo annotated tag v1.0.0 (initial release)
git checkout main
git tag -a v1.0.0 -m "Release v1.0.0

### What's new
- Initial project setup
- Git Flow branch strategy
- CODEOWNERS configuration

### Bug Fixes
- None (first release)
"

# 3. Push tag lên remote
git push origin v1.0.0
# Hoặc push tất cả tags: git push origin --tags

# 4. Liệt kê tags với thông tin
git tag -n10
# Output: v1.0.0   Release v1.0.0

# 5. Tạo GitHub Release từ tag vừa push
gh release create v1.0.0 \
  --title "v1.0.0 — Initial Release" \
  --notes "## Highlights
- Git Flow branch strategy implemented
- Protected branch rules configured
- CODEOWNERS for auto-assign reviews

## Breaking Changes
None — initial release." \
  --latest

# 6. Tạo pre-release tag (ví dụ v1.1.0-beta.1)
git checkout develop
# (làm thêm một số thay đổi)
echo "# beta feature" >> README.md
git add README.md && git commit -m "feat: beta feature"
git tag -a v1.1.0-beta.1 -m "Pre-release: beta testing"
git push origin v1.1.0-beta.1
gh release create v1.1.0-beta.1 --prerelease --title "v1.1.0-beta.1 — Beta" --generate-notes

# 7. Xem tất cả releases
gh release list

🖥️ GitHub Web:

Repo → Releases → "Draft a new release" → chọn tag (hoặc tạo mới) → điền title + release notes → tích "Set as latest release" → "Publish release".

✅ Kết quả mong đợi: git tag -n10 hiển thị tag với message; gh release list hiển thị v1.0.0 (Latest) và v1.1.0-beta.1 (Pre-release); GitHub Releases page có download source code (.zip, .tar.gz) tự động.

🧹 Cleanup: git tag -d v1.1.0-beta.1 && git push origin --delete v1.1.0-beta.1 để xóa pre-release tag; giữ v1.0.0 làm mẫu.

3. Tình huống doanh nghiệp thực tế

Bối cảnh

Một công ty fintech với 15 developer, 2 team (Backend + Frontend), cần release mỗi 2 tuần. Hiện tại code review thủ công qua chat, không có quy trình, xảy ra "works on my branch" thường xuyên, deployment thất bại do code chưa review kỹ lẫn nhau.

Giải pháp áp dụng

  • Branch strategy: GitHub Flow — main là production-ready, mọi feature từ main và PR ngược lại main. Loại bỏ develop branch vì team nhỏ.
  • CODEOWNERS: Backend team (@backend-team) review src/api/; Frontend team (@frontend-team) review src/ui/. Auto-assign, không cần nhớ ai review gì.
  • Protected branch: main yêu cầu 1 approval + CI pass (unit test + lint). Force-push bị block hoàn toàn.
  • SemVer tags: Mỗi sprint kết thúc tạo release tag MINOR (v1.X.0); hotfix tạo PATCH (v1.X.Y). GitHub Release notes auto-generate từ PR titles.
  • Kết quả: Lead Time giảm từ 3 ngày (review thủ công) xuống 4 giờ; Change Failure Rate giảm nhờ required CI checks; team không còn tranh luận "ai review code ai".

📚 Nguồn tham khảo

Module 03: Networking Fundamentals Module 05: Bash, PowerShell & Python
Zalo