- Git điều khiển cách hoạt động thông qua các tệp cụ thể trong kho lưu trữ, và đây là những tệp được commit và di chuyển cùng mã nguồn chứ không phải cấu hình bên trong
.git/
.gitignore, .gitattributes, .lfsconfig, .gitmodules, .mailmap lần lượt đảm nhiệm loại trừ theo dõi tệp, định nghĩa thuộc tính, cấu hình LFS, quản lý submodule, hợp nhất tác giả
.git-blame-ignore-revs và .gitmessage cung cấp bỏ qua các commit định dạng mã và mẫu thông điệp commit, giúp nâng cao chất lượng cộng tác
- GitHub, GitLab, Gitea... mở rộng tính năng như CI/CD, chỉ định reviewer thông qua các thư mục cấu hình riêng theo nền tảng như
.github/, .gitlab/, .gitea/
- Cấu trúc này còn được áp dụng ngoài Git, trong EditorConfig, Docker, các công cụ quản lý phiên bản ngôn ngữ..., hình thành nên hệ sinh thái tự động cấu hình dựa trên dotfile
Các tệp ma thuật chính của Git
- Git nhận diện nhiều tệp đặc biệt như
.gitignore, .gitattributes, .lfsconfig, .gitmodules, .mailmap để điều khiển hành vi của kho lưu trữ
- Những tệp này không phải cấu hình nội bộ trong
.git/ mà là thành phần cấu hình được commit và chia sẻ, giúp đảm bảo hành vi nhất quán khi cộng tác
.gitignore
- Định nghĩa mẫu tệp không nên bị Git theo dõi
- Hỗ trợ wildcard (
*.log), thư mục (dist/), phủ định (!important.log) v.v.
- Được áp dụng theo thứ tự
.gitignore, .git/info/exclude, cấu hình toàn cục (~/.config/git/ignore)
- Các tệp đã được theo dõi từ trước vẫn tiếp tục bị theo dõi ngay cả sau khi thêm vào
.gitignore, và có thể gỡ bằng git rm --cached
- GitHub, GitLab, Gitea... vẫn cho phép commit các tệp khớp mẫu bị bỏ qua mà không cảnh báo
- GitHub cung cấp các mẫu
.gitignore theo ngôn ngữ tại kho lưu trữ chính thức
.gitattributes
- Điều khiển filter, diff, merge, xuống dòng, nhận diện ngôn ngữ theo từng tệp
- Ví dụ:
*.psd filter=lfs, *.png binary, *.sh text eol=lf
text dùng để chuẩn hóa xuống dòng, binary vô hiệu hóa diff/merge, merge=ours giữ phiên bản cục bộ khi xảy ra xung đột
- GitHub Linguist đọc
.gitattributes để loại khỏi thống kê ngôn ngữ, thu gọn mã sinh ra, loại trừ tài liệu v.v.
- Đồng thời nhận diện
.gitattributes theo từng thư mục và .git/info/attributes
.lfsconfig
- Chia sẻ cấu hình Git LFS cùng với kho lưu trữ
.gitattributes chỉ định các tệp được xử lý bằng LFS, còn .lfsconfig đảm nhiệm các thiết lập chi tiết như vị trí máy chủ
- Để chuyển các tệp trong commit cũ sang LFS, cần dùng lệnh
git lfs migrate
.gitmodules
- Lưu thông tin cấu hình submodule
- Được tạo khi chạy
git submodule add, và được tham chiếu khi chạy git submodule update
- Khi
git clone, Git không tự động lấy submodule; cần tùy chọn --recurse-submodules
- Có nhược điểm như không thể theo dõi dải phiên bản, tạo thư mục
.git lồng nhau...
.mailmap
- Quản lý hợp nhất tên và email tác giả
- Hiển thị tên đã hợp nhất trong
git log, git shortlog, git blame...
- Biểu đồ contributor của GitHub không phản ánh mailmap
- Có thể chỉ định vị trí bằng
.mailmap hoặc cấu hình mailmap.file
.git-blame-ignore-revs
- Chỉ định danh sách commit sẽ bị bỏ qua trong
git blame
- Kích hoạt bằng
git config blame.ignoreRevsFile .git-blame-ignore-revs
- GitHub, GitLab (15.4+), Gitea tự động nhận diện
- Nếu tệp không tồn tại có thể phát sinh lỗi, nên duy trì một tệp rỗng
.gitmessage
- Định nghĩa mẫu thông điệp commit
- Ví dụ:
# <type>: <subject>
#
# Types: feat, fix, docs, style, refactor, test, chore
- Cần cấu hình bằng
git config commit.template .gitmessage
- Sau khi clone vẫn cần thiết lập thủ công; một số đội dùng husky... để tự động hóa
- Ngoài ra có thể dùng hook
commit-msg hoặc prepare-commit-msg
Các thư mục mở rộng theo nền tảng
- GitHub, GitLab, Gitea, Forgejo, Bitbucket... dùng thư mục cấu hình riêng
.github/, .gitlab/, .gitea/, .forgejo/, .bitbucket/
- Chứa workflow CI/CD, mẫu issue·PR, tệp CODEOWNERS v.v.
- Forgejo fallback theo thứ tự
.forgejo/ → .gitea/ → .github/, còn Gitea là .gitea/ → .github/
- SourceHut dùng
.build.yml hoặc .builds/*.yml
Các tệp quy ước khác
- .gitkeep: Git không theo dõi thư mục rỗng, nên tệp này được dùng như tệp giả để giữ lại thư mục
- .gitconfig: Có thể cung cấp ví dụ cấu hình Git theo dự án, nhưng không được tự động nạp
- .gitsigners: Quản lý danh sách khóa ký GPG/SSH, có thể chỉ định bằng
gpg.ssh.allowedSignersFile
- .gitreview: Tệp cấu hình máy chủ review mã Gerrit
- .gitlint: Định nghĩa quy tắc lint cho thông điệp commit
- .jj/: Thư mục trạng thái của Jujutsu, một VCS tương thích Git, có thể tồn tại cùng
.git/
Hệ sinh thái dotfile vượt ra ngoài Git
- .editorconfig: Giữ phong cách mã nhất quán giữa các editor
- Định nghĩa thụt lề, xuống dòng, mã hóa, loại bỏ khoảng trắng thừa...
- Được hỗ trợ bởi các editor lớn như VS Code, Vim, Emacs
- .ruby-version, .node-version, .python-version: Được các công cụ quản lý phiên bản ngôn ngữ (rbenv, nodenv, pyenv...) đọc để tự động chuyển phiên bản
- .tool-versions: Tệp quản lý phiên bản đa ngôn ngữ của asdf
- .dockerignore: Chỉ định danh sách tệp cần loại trừ khi build Docker
- Dùng cùng cú pháp mẫu như
.gitignore, giúp tăng tốc độ build và loại trừ thông tin bí mật
Những điểm cần lưu ý khi phát triển công cụ tích hợp Git
- Công cụ xử lý kho Git cần обязательно nhận diện các tệp sau
.gitignore: áp dụng mẫu bỏ qua khi duyệt tệp
.gitattributes: phân biệt tệp nhị phân và tệp sinh ra
.mailmap: hiển thị hợp nhất thông tin tác giả
.gitmodules: xử lý submodule
- Định dạng tệp cấu hình Git có cấu trúc
[section "subsection"] key = value, và có thể đọc/ghi bằng lệnh git config
- Hầu hết thư viện Git cho các ngôn ngữ đều cung cấp khả năng parse định dạng này
2 bình luận
Tôi chưa biết về
gitmessage, chắc phải thử mới đượcÝ kiến trên Hacker News
.gitignorenên không hiển thị các tệp bị bỏ qua trên web UI, nhưng có vẻ đây là cách giải thích saiThực ra, chúng không hiện ra vì các tệp bị bỏ qua không được đưa vào repository. Nếu là tệp đã được commit thì đúng ra vẫn phải hiện
.gitignore, nó vẫn hiện trên UI. Vì tệp đó vẫn là một phần của repoNgược lại, cũng có thể ép commit một tệp bị ignore ngay từ đầu, nhưng cần một chút mẹo
.gitignorechỉ quyết định có ẩn các tệp untracked hay không. Nếu muốn thì vẫn có thể commit các tệp bị ignoreshowinwebui=(true|false)thì hay 😄.git/info/exclude. Đây là gitignore chỉ dành cho máy cục bộ, là cấu hình cho riêng tôiVí dụ khi điều tra bug, tôi tạo các tệp tạm và muốn giữ nguyên chúng kể cả khi đổi branch thì tính năng này rất hữu ích
Tôi dùng shell alias như dưới đây Như vậy có thể thêm nhanh bằng
git-ignore-local myfile.extTrên MacOS chỉ cần sửa phần
readlinkNếu đăng ký hàm này trong PATH với têngit-ignore-localthì có thể dùng nhưgit ignore-local.git/info/excludecũng đã được nhắc đến ngay phần đầu của phần mô tả.gitignore/test export-ignorevào.gitattributes, bạn có thể loại trừ các tệp test khi deploy lên production serverKhi các công cụ deploy như Capistrano dùng
git export, quy tắc này sẽ được áp dụng tự động nên tệp test không bị đưa lên serverNó không ảnh hưởng trong lúc phát triển mà vẫn tiết kiệm được dung lượng đĩa
git archivetồn tạiTôi hầu như không thấy nó được dùng trong các công cụ CI cơ bản. Capistrano là ví dụ đầu tiên tôi biết có tận dụng nó
Nhân tiện, nếu dùng tùy chọn
export-substthì còn có thể chèn trực tiếp vào tệp những thông tin tương tựgit describejj, tôi muốn loại trừ hoàn toàn thư mục.jjkhỏi repo và mọi thao tác gitKể cả để
git clean -xdfcũng không xóa nó. Hiện tại tôi đang tạm xử lý bằng aliasgit clean -e .jj.git/info/exclude.mailmapThảo luận liên quan có ở GitHub Community Discussion
package-lock.json merge=ourslà nguy hiểmVì khi merge hay rebase thì ý nghĩa của ours/theirs không rõ ràng
Kiểu cấu hình này chỉ có ý nghĩa trong các công cụ merge tự động hóa, ví dụ như git-annex branch
Tham khảo: giải thích ý nghĩa ours/theirs, cấu trúc bên trong git-annex
.git-blame-ignore-revslà tính năng tốt, nhưng nó nên thuộc phần “các quy ước khác”Nếu không cấu hình trong git client thì ở các repo không có tệp đó, git blame sẽ thất bại
(:optional)để không báo lỗi ngay cả khi tệp không tồn tạiGiải thích liên quan có trong câu trả lời trên Stack Overflow
Chỉ tiếc là không phải mọi công cụ đều hỗ trợ
.mailmap. Ví dụ IntelliJ hiện vẫn đang ở trạng thái bug/yêu cầu tính năng cho chức năng liên quanNgoài ra,
.git-blame-ignore-revschỉ là một quy ước đơn thuần, phải tự cấu hình thì mới hoạt động.ignoreTrước đây tôi cứ nghĩ chỉ áp dụng
.gitignore, nhưng khi thay đổi cấu hình ripgrep trong.ignorethì kết quả tìm kiếm đã khác đi. Hóa ra đây là cách hoạt động hợp lýLink: bài viết trên nesbitt.io