Skip to content

Cấu trúc thư mục .git/ 📁

Mục tiêu: Hiểu từng thành phần bên trong thư mục .git/ và vai trò của chúng.

Khi bạn chạy git init, Git tạo một thư mục ẩn .git/. Đây là toàn bộ repository của bạn - không có gì magic, chỉ là files và folders.


🗂️ Anatomy of .git/

.git/
├── HEAD              # Con trỏ đến branch hiện tại
├── config            # Cấu hình local repository
├── description       # Mô tả repo (GitWeb)
├── hooks/            # Scripts tự động (pre-commit, post-merge...)
├── info/             # Exclude patterns không commit
├── objects/          # 💎 DATABASE - Tất cả Blobs, Trees, Commits
│   ├── pack/         # Objects được nén (packfiles)
│   └── info/         # Pack metadata
├── refs/             # 💎 POINTERS - Branches và Tags
│   ├── heads/        # Local branches
│   ├── remotes/      # Remote-tracking branches
│   └── tags/         # Tags
├── logs/             # History của refs (cho reflog)
└── index             # Staging area (binary file)

🔑 Các thành phần quan trọng

1. HEAD - The Current Position

HEAD là một file text đơn giản chứa reference đến branch hiện tại của bạn.

bash
# Xem nội dung HEAD
cat .git/HEAD
# Output: ref: refs/heads/main

DETACHED HEAD

Khi bạn checkout một commit cụ thể (không phải branch), HEAD sẽ chứa trực tiếp SHA-1 thay vì reference. Đây gọi là detached HEAD state.

bash
# Detached HEAD
cat .git/HEAD
# Output: a1b2c3d4e5f6... (raw SHA-1)

2. objects/ - The Content Database

Đây là trái tim của Git - nơi lưu trữ tất cả data theo dạng content-addressable storage.

objects/
├── a1/
│   └── b2c3d4e5f6...  # Object với SHA-1 bắt đầu bằng "a1"
├── pack/
│   ├── pack-xxx.pack  # Packfile (nhiều objects nén)
│   └── pack-xxx.idx   # Index cho packfile
└── info/
    └── packs          # Danh sách packfiles

Cách Git lưu trữ:

  1. Mỗi object được nén bằng zlib
  2. SHA-1 hash (40 ký tự) của nội dung = tên file
  3. 2 ký tự đầu = tên thư mục, 38 ký tự còn lại = tên file
bash
# Xem một object
git cat-file -p a1b2c3d4e5f6...

# Xem loại object (blob/tree/commit/tag)
git cat-file -t a1b2c3d4e5f6...

# Xem size
git cat-file -s a1b2c3d4e5f6...

CONTENT-ADDRESSABLE STORAGE

Nếu hai files có cùng nội dung, chúng sẽ có cùng SHA-1 → Git chỉ lưu một bản duy nhất. Đây là lý do Git hiệu quả về storage.


3. refs/ - The Pointer System

Branches và tags chỉ là files text chứa SHA-1.

refs/
├── heads/
│   ├── main           # Contains: a1b2c3d4... (latest commit)
│   ├── feature/login  # Contains: e5f6g7h8...
│   └── develop        # Contains: i9j0k1l2...
├── remotes/
│   └── origin/
│       ├── main       # Remote tracking branch
│       └── develop
└── tags/
    ├── v1.0.0         # Lightweight tag (just SHA-1)
    └── v2.0.0         # Or annotated tag object
bash
# Xem một branch chỉ cụ thể đến commit nào
cat .git/refs/heads/main
# Output: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

# Tạo branch thủ công (!)
echo "a1b2c3d4..." > .git/refs/heads/my-new-branch
# Đúng vậy, branch chỉ là một file text!

4. index - The Staging Area

File binary chứa trạng thái của staged files. Đây là "vùng đệm" giữa working directory và repository.

bash
# Xem nội dung staging area
git ls-files --stage

# Output:
# 100644 a1b2c3d4... 0    src/main.py
# 100644 e5f6g7h8... 0    src/utils.py

Format: mode SHA-1 stage path


5. config - Local Configuration

File INI-style chứa cấu hình local repository.

ini
[core]
    repositoryformatversion = 0
    filemode = false
    bare = false
    logallrefupdates = true

[remote "origin"]
    url = git@github.com:user/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

[branch "main"]
    remote = origin
    merge = refs/heads/main

CẤU HÌNH ĐA TẦNG

Git có 3 levels cấu hình (ưu tiên từ cao đến thấp):

  1. Local: .git/config (repository này)
  2. Global: ~/.gitconfig (user này)
  3. System: /etc/gitconfig (toàn hệ thống)

6. logs/ - Reference Logs (Reflog)

Lưu lịch sử thay đổi của các refs. Đây là data source cho git reflog.

bash
# Xem reflog của HEAD
cat .git/logs/HEAD

# Xem reflog của một branch
cat .git/logs/refs/heads/main

🔬 Hands-on Exploration

Exercise: Khám phá Repository của bạn

bash
# 1. Tạo repo mới
mkdir git-lab && cd git-lab
git init

# 2. Xem cấu trúc .git/
tree .git  # hoặc: find .git -type f

# 3. Tạo file và commit
echo "Hello Git" > hello.txt
git add hello.txt
git commit -m "Initial commit"

# 4. Tìm blob object của hello.txt
git ls-files --stage
# Lấy SHA-1 và xem nội dung
git cat-file -p <sha1>

# 5. Xem commit object
git log --oneline
git cat-file -p HEAD

# 6. Xem tree object
git cat-file -p HEAD^{tree}

📊 Visual Summary


💡 Key Takeaways

HPN'S INSIGHT

"Toàn bộ Git chỉ là: Objects (data) + Refs (pointers) + HEAD (current position). Không có magic. Chỉ có files."

  1. .git/ là một database hoàn chỉnh - Bạn có thể copy thư mục này và có full repository
  2. Branches là files text - Chỉ chứa SHA-1 của commit
  3. Objects là immutable - Một khi tạo, không bao giờ thay đổi
  4. HEAD là current position - Cho Git biết bạn đang ở đâu
  5. Index là staging area - Cầu nối giữa working dir và repository