Điều gì nếu mỗi commit git chỉ là một thư mục bạn có thể duyệt qua?
Julia Evans xây git-commit-folders: mount repo git qua NFS, mỗi commit trở thành thư mục thật sự - có thể grep, vim, hay pipe vào bất kỳ công cụ nào.

Mỗi lần muốn xem một file từ branch khác, tôi lại phải làm cái điệu múa quen thuộc. Mở notes ra. Tìm “git show file trên branch khác”. Tìm thấy câu trả lời Stack Overflow từ năm 2011. Copy lệnh. Đọc nhầm cú pháp dấu hai chấm. Lỗi. Thử lại. Cuối cùng lấy được file, cảm thấy hơi thất bại.
Tôi không tệ môn git. Não tôi chỉ từ chối ghi nhớ git show branch-khác:đường/dẫn/file.go mà thôi.
Julia Evans có vẻ gặp vấn đề tương tự. Và thay vì viết cheatsheet, bà ấy dựng cả một NFS server.
Ý tưởng cốt lõi: commit là thư mục, hãy làm nó thật sự như vậy
Commit git thực sự hoạt động như thư mục. Mỗi commit trỏ đến một tree object - về cơ bản là danh sách đệ quy các file và thư mục con. Lý do duy nhất bạn không thể duyệt ~/.git như filesystem là vì git lưu mọi thứ ở dạng binary objects để tiết kiệm dung lượng đĩa.
git-commit-folders loại bỏ lớp trừu tượng đó. Chạy nó trên một repo và nó mount một filesystem ảo, mỗi commit hash trở thành một thư mục thật:
$ ls commits/8d/8dc0/8dc0cb0b4b0de3c6f40674198cb2bd44aeee9b86/
README
$ ls commits/c9/c94e/c94e6f531d02e658d96a3b6255bbf424367765e9/
_config.yml config.rb Rakefile rubypants.rb source
Branch và tag chỉ là symlink trỏ đến thư mục commit:
$ ls -l branches/
lrwxr-xr-x main -> ../commits/04/043e/043e90debbeb0fc6b4e28cf8776e874aa5b6e673
lrwxr-xr-x feature-x -> ../commits/91/912d/912da3150d9cfa74523b42fae028bbb320b6804f
Giờ thì bài toán “xem file trên branch khác” trở thành:
vim branches/branch-khac/go.mod
Không cần nhớ cú pháp git. Chỉ là đường dẫn file.
Tại sao cách này lại có ích (dù git grep đã tồn tại)
Julia thẳng thắn thừa nhận đây không phải cách hiệu quả nhất. git show, git log -S, git grep đều có sẵn. Nhưng:
| Tác vụ | Cách git thường | Cách dùng filesystem |
|---|---|---|
| Tìm hàm đã xóa | git log -S 'funcName' --all -- file.go |
grep -r funcName branch_histories/main/*/file.go |
| Xem file trên branch khác | git show branch:đường/dẫn/file |
vim branches/branch-khac/đường/dẫn/file |
| Tìm kiếm trên tất cả branch | git grep pattern $(git branch -a) |
grep -r pattern branches/*/commit.go |
Lệnh git mạnh hơn - có thể lọc theo ngày, tác giả, nội dung patch. Nhưng cách dùng filesystem thì không cần nhớ gì hết. Mọi công cụ bạn đã biết (grep, find, diff, vim) đều hoạt động ngay.
Nhưng kỹ thuật không đơn giản chút nào
Julia muốn cái này chạy được trên macOS mà không cần kernel extension. Điều đó loại FUSE ra khỏi danh sách. Hai giao thức filesystem native còn lại trên macOS là WebDAV và NFS.
Bà thử WebDAV trước. Thư viện chuẩn Go có sẵn WebDAV. Trông khả thi. Rồi gặp bẫy: x/net/webdav dùng io/fs, mà io/fs không hỗ trợ symlink. Branch sẽ phải là thư mục thật thay vì symlink - phá vỡ toàn bộ mental model.
Vậy là chuyển sang NFS. NFSv3 cụ thể, qua thư viện go-nfs.
Kết quả là một nhật ký kỹ thuật sâu 9 vấn đề:
- Vấn đề 3 (liệt kê hàng triệu commit): Tổ chức theo 2 ký tự prefix, giống cách
.git/objectslàm, rồi cache toàn bộ hash commit đã pack vào memory. Hoạt động được trên Linux kernel với ~1 triệu commit. Mất khoảng một phút khởi động lần đầu, sau đó cập nhật nhanh. - Vấn đề 4 (lỗi “Not a directory”): Đây là cách NFS báo bất kỳ lỗi liệt kê thư mục nào, không phải sai kiểu dữ liệu. Phải dùng Wireshark mới chẩn đoán được.
- Vấn đề 5 (inode numbers): Julia vô tình đặt mọi inode thư mục về 0.
findnhận ra khi mọi thư mục có cùng inode và từ chối đệ quy, cho rằng có vòng lặp filesystem - điều này hoàn toàn hợp lý. - Vấn đề 6 (stale file handles): Vẫn chưa giải quyết được. NFS cần map 64-byte opaque handles sang file đúng, nhưng thư viện go-nfs dùng cache cố định bị tràn trên repo lớn.
Đây là điều tôi thích ở cách Julia viết: bà không dọn dẹp đống thất bại. Bài viết đọc như nhật ký debug, và những thứ chưa sửa được vẫn nằm nguyên trong danh sách.
Tại sao HN đào lại bài này vào năm 2026
Người submit (pvtmert) nói thẳng:
“Given the advent of LLMs and agentic coding, I believe this article needs re-visiting as it makes it much more discoverable to compare individual files across commits.”
Đây mới là góc nhìn thú vị. AI coding agent không vất vả với cú pháp git show - nhưng lại gặp khó với các lệnh git plumbing tùy tiện không được biểu diễn kỹ trong training data, hoặc cần parse binary output. Một filesystem thuần túy mà mọi công cụ đều đọc được là interface đơn giản hơn nhiều cho agent đang điều hướng qua lịch sử code.
Thread HN cũng nhắc đến ClearCase (hệ thống version control doanh nghiệp ra đời trước git) có thứ tương tự: bạn có thể truy cập foo.c@@/versions/5 như một đường dẫn thông thường. Fossil cũng có lệnh fusefs làm điều này.
Và một commenter, steveBK123, tóm gọn sự hoài nghi trong ba chữ:
“NFS.. stop right there”
Không phải không có lý. NFS nổi tiếng với những edge case kỳ lạ. Nhưng khi phương án thay thế là FUSE với kext hoặc không-xây-gì-hết, lựa chọn của Julia hoàn toàn ổn.
Nên xem không?
Đọc bài gốc nếu:
- Bạn viết công cụ điều hướng lịch sử git bằng code
- Bạn tò mò về cách object model của git ánh xạ lên filesystem
- Bạn xây AI coding tools và đang nghĩ về cách agent truy cập context code cũ
- Bạn là fan Julia Evans và muốn xem ai đó ghi lại cẩn thận 9 cách NFS làm khó cuộc sống
Bỏ qua nếu:
git showvàgit log -Sđã nằm trong cơ bắp bạn rồi- Bạn cần truy cập lịch sử git cho môi trường production (có công cụ VFS tốt hơn)
- Repo của bạn có hàng triệu commit và bạn không muốn chờ 1 phút mỗi lần khởi động
Dự án này thực nghiệm và Julia nói thẳng điều đó. Nhưng công cụ thực nghiệm giúp bạn hiểu cách thứ gì đó vận hành thường là loại tốt nhất.
Thảo luận trên Hacker News · Nguồn: jvns.ca · Đăng bởi pvtmert
Bài viết liên quan
Tencent BrowserSkill Là Gì: Cho AI Dùng Chung Trình Duyệt Không Cướp Chuột
Tencent BrowserSkill kết nối AI agent với Chrome mà không cướp chuột hay bắt đăng nhập lại. Cơ chế mượn tab thông minh, vượt captcha và giữ nguyên bảo mật.
Nuôi Tôm AI 0 Đồng: Biến Laptop Vỡ Màn Thành Server Kỹ Sư Tự Trị 24/7
Biến laptop LG Gram vỡ màn thành server homelab tự trị 24/7 với 0 đồng: pin chống sập, Bubblewrap xoay tua quota Google, cày code cho thằng chủ rảnh tay đi cà phê.
Claude Blog Giải Thích: Cỗ Máy Viết Bài Tự Động 5 Vòng Kiểm Duyệt
Mổ xẻ AgriciDaniel/claude-blog: kiến trúc 32 sub-skills, 5 subagent, và bộ Delivery Contract 5 cửa chặn đứng bài viết rác từ LLM trước khi tới tay người dùng.
SEO Machine Giải Thích: Cỗ Máy Nội Dung Tăng Trưởng B2B SaaS
Mổ xẻ TheCraigHewitt/seomachine: cách workspace Claude Code kết hợp dữ liệu GSC, DataForSEO và 10 context file để biến bài blog kỹ thuật thành doanh thu MRR.