Mổ xẻ thư mục .git: Hiểu Objects, Refs và Index để ‘cứu’ code như chuyên gia

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Đừng coi thư mục .git là một “hộp đen” bí ẩn

Hầu hết chúng ta thường gõ git add, git commit rồi git push theo bản năng. Mọi chuyện vẫn êm đẹp cho đến khi bạn lỡ tay git reset --hard hoặc force push nhầm, khiến toàn bộ commit quan trọng trên branch chính biến mất trong tích tắc.

Mình từng thức trắng đêm để tìm cách cứu một branch chưa kịp push lên server. Sau những lần “đau thương” đó, mình nhận ra Git không hề khó hiểu. Thực chất, nó là một hệ thống quản lý nội dung (content-addressable filesystem) cực kỳ logic. Nắm vững những gì diễn ra bên trong folder .git sẽ giúp bạn làm chủ mọi tình huống oái oăm nhất, thay vì phải xóa repo và clone lại từ đầu.

Thực hành: Soi nội dung .git trong 2 phút

Cách tốt nhất để học là nhìn tận mắt. Hãy tạo một repo trống và kiểm tra cấu trúc mặc định ngay trên terminal của bạn:

mkdir git-lab && cd git-lab
git init
ls -F .git/

Bạn sẽ thấy các thành phần cốt lõi hiện ra:

  • HEAD: File định danh branch hiện tại bạn đang đứng.
  • config: Nơi lưu các thiết lập local, ví dụ như thông tin remote URL.
  • objects/: Kho lưu trữ vĩnh viễn mọi phiên bản file và commit.
  • refs/: Danh sách các con trỏ dẫn tới các commit (nhánh và tag).
  • hooks/: Các script tự động chạy khi bạn commit hoặc push.

Bây giờ, hãy thử tạo một thay đổi nhỏ:

echo "Học Git từ gốc" > README.md
git add README.md
git commit -m "Initial commit"

Sau lệnh này, thư mục objects/ sẽ không còn trống rỗng. Git đã bắt đầu băm (hash) nội dung file của bạn thành các dãy mã SHA-1 duy nhất.

Ba trụ cột tạo nên sức mạnh của Git

1. Git Objects: Xương sống của dữ liệu

Git không lưu các bản vá (diff) nhỏ lẻ. Thay vào đó, nó lưu các bản snapshot hoàn chỉnh. Có 3 loại object bạn cần phân biệt rõ:

  • Blob: Lưu nội dung file. Git không quan tâm tên file là gì, nó chỉ quan tâm bên trong file có gì.
  • Tree: Đóng vai trò như một thư mục, liên kết các Blob với tên file cụ thể.
  • Commit: Chứa thông tin tác giả, thời gian và ID của một Tree đại diện cho snapshot tại thời điểm đó.

Mỗi object được định danh bằng mã SHA-1 gồm 40 ký tự. Git thông minh ở chỗ lấy 2 ký tự đầu làm tên thư mục và 38 ký tự còn lại làm tên file. Cách làm này giúp hệ điều hành truy xuất file nhanh hơn khi dự án của bạn lên tới hàng chục nghìn object.

Dùng lệnh này để “đọc vị” bất kỳ object nào:

# Kiểm tra loại object
git cat-file -t [SHA-1_HASH]

# Xem nội dung thực tế bên trong
git cat-file -p [SHA-1_HASH]

2. Refs: Những cái tên thay cho mã hash khó nhớ

Việc nhớ mã e69de29... là bất khả thi. Refs sinh ra để giải quyết việc này. Một branch thực chất chỉ là một file văn bản nặng vài byte, chứa mã hash của commit mới nhất.

Thử mở file .git/refs/heads/main, bạn sẽ thấy nó trỏ đúng tới commit cuối cùng. Khi bạn tạo branch mới, Git không copy code; nó chỉ tạo thêm một file text nhỏ trỏ tới cùng một commit. Đó là lý do tại sao tạo branch trong Git lại nhanh đến mức gần như tức thì.

3. The Index: Vùng đệm chiến thuật

File .git/index là một file nhị phân ghi lại trạng thái của staging area. Tại sao Git lại bắt chúng ta phải git add rườm rà?

Index cho phép bạn chuẩn bị commit một cách tỉ mỉ. Bạn có thể sửa 5 file nhưng chỉ chọn lọc các thay đổi ở 2 file để commit trước. Điều này giữ cho lịch sử dự án luôn sạch sẽ, dễ theo dõi thay vì một đống hỗn độn các thay đổi không liên quan.

Kỹ thuật phục hồi: Reflog và Garbage Collection

Qua thời gian, objects/ sẽ chứa cả những dữ liệu thừa từ các commit đã bị xóa. Git định kỳ chạy git gc (Garbage Collection) để nén dữ liệu vào các Packfiles, giúp giảm dung lượng repo từ vài trăm MB xuống còn vài chục MB.

Nếu lỡ tay xóa nhầm code, Reflog chính là “phao cứu sinh” cuối cùng. Mọi thay đổi của con trỏ HEAD đều được ghi lại tại .git/logs/.

git reflog

Màn hình sẽ hiện ra danh sách các hành động gần đây kèm mã hash. Bạn chỉ cần tìm lại mã hash trước thời điểm xảy ra lỗi và dùng git reset --hard [HASH] để đưa mọi thứ trở lại trạng thái ban đầu.

Kinh nghiệm thực tế khi xử lý folder .git

  • Hạn chế sửa file trực tiếp: Bạn có thể sửa file config, nhưng tuyệt đối đừng chạm vào nội dung trong objects nếu không muốn làm hỏng toàn bộ cấu trúc repo.
  • Quản lý dung lượng: Nếu folder .git phình to bất thường (ví dụ > 1GB cho một project web), hãy kiểm tra xem bạn có lỡ commit file media lớn hay thư mục node_modules không.
  • Dọn dẹp triệt để: Khi cần xóa hoàn toàn một file nhạy cảm (như file .env chứa mật khẩu) khỏi lịch sử, hãy dùng các công cụ chuyên dụng như filter-repo thay vì chỉ xóa và commit mới.
  • Chia sẻ code an toàn: Khi nén code gửi cho đối tác, hãy nhớ loại bỏ folder .git để tránh rò rỉ các phiên bản cũ hoặc các ghi chú commit mang tính nội bộ.

Hiểu về cấu trúc bên trong không giúp bạn gõ code nhanh hơn, nhưng nó mang lại sự tự tin của một kỹ sư thực thụ. Khi nắm được cơ chế vận hành của Git, bạn sẽ không còn sợ hãi trước những dòng báo lỗi đỏ rực hay những pha mất code hy hữu nữa.

Nếu bạn đang gặp một ca “mất code” khó nhằn, đừng ngần ngại mô tả tình huống dưới phần bình luận, mình sẽ hỗ trợ bạn tìm lại mã hash sớm nhất!

Share: