45 điểm bởi GN⁺ 2026-02-24 | 2 bình luận | Chia sẻ qua WhatsApp
  • 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.gitmessage cung cấp bỏ qua các commit định dạng mã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ữ
    • 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
      
  • .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ả
    • Ví dụ:
      Jane Developer <[email protected]> <[email protected]>
      
  • 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
    • 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
      
  • 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
    • Ví dụ:
      [gerrit]
      host=review.opendev.org
      port=29418
      project=openstack/nova.git
      defaultbranch=master
      
  • .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
      
  • .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

 
wedding 2026-02-24

Tôi chưa biết về gitmessage, chắc phải thử mới được

 
GN⁺ 2026-02-24
Ý kiến trên Hacker News
  • Có người nói GitHub, GitLab và Gitea đều tôn trọng .gitignore nê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 sai
    Thự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
    • Không đúng. Nếu một tệp đã được push rồi sau đó mới thêm vào .gitignore, nó vẫn hiện trên UI. Vì tệp đó vẫn là một phần của repo
      Ngượ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
    • Đúng vậy, bình luận gốc sai. .gitignore chỉ 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ị ignore
    • Giá mà có một tùy chọn như showinwebui=(true|false) thì hay 😄
    • Tôi cảm thấy không thể nào đoạn đó do con người tự viết ra, nên tôi đã dừng đọc từ chỗ ấy
  • Tôi muốn nhấn mạnh .git/info/exclude. Đây là gitignore chỉ dành cho máy cục bộ, là cấu hình cho riêng tôi
    Ví 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
    git-ignore-local () {
      echo "$1" >> .git/info/exclude
    }
    
    Như vậy có thể thêm nhanh bằng git-ignore-local myfile.ext
    • Tôi đã làm một phiên bản ma thuật hơn để nó vẫn hoạt động dù không đứng ở thư mục gốc
      Trên MacOS chỉ cần sửa phần readlink
      git-ignore-local () {
        root=$(git rev-parse --show-toplevel)
        path=$(readlink -f "$1")
        relpath=$(relpath -m --relative-to="$root" "$path")
        echo "$relpath" >> "${root}.git/info/exclude"
      }
      
      Nếu đăng ký hàm này trong PATH với tên git-ignore-local thì có thể dùng như git ignore-local
    • .git/info/exclude cũng đã được nhắc đến ngay phần đầu của phần mô tả .gitignore
    • Đây là lần đầu tôi biết đến tính năng này. PR trong dự án của tôi từng bị rối vì các tệp tạm nhỏ kiểu này, có vẻ cái này sẽ giải quyết được
  • Nếu thêm /test export-ignore vào .gitattributes, bạn có thể loại trừ các tệp test khi deploy lên production server
    Khi 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 server
    Nó không ảnh hưởng trong lúc phát triển mà vẫn tiết kiệm được dung lượng đĩa
    • Đây là tính năng hay, nhưng có vẻ đa số mọi người thậm chí còn không biết git archive tồn tại
      Tô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-subst thì còn có thể chèn trực tiếp vào tệp những thông tin tương tự git describe
  • Khi dùng jj, tôi muốn loại trừ hoàn toàn thư mục .jj khỏi repo và mọi thao tác git
    Kể cả để git clean -xdf cũng không xóa nó. Hiện tại tôi đang tạm xử lý bằng alias git clean -e .jj
    • Chỉ cần dùng .git/info/exclude
  • Contributor graph của GitHub không hỗ trợ .mailmap
    Thảo luận liên quan có ở GitHub Community Discussion
  • Tôi nghĩ cấu hình package-lock.json merge=ours là nguy hiểm
    Vì 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-revs là 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
    • Từ git 2.52 trở đi có thể dùng tùy chọn (:optional) để không báo lỗi ngay cả khi tệp không tồn tại
      Giải thích liên quan có trong câu trả lời trên Stack Overflow
  • Nhìn chung tôi thấy đây là một danh sách được tổng hợp khá tốt
    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 quan
    Ngoài ra, .git-blame-ignore-revs chỉ là một quy ước đơn thuần, phải tự cấu hình thì mới hoạt động
  • Hơi lạc đề một chút, nhưng gần đây tôi mới biết VS Code cũng nhận diện tệp .ignore
    Trước đây tôi cứ nghĩ chỉ áp dụng .gitignore, nhưng khi thay đổi cấu hình ripgrep trong .ignore thì kết quả tìm kiếm đã khác đi. Hóa ra đây là cách hoạt động hợp lý
  • Tác giả bài viết cũng đã đăng một bài tiếp theo về forge-specific repository folders (một kiểu “thư mục ma thuật”)
    Link: bài viết trên nesbitt.io