
Git là công cụ quản lý phiên bản phổ biến nhất, nhưng nhiều developer chỉ dùng các lệnh bề mặt như git add, git commit, git push. Hiểu bên trong thư mục .git giúp bạn debug lỗi, khôi phục dữ liệu mất và tối ưu repository hiệu quả. Nắm vững kiến thức này sẽ biến bạn từ người dùng cơ bản thành chuyên gia Git có thể giải quyết mọi tình huống phức tạp.
Cấu trúc thư mục .git
Thư mục .git chứa toàn bộ lịch sử và metadata của repository. Các thành phần chính:
- HEAD: con trỏ chỉ nhánh hiện tại
- config: cấu hình local của repository
- objects/: lưu trữ mọi blob, tree, commit dưới dạng SHA-1
- refs/: lưu trữ tham chiếu đến các nhánh (branches) và thẻ (tags)
- index: vùng staging, danh sách file chuẩn bị commit

Cách Git lưu trữ dữ liệu
Git không lưu trữ dữ liệu dạng delta so với commit trước như SVN. Thay vào đó, mỗi file được lưu dưới dạng blob có SHA-1 duy nhất. Nếu nội dung file không thay đổi, Git chỉ lưu một bản sao. Khi một commit được tạo, Git tạo:
- Tree object: mô tả cấu trúc thư mục và file
- Commit object: chứa author, message, timestamp, tham chiếu tree và cha
- Parent reference: kết nối commit hiện tại với commit trước đó

Cách Git nén dữ liệu
Git lưu trữ mọi object dưới dạng zlib nén trong .git/objects/. Trước khi ghi, Git tính SHA-1 40 ký tự. Nếu cùng một file được lưu nhiều lần trong các commit khác nhau, Git chỉ lưu một bản sao. Bạn có thể kiểm chứng bằng git cat-file -p để xem nội dung object.
Staging area hoạt động như thế nào
Khi chạy git add file.txt, Git lưu nội dung file dưới dạng blob trong objects/, sau đó cập nhật index (staging area) với đường dẫn và hash. File trong index chính là “staged”. Khi chạy git commit, Git đọc index, tạo tree object, tạo commit object, rồi di chuyển HEAD và nhánh hiện tại.
Relog và reflog giúp khôi phục
Mỗi thay đổi HEAD được lưu trong .git/logs/refs/. Lệnh git reflog liệt kê lịch sử tham chiếu, giúp tìm commit “đã mất” sau git reset hay rebase. Reflog tự động xóa sau khoảng 90 ngày theo cấu hình git gc.
Để khôi phục file bị xóa chưa commit, dùng git checkout HEAD~1 -- file.txt. Nếu đã commit, dùng git revert để tạo commit đảo ngược mà không thay đổi lịch sử. Với git reflog, bạn có thể tìm SHA của commit bị mất và khôi phục bằng git checkout .
Lệnh plumbing quan trọng
git cat-file: xem nội dung, loại, kích thước của một objectgit hash-object: tính SHA-1 cho file, lưu thành blobgit update-index: thêm/xóa file khỏi staging area thủ cônggit write-tree: tạo tree object từ staging areagit commit-tree: tạo commit object từ tree
Phân biệt .git và working tree
Working tree là thư mục bạn đang làm việc. .git là kho lưu trữ ẩn. Mọi thay đổi trong working tree chưa có trong .git cho đến khi add và commit. Hiểu khác biệt này giúp tránh mất dữ liệu khi xóa nhầm file.
Quy trình làm việc nhóm
Nhóm developer thường dùng workflow nhánh: tạo feature branch từ main, phát triển, rồi gộp qua pull request. Nhánh remote được lưu trong .git/refs/remotes/. git fetch cập nhật remote tracking refs mà không trộn; git pull tương đương fetch + merge. Với nhóm lớn, git worktree cho phép làm việc đồng thời trên nhiều nhánh mà không cần switch nhánh.
Các lệnh nâng cao thường dùng
git bisect: tìm commit gây lỗi bằng tìm kiếm nhị phângit cherry-pick: áp dụng một commit cụ thể từ nhánh khácgit rebase -i: viết lại lịch sử: squash, reorder, edit commitgit filter-repo: xóa file lớn, nhạy cảm khỏi lịch sử toàn bộ repo
Khi nào cần hiểu sâu .git internals
- Khôi phục sau lỗi: rebase xung đột, commit nhầm, xóa nhánh nhầm
- Tối ưu repository: xóa file lớn trong lịch sử bằng
git filter-repo - Debug CI/CD: hiểu tại sao file không được track hoặc bị bỏ qua
- Quản lý code: audit changes qua reflog, kiểm soát access
Những developer senior thường dùng lệnh plumbing để xây dựng công cụ riêng, tích hợp CI/CD, và viết script migration. Nắm vững Git internals giúp bạn tự tin dùng git reset --hard, git rebase -i, git bisect khi cần thiết. Tham khảo sách Pro Git để đào sâu hơn.
Mẹo nhanh: Khi làm việc với repo lớn, sử dụng git gc --aggressive để nén objects và giảm dung lượng disk, nhưng chỉ chạy khi không có ai khác làm việc trên repo để tránh xung đột.
