Giao diện
Advanced Repository Management 🏗️
ROLE: HPN (Architecture & DevOps).
AUDIENCE: Engineers quản lý monorepos, shared libraries, và large assets.
Khi dự án của bạn lớn lên, bạn sẽ gặp các vấn đề mà git add && git commit không giải quyết được: shared libraries, multiple parallel workstreams, và large binary files. Module này trang bị cho bạn các công cụ nâng cao để xử lý chúng.
🎯 Mục tiêu
Sau module này, bạn sẽ:
- Quản lý Submodules - repos lồng nhau
- Dùng Worktrees - làm việc trên nhiều branches cùng lúc
- Setup Git LFS - xử lý large binaries hiệu quả
📦 Git Submodules - Repos Inside Repos
The Problem
"Team A đang maintain thư viện
ui-components. Team B, C, D đều muốn dùng. Copy-paste? Vendor folder? Fork?"
Solution: Git Submodules - embed một repo vào trong repo khác.
How It Works
Key insight: Main repo chỉ lưu pointer (commit SHA) đến submodule, không phải toàn bộ code.
Basic Commands
bash
# 1. Thêm submodule
git submodule add https://github.com/team/ui-components.git libs/ui-components
# 2. Clone repo có submodules
git clone --recurse-submodules https://github.com/company/main-project.git
# Hoặc nếu đã clone rồi:
git submodule update --init --recursive
# 3. Cập nhật submodule lên version mới
cd libs/ui-components
git checkout v2.0.0 # hoặc git pull origin main
cd ../..
git add libs/ui-components
git commit -m "chore: update ui-components to v2.0.0"
# 4. Xem status của submodules
git submodule status❌ The Pain: Detached HEAD
Vấn đề phổ biến nhất: Sau khi git submodule update, bạn ở trạng thái detached HEAD.
bash
$ cd libs/ui-components
$ git status
HEAD detached at abc123 # 😱 Không ở branch nào!Tại sao? Submodule checkout exact commit, không phải branch tip.
Cách fix:
bash
# 1. Checkout branch thay vì commit
cd libs/ui-components
git checkout main # or develop, etc.
# 2. Hoặc config để tự động track branch
git config -f .gitmodules submodule.libs/ui-components.branch main
git submodule update --remote --mergeSubmodule Workflows
Update All Submodules
bash
# Cập nhật tất cả submodules lên latest commit của tracked branch
git submodule update --remote --merge
# Recursive (nested submodules)
git submodule update --init --recursive --remoteRemove a Submodule
bash
# 1. Deinit
git submodule deinit -f libs/ui-components
# 2. Remove from .git/modules
rm -rf .git/modules/libs/ui-components
# 3. Remove from working tree
git rm -f libs/ui-components
# 4. Commit
git commit -m "chore: remove ui-components submodule"Foreach - Run Command in All Submodules
bash
# Pull all submodules
git submodule foreach 'git pull origin main'
# Check status of all
git submodule foreach 'git status'
# Recursive foreach
git submodule foreach --recursive 'git fetch --all'.gitmodules File
ini
[submodule "libs/ui-components"]
path = libs/ui-components
url = https://github.com/team/ui-components.git
branch = main
[submodule "libs/shared-utils"]
path = libs/shared-utils
url = git@github.com:team/shared-utils.gitCOMMON PITFALL
Sau khi git pull main repo, luôn chạy:
bash
git submodule update --init --recursiveNếu không, submodule của bạn sẽ ở version cũ!
🌳 Git Worktrees - Multiple Branches, One Repo
The Problem
"Đang code dở feature branch, có bug urgent cần fix trên main. Stash? Commit WIP? Cả hai đều messy."
Solution: Git Worktrees - checkout nhiều branches vào nhiều folders khác nhau, từ cùng một repo.
How It Works
Key insight: Tất cả worktrees share cùng .git/ directory → không duplicate objects.
Basic Commands
bash
# 1. Tạo worktree cho branch có sẵn
git worktree add ../app-hotfix hotfix/urgent-fix
# 2. Tạo worktree với branch mới
git worktree add -b feature/new-ui ../app-new-ui main
# 3. List all worktrees
git worktree list
# /home/user/projects/app abc123 [main]
# /home/user/projects/app-hotfix def456 [hotfix/urgent-fix]
# /home/user/projects/app-new-ui ghi789 [feature/new-ui]
# 4. Remove worktree khi xong
git worktree remove ../app-hotfix
# 5. Prune stale worktrees
git worktree pruneReal-World Workflow
bash
# Scenario: Đang code feature, có bug urgent
# 1. Bạn đang ở main worktree, working on feature
cd ~/projects/myapp
git switch feature/login-redesign
# ... đang code dở ...
# 2. Có bug urgent! Tạo worktree mới, không disturb work hiện tại
git worktree add ../myapp-hotfix hotfix/critical-bug
# 3. Switch sang folder mới, fix bug
cd ../myapp-hotfix
# fix bug...
git add . && git commit -m "fix: critical security issue"
git push origin hotfix/critical-bug
# Create PR, merge...
# 4. Quay lại feature work
cd ../myapp
# Code của feature vẫn y nguyên! Không cần stash/unstash
# 5. Cleanup
cd ~/projects/myapp
git worktree remove ../myapp-hotfixWorktree Use Cases
| Scenario | Worktree Solution |
|---|---|
| Fix urgent bug mid-feature | Tạo worktree cho hotfix branch |
| Test two versions side-by-side | Worktree cho main và develop |
| Review PR mà không làm gián đoạn work | Worktree checkout PR branch |
| Long-running experiment | Worktree cho experiment branch |
PRO TIP
Đặt worktrees ở cùng parent folder với main repo:
~/projects/
├── myapp/ (main worktree)
├── myapp-hotfix/ (hotfix worktree)
└── myapp-feature/ (feature worktree)🗃️ Git LFS - Large File Storage
The Problem
"Designer commit file PSD 500MB. Repo clone từ 100MB lên 2GB. Mọi người muốn giết designer."
Tại sao Git xử lý binary kém?
- Git lưu full snapshot, không delta compression cho binaries
- Mỗi version = thêm full file size
- Clone phải download toàn bộ history
The Solution: Git LFS
Git LFS lưu pointer trong repo, actual file trên LFS server riêng.
Setup Git LFS
bash
# 1. Install (một lần trên máy)
# macOS
brew install git-lfs
# Windows
winget install GitHub.GitLFS
# Ubuntu
sudo apt install git-lfs
# 2. Initialize trong user profile (một lần)
git lfs install
# 3. Track file types trong repo
cd your-repo
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "*.mp4"
git lfs track "assets/**"
# 4. Commit .gitattributes
git add .gitattributes
git commit -m "chore: configure Git LFS"How LFS Works
Pointer File
Thay vì actual binary, Git repo chứa pointer file:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 536870912Workflow
Essential Commands
bash
# Xem files đang được track
git lfs track
# Xem LFS files trong repo
git lfs ls-files
# Pull LFS files (nếu chưa có)
git lfs pull
# Clone với LFS files
git clone <url> # Tự động pull LFS nếu đã install
# Clone KHÔNG có LFS files (lightweight)
GIT_LFS_SKIP_SMUDGE=1 git clone <url>
# Migrate existing files to LFS
git lfs migrate import --include="*.psd" --everything
# Fetch specific LFS files
git lfs fetch --include="assets/logo.png".gitattributes Configuration
gitattributes
# Images
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
# Videos
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
# Archives
*.zip filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
# ML Models
*.bin filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
# Specific folders
assets/** filter=lfs diff=lfs merge=lfs -textLFS Considerations
| Aspect | Details |
|---|---|
| Storage | GitHub: 1GB free, 50GB với $5/mo data pack |
| Bandwidth | GitHub: 1GB/mo free, paid tiers available |
| CI/CD | Cần git lfs install + git lfs pull trong pipeline |
| Submodules | LFS works với submodules, cần config đúng |
LFS GOTCHA
Nếu forget để git lfs install trước khi commit large files:
bash
# Migrate những files đã commit nhầm
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main
git push --force # ⚠️ Rewrites history!📊 Quick Reference
Submodules
| Command | Purpose |
|---|---|
git submodule add <url> <path> | Add submodule |
git submodule update --init --recursive | Initialize & update |
git submodule update --remote | Update to latest |
git submodule foreach '<cmd>' | Run command in all |
git submodule status | Check versions |
Worktrees
| Command | Purpose |
|---|---|
git worktree add <path> <branch> | Create worktree |
git worktree add -b <new> <path> <base> | Create with new branch |
git worktree list | List all worktrees |
git worktree remove <path> | Remove worktree |
git worktree prune | Cleanup stale |
LFS
| Command | Purpose |
|---|---|
git lfs install | Setup LFS |
git lfs track "<pattern>" | Track file pattern |
git lfs ls-files | List tracked files |
git lfs pull | Download LFS files |
git lfs migrate import | Migrate existing files |
💡 Key Takeaways
HPN'S INSIGHT
"Submodules cho shared code, Worktrees cho parallel work, LFS cho binaries. Đúng tool cho đúng problem."
- Submodules lưu pointers: Main repo chỉ track commit SHA, không phải code
- Always
--recursive:git submodule update --init --recursivelà bạn tốt - Worktrees share objects: Không duplicate data, instant checkout
- LFS là mandatory cho binaries: Files >10MB nên dùng LFS
- CI/CD needs setup: Submodules và LFS cần explicit commands trong pipelines
CHOOSE WISELY
| Problem | Wrong Tool | Right Tool |
|---|---|---|
| Shared library | Copy-paste | Submodule |
| Parallel branches | Stash | Worktree |
| Large binaries | Regular commit | LFS |
| Forked customization | Submodule | Subtree or fork |
🧠 Quiz
Câu 1: Khi nào nên dùng Git Submodules thay vì copy-paste shared library?
- [x] A) Khi cần include một repository bên ngoài và muốn pin tại commit cụ thể, tự động update
- [ ] B) Khi shared library chỉ có 1 file
- [ ] C) Khi không có internet access
- [ ] D) Khi repository quá lớn
💡 Giải thích: Submodules cho phép include repository khác như dependency, pin tại commit cụ thể, và update khi cần. Copy-paste tạo code duplication, mất version tracking, và khó update. Submodules là "right tool" cho shared libraries.
Câu 2: Git LFS (Large File Storage) giải quyết vấn đề gì?
- [ ] A) Tăng tốc độ
git clone - [ ] B) Encrypt large files trong repository
- [x] C) Lưu large binary files (images, videos, models) trên server riêng, chỉ giữ pointer trong Git
- [ ] D) Nén toàn bộ repository
💡 Giải thích: Git không hiệu quả với large binary files (mỗi thay đổi lưu full copy). LFS thay thế binary files bằng text pointers trong Git, lưu actual files trên LFS server. Repository nhẹ hơn, clone nhanh hơn.
Câu 3: Sự khác biệt chính giữa Submodule và Subtree là gì?
- [ ] A) Submodule mới hơn Subtree
- [ ] B) Subtree không hoạt động với remote repositories
- [x] C) Submodule giữ reference đến repo ngoài, Subtree merge code trực tiếp vào repository
- [ ] D) Submodule chỉ hỗ trợ một level nesting
💡 Giải thích: Submodule giữ pointer đến commit của repo bên ngoài (separate history). Subtree copy/merge code trực tiếp vào repo chính (single history). Subtree đơn giản hơn cho consumer, Submodule cho phép hai-chiều collaboration.