Skip to content

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 --merge

Submodule 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 --remote

Remove 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.git

COMMON PITFALL

Sau khi git pull main repo, luôn chạy:

bash
git submodule update --init --recursive

Nế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 prune

Real-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-hotfix

Worktree Use Cases

ScenarioWorktree Solution
Fix urgent bug mid-featureTạo worktree cho hotfix branch
Test two versions side-by-sideWorktree cho main và develop
Review PR mà không làm gián đoạn workWorktree checkout PR branch
Long-running experimentWorktree 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 536870912

Workflow


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 -text

LFS Considerations

AspectDetails
StorageGitHub: 1GB free, 50GB với $5/mo data pack
BandwidthGitHub: 1GB/mo free, paid tiers available
CI/CDCần git lfs install + git lfs pull trong pipeline
SubmodulesLFS 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

CommandPurpose
git submodule add <url> <path>Add submodule
git submodule update --init --recursiveInitialize & update
git submodule update --remoteUpdate to latest
git submodule foreach '<cmd>'Run command in all
git submodule statusCheck versions

Worktrees

CommandPurpose
git worktree add <path> <branch>Create worktree
git worktree add -b <new> <path> <base>Create with new branch
git worktree listList all worktrees
git worktree remove <path>Remove worktree
git worktree pruneCleanup stale

LFS

CommandPurpose
git lfs installSetup LFS
git lfs track "<pattern>"Track file pattern
git lfs ls-filesList tracked files
git lfs pullDownload LFS files
git lfs migrate importMigrate existing files

💡 Key Takeaways

HPN'S INSIGHT

"Submodules cho shared code, Worktrees cho parallel work, LFS cho binaries. Đúng tool cho đúng problem."

  1. Submodules lưu pointers: Main repo chỉ track commit SHA, không phải code
  2. Always --recursive: git submodule update --init --recursive là bạn tốt
  3. Worktrees share objects: Không duplicate data, instant checkout
  4. LFS là mandatory cho binaries: Files >10MB nên dùng LFS
  5. CI/CD needs setup: Submodules và LFS cần explicit commands trong pipelines

CHOOSE WISELY

ProblemWrong ToolRight Tool
Shared libraryCopy-pasteSubmodule
Parallel branchesStashWorktree
Large binariesRegular commitLFS
Forked customizationSubmoduleSubtree or fork