Các tệp ma thuật của Git
(nesbitt.io)- 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,.mailmaplầ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-revsvà.gitmessagecung 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
- Những tệp này không phải cấu hình nội bộ trong
.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)
- Hỗ trợ wildcard (
- 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ằnggit 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
.gitignoretheo 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
- Ví dụ:
textdùng để chuẩn hóa xuống dòng,binaryvô hiệu hóa diff/merge,merge=oursgiữ 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
.gitattributestheo 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ữ
- Có thể cấu hình URL máy chủ LFS, số lần thử truyền lại...
- Ví dụ:
[lfs] url = https://lfs.example.com/repo [lfs "transfer"] maxretries = 3
.gitattributeschỉ đị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
- Bao gồm đường dẫn, URL, nhánh của từng module
- Ví dụ:
[submodule "vendor/lib"] path = vendor/lib url = https://github.com/example/lib.git branch = main
- Được tạo khi chạy
git submodule add, và được tham chiếu khi chạygit 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
.gitlồng nhau...
.mailmap
- Quản lý hợp nhất tên và email tác giả
- Ví dụ:
Jane Developer <[email protected]> <[email protected]>
- Ví dụ:
- 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
.mailmaphoặc cấu hìnhmailmap.file
.git-blame-ignore-revs
- Chỉ định danh sách commit sẽ bị bỏ qua trong
git blame- Loại trừ các thay đổi không mang nhiều ý nghĩa như chạy formatter, áp dụng lint
- Ví dụ:
# Ran prettier on entire codebase a1b2c3d4e5f6g7h8i9j0...
- 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
- Ví dụ:
- 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-msghoặcprepare-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.ymlhoặ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
- Ví dụ:
[gerrit] host=review.opendev.org port=29418 project=openstack/nova.git defaultbranch=master
- Ví dụ:
- .gitlint: Định nghĩa quy tắc lint cho thông điệp commit
- Ví dụ:
[general] ignore=body-is-missing [title-max-length] line-length=72
- Ví dụ:
- .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
- Dùng cùng cú pháp mẫu như
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ệnhgit 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