Git nội bộ: hiểu Git từ bên trong

Mỗi bài mổ xẻ một cơ chế bên trong Git bằng lệnh git thật và nội dung thư mục .git — không chỉ học lệnh mà hiểu vì sao Git hoạt động như vậy.

12/12 phần đã đăng Công cụ
1 Git là một cơ sở dữ liệu nội dung địa chỉ hoá: blob, tree, commit Đa số người dùng Git như một hộp đen với add/commit/push. Nhưng bên dưới, Git chỉ là một key-value store đơn giản: khoá là SHA của nội dung, giá trị là object. Bài này mổ xẻ ba loại object (blob, tree, commit) bằng lệnh git thật — tự tính ra khoá SHA của Git và chứng minh nó băm nội dung, không phải tên file. 22/09/2026 · 6 phút đọc 2 Ba vùng của Git: working directory, index (staging) và repository Ai cũng gõ git add rồi git commit, nhưng ít người biết index (staging) thực chất là gì. Bài này mổ xẻ ba vùng của Git bằng lệnh thật: index là một file nhị phân lưu SHA blob + mode + path, git add ghi blob mới và cập nhật index, và hai lệnh diff soi hai khe khác nhau — hiểu điều này giúp bạn đọc đúng git status và dùng đúng git reset. 22/09/2026 · 6 phút đọc 3 Ref, HEAD và branch trong Git: một nhánh chỉ là một con trỏ 41 byte Nhiều người tưởng tạo branch là sao chép cả dự án, nên ngại tạo nhánh. Thực ra một branch chỉ là một file 41 byte chứa SHA của commit. Bài này chứng minh bằng lệnh thật: HEAD trỏ tới ref, ref trỏ tới commit, tạo branch = ghi 41 byte, chuyển branch = đổi con trỏ HEAD — và vì sao Git khuyến khích bạn tạo nhánh thoải mái. 22/09/2026 · 5 phút đọc 4 Lịch sử Git là một DAG: commit trỏ cha, và lưu snapshot chứ không lưu diff Nhiều người tưởng Git lưu 'các thay đổi' (diff) giữa các commit. Thực ra mỗi commit lưu một ảnh chụp (snapshot) toàn bộ cây, và trỏ tới commit cha — tạo thành một đồ thị có hướng không chu trình (DAG). Bài này chứng minh bằng lệnh thật: file không đổi dùng lại cùng blob qua nhiều commit, và merge tạo commit hai cha. 22/09/2026 · 6 phút đọc 5 Merge ba chiều trong Git: base, ours, theirs — và vì sao có xung đột Nhiều người sợ merge vì không hiểu Git làm gì. Thực ra merge của Git là 'ba chiều': nó tìm commit tổ tiên chung (merge base) rồi so với hai phía để biết bên nào đã đổi gì. Bài này chứng minh bằng lệnh thật: thay đổi khác vùng tự gộp, thay đổi cùng dòng gây xung đột, và index giữ cả ba phiên bản (base/ours/theirs). 22/09/2026 · 5 phút đọc 6 Rebase trong Git: vì sao nó viết lại lịch sử — chứng minh bằng SHA thật Nhiều người dùng rebase mà không hiểu nó khác merge chỗ nào, rồi hoảng khi thấy commit 'biến mất'. Sự thật: rebase KHÔNG di chuyển commit cũ — nó tạo commit MỚI với SHA khác vì đổi parent. Bài này chứng minh bằng lệnh thật: cùng nội dung, cùng message, nhưng SHA đổi hoàn toàn; lịch sử thẳng thay vì rẽ nhánh; và commit cũ vẫn nằm trong reflog để cứu. 22/09/2026 · 6 phút đọc 7 Reflog trong Git: vì sao gần như không thao tác nào làm mất commit vĩnh viễn Nhiều người tưởng git reset --hard hay xoá nhánh là mất commit không cứu được, rồi hoảng loạn. Sự thật: Git ghi mọi lần HEAD dịch chuyển vào reflog, và commit mồ côi còn nằm trong kho hàng tuần trước khi bị gc dọn. Bài này khôi phục thật một reset --hard làm 'mất' hai commit và một nhánh đã xoá — chỉ bằng SHA đọc từ reflog. 22/09/2026 · 6 phút đọc 8 Packfile trong Git: vì sao mỗi commit là snapshot mà .git không phình vô hạn Git lưu snapshot đầy đủ mỗi commit chứ không lưu diff — nghe như thư mục .git phải nhân đôi mỗi lần sửa file lớn. Thực tế không. Bài này đo thật: 6 phiên bản của một file 622 KB, git gc gói lại chỉ còn 34 KB nhờ packfile nén delta. Mở verify-pack xem tận mắt chuỗi delta depth 1 đến 5, mỗi bản sửa chỉ tốn ~350 byte. 22/09/2026 · 6 phút đọc 9 git status và git diff so cái gì với cái gì — và cái bẫy .gitignore ai cũng dính Bạn gõ git status và git diff hàng chục lần mỗi ngày nhưng ít khi hỏi chúng so những gì. Câu trả lời nằm ở ba vùng: working tree, index, HEAD. Bài này đo thật: git diff so working với index, git diff --cached so index với HEAD, git status --short đọc bằng hai cột, và vì sao thêm file vào .gitignore không gỡ được file đã theo dõi. 22/09/2026 · 6 phút đọc 10 git bisect: tìm commit gây lỗi trong 5 lần thay vì 30 — và cách để máy tự làm Một tính năng vừa hỏng mà bạn không biết commit nào gây ra, giữa hàng trăm commit. Dò tuần tự là ác mộng. git bisect tìm nhị phân: mỗi lần chia đôi số commit khả nghi. Bài này đo thật trên 31 commit — bisect tìm ra thủ phạm chỉ sau 5 lần kiểm thử, và git bisect run để máy tự chạy hết bằng một script. 22/09/2026 · 6 phút đọc 11 cherry-pick và detached HEAD: bê một commit lẻ, và vì sao HEAD rời không đáng sợ Bạn chỉ muốn một commit hotfix từ nhánh tính năng sang main, không phải cả nhánh — đó là cherry-pick. Và trạng thái detached HEAD mà bisect/checkout hay đẩy bạn vào khiến nhiều người hoảng. Bài này đo thật: cherry-pick tạo commit mới cùng nội dung khác SHA, và một commit tạo trong detached HEAD mất hay được cứu tùy bạn có đặt tên nhánh hay không. 22/09/2026 · 6 phút đọc 12 git fetch và git push trao đổi gì với máy chủ: want, have, và pack protocol Push và fetch không gửi toàn bộ repo mỗi lần — chúng thương lượng để chỉ truyền object còn thiếu. Bài cuối sê-ri Git nội bộ mổ xẻ giao thức: ref advertisement, đàm phán want/have, rồi pack protocol gói phần thiếu. Đo thật bằng GIT_TRACE_PACKET — client nói want một SHA, have những SHA đã có, server chỉ gửi packfile chênh lệch. Và vì sao push đôi khi bị từ chối. 22/09/2026 · 6 phút đọc