ไฟล์เวทมนตร์ของ Git
(nesbitt.io)- Git ควบคุมวิธีการทำงานผ่าน ไฟล์เฉพาะบางไฟล์ภายในรีโพซิทอรี ซึ่งไม่ใช่การตั้งค่าภายใน
.git/แต่เป็น ไฟล์ที่ถูกคอมมิตและย้ายไปพร้อมกับโค้ด .gitignore,.gitattributes,.lfsconfig,.gitmodules,.mailmapเป็นต้น ต่างทำหน้าที่ ยกเว้นการติดตามไฟล์, กำหนดแอตทริบิวต์, ตั้งค่า LFS, จัดการซับโมดูล, รวมข้อมูลผู้เขียน ตามลำดับ.git-blame-ignore-revsและ.gitmessageช่วย ละเว้นคอมมิตสำหรับจัดรูปแบบโค้ด และให้ เทมเพลตข้อความคอมมิต เพื่อยกระดับคุณภาพการทำงานร่วมกัน- GitHub, GitLab, Gitea เป็นต้น ขยายความสามารถผ่าน โฟลเดอร์ตั้งค่าเฉพาะแพลตฟอร์ม อย่าง
.github/,.gitlab/,.gitea/สำหรับ CI/CD, การระบุรีวิวเวอร์ และฟังก์ชันอื่น ๆ - โครงสร้างลักษณะนี้ไม่ได้มีแค่ Git แต่ยังใช้กับ EditorConfig, Docker, เครื่องมือจัดการเวอร์ชันภาษา ฯลฯ ด้วย จนเกิดเป็น ระบบนิเวศการตั้งค่าอัตโนมัติแบบ dotfile
ไฟล์เวทมนตร์หลักของ Git
- Git รู้จัก ไฟล์พิเศษหลายชนิด เช่น
.gitignore,.gitattributes,.lfsconfig,.gitmodules,.mailmapเพื่อควบคุมการทำงานของรีโพซิทอรี- ไฟล์เหล่านี้ไม่ใช่การตั้งค่าใน
.git/แต่เป็น องค์ประกอบการตั้งค่าที่ถูกคอมมิตและแชร์ร่วมกัน ช่วยให้การทำงานร่วมกันมีพฤติกรรมที่สอดคล้องกัน
- ไฟล์เหล่านี้ไม่ใช่การตั้งค่าใน
.gitignore
- กำหนด แพตเทิร์นของไฟล์ที่ Git ไม่ควรติดตาม
- รองรับไวลด์การ์ด (
*.log), ไดเรกทอรี (dist/), การยกเว้นกลับ (!important.log) เป็นต้น - ใช้งานตามลำดับ
.gitignore,.git/info/exclude, การตั้งค่าระดับโกลบอล (~/.config/git/ignore)
- รองรับไวลด์การ์ด (
- ไฟล์ที่ถูกติดตามอยู่แล้วจะยังคงถูกติดตามต่อไปแม้เพิ่ม
.gitignoreภายหลัง และสามารถลบออกจากดัชนีได้ด้วยgit rm --cached - GitHub, GitLab, Gitea เป็นต้น ยังสามารถคอมมิตไฟล์ที่ตรงกับแพตเทิร์นที่ถูก ignore ได้โดยไม่มีคำเตือน
- GitHub มีเทมเพลต
.gitignoreตามภาษาให้ใน รีโพซิทอรีทางการ
.gitattributes
- ควบคุม filter, diff, merge, การขึ้นบรรทัดใหม่, การตรวจจับภาษา แยกตามไฟล์
- เช่น
*.psd filter=lfs,*.png binary,*.sh text eol=lf
- เช่น
textใช้ทำ normalization ของการขึ้นบรรทัดใหม่,binaryปิดการทำ diff/merge,merge=oursใช้เก็บเวอร์ชันฝั่งโลคัลเมื่อเกิดคอนฟลิกต์- GitHub Linguist อ่าน
.gitattributesเพื่อทำ การตัดออกจากสถิติภาษา, พับโค้ดที่สร้างอัตโนมัติ, ตัดเอกสารออก เป็นต้น - รองรับทั้ง
.gitattributesในแต่ละไดเรกทอรีและ.git/info/attributes
.lfsconfig
- เก็บ การตั้งค่า Git LFS ไว้ให้แชร์ไปพร้อมรีโพซิทอรี
- ตั้งค่าได้ เช่น URL ของเซิร์ฟเวอร์ LFS, จำนวนครั้งในการ retry ระหว่างส่งข้อมูล
- ตัวอย่าง:
[lfs] url = https://lfs.example.com/repo [lfs "transfer"] maxretries = 3
.gitattributesใช้ระบุไฟล์ที่จะให้ LFS จัดการ ส่วน.lfsconfigดูแลรายละเอียดอย่างตำแหน่งเซิร์ฟเวอร์- หากต้องการย้ายไฟล์จากคอมมิตเดิมไปใช้ LFS ต้องใช้คำสั่ง
git lfs migrate
.gitmodules
- เก็บ ข้อมูลการตั้งค่าของซับโมดูล
- มีข้อมูล path, URL, branch ของแต่ละโมดูล
- ตัวอย่าง:
[submodule "vendor/lib"] path = vendor/lib url = https://github.com/example/lib.git branch = main
- ถูกสร้างเมื่อใช้
git submodule addและถูกอ้างอิงเมื่อใช้git submodule update - ตอน
git cloneจะไม่ดึงซับโมดูลมาให้อัตโนมัติ ต้องใช้ตัวเลือก--recurse-submodules - มีข้อเสีย เช่น ติดตามช่วงเวอร์ชันไม่ได้ และอาจเกิดไดเรกทอรี
.gitแบบซ้อนกัน
.mailmap
- ใช้ รวมชื่อและอีเมลของผู้เขียนให้เป็นรูปแบบเดียวกัน
- ตัวอย่าง:
Jane Developer <[email protected]> <[email protected]>
- ตัวอย่าง:
git log,git shortlog,git blameเป็นต้น จะแสดงชื่อที่ถูกรวมแล้ว- กราฟผู้มีส่วนร่วมของ GitHub ไม่สะท้อน mailmap
- สามารถระบุตำแหน่งได้ผ่าน
.mailmapหรือการตั้งค่าmailmap.file
.git-blame-ignore-revs
- ระบุ รายการคอมมิตที่
git blameควรละเว้น- ใช้ตัดการเปลี่ยนแปลงที่ไม่มีนัยสำคัญ เช่น การรัน formatter หรือการใช้ lint
- ตัวอย่าง:
# Ran prettier on entire codebase a1b2c3d4e5f6g7h8i9j0...
- เปิดใช้งานได้ด้วย
git config blame.ignoreRevsFile .git-blame-ignore-revs - GitHub, GitLab (15.4+), Gitea รองรับการตรวจพบอัตโนมัติ
- หากไม่มีไฟล์นี้อาจเกิดข้อผิดพลาดได้ จึงแนะนำให้คงไฟล์ว่างไว้
.gitmessage
- กำหนด เทมเพลตข้อความคอมมิต
- ตัวอย่าง:
# <type>: <subject> # # Types: feat, fix, docs, style, refactor, test, chore
- ตัวอย่าง:
- ต้องตั้งค่าด้วย
git config commit.template .gitmessage - หลัง clone แล้วต้องตั้งค่าด้วยตนเอง และบางทีมใช้ husky เป็นต้นเพื่อทำให้อัตโนมัติ
- อีกทางเลือกคือใช้ hook แบบ
commit-msgหรือprepare-commit-msg
โฟลเดอร์ส่วนขยายเฉพาะแพลตฟอร์ม
- GitHub, GitLab, Gitea, Forgejo, Bitbucket เป็นต้น ใช้ โฟลเดอร์ตั้งค่าเฉพาะของตนเอง
.github/,.gitlab/,.gitea/,.forgejo/,.bitbucket/
- ภายในอาจมี CI/CD workflow, เทมเพลต issue·PR, ไฟล์ CODEOWNERS เป็นต้น
- Forgejo มี fallback ตามลำดับ
.forgejo/ → .gitea/ → .github/ส่วน Gitea ใช้.gitea/ → .github/ - SourceHut ใช้
.build.ymlหรือ.builds/*.yml
ไฟล์ตามธรรมเนียมอื่น ๆ
- .gitkeep: เนื่องจาก Git ไม่ติดตามไดเรกทอรีว่าง จึงใช้เป็นไฟล์จำลองเพื่อคงไดเรกทอรีไว้
- .gitconfig: ใช้เป็นตัวอย่างการตั้งค่า Git ระดับโปรเจกต์ แต่จะไม่ถูกโหลดอัตโนมัติ
- .gitsigners: ใช้จัดการรายการคีย์ลายเซ็น GPG/SSH และระบุได้ผ่าน
gpg.ssh.allowedSignersFile - .gitreview: ไฟล์ตั้งค่าเซิร์ฟเวอร์รีวิวโค้ด Gerrit
- ตัวอย่าง:
[gerrit] host=review.opendev.org port=29418 project=openstack/nova.git defaultbranch=master
- ตัวอย่าง:
- .gitlint: กำหนดกฎ lint สำหรับข้อความคอมมิต
- ตัวอย่าง:
[general] ignore=body-is-missing [title-max-length] line-length=72
- ตัวอย่าง:
- .jj/: ไดเรกทอรีสถานะของ Jujutsu ซึ่งเป็น VCS ที่เข้ากันได้กับ Git และสามารถอยู่ร่วมกับ
.git/ได้
ระบบนิเวศ dotfile ที่ไปไกลกว่า Git
- .editorconfig: ช่วยคงสไตล์โค้ดให้สม่ำเสมอข้ามเอดิเตอร์
- กำหนดการเยื้อง, การขึ้นบรรทัดใหม่, การเข้ารหัส, การลบช่องว่าง เป็นต้น
- เอดิเตอร์หลักอย่าง VS Code, Vim, Emacs รองรับ
- .ruby-version, .node-version, .python-version: เครื่องมือจัดการเวอร์ชันภาษา (rbenv, nodenv, pyenv เป็นต้น) อ่านเพื่อสลับเวอร์ชันอัตโนมัติ
- .tool-versions: ไฟล์จัดการเวอร์ชันหลายภาษาของ asdf
- .dockerignore: ระบุรายการไฟล์ที่จะไม่รวมระหว่าง Docker build
- ใช้ไวยากรณ์แพตเทิร์นแบบเดียวกับ
.gitignoreช่วยเพิ่มความเร็วในการ build และกันข้อมูลลับออก
- ใช้ไวยากรณ์แพตเทิร์นแบบเดียวกับ
สิ่งที่ควรคำนึงถึงเมื่อพัฒนาเครื่องมือที่เชื่อมกับ Git
- เครื่องมือที่จัดการรีโพซิทอรี Git ควรรู้จักไฟล์ต่อไปนี้ให้ครบ
.gitignore: ใช้แพตเทิร์น ignore ระหว่างสำรวจไฟล์.gitattributes: ใช้แยกไฟล์ไบนารีและไฟล์ที่สร้างอัตโนมัติ.mailmap: ใช้แสดงข้อมูลผู้เขียนแบบรวมศูนย์.gitmodules: ใช้จัดการซับโมดูล
- รูปแบบไฟล์ตั้งค่า Git ใช้โครงสร้าง
[section "subsection"] key = valueและสามารถอ่าน/เขียนได้ด้วยคำสั่งgit config - ไลบรารี Git ของภาษาส่วนใหญ่มีความสามารถในการ parse รูปแบบนี้มาให้
2 ความคิดเห็น
ไม่เคยรู้จัก
gitmessageมาก่อนเลย แต่คงต้องลองใช้ดูแล้วความคิดเห็นบน Hacker News
.gitignoreจึงไม่แสดงไฟล์ที่ถูก ignore ในเว็บ UI แต่ดูเหมือนว่าคำอธิบายนั้นจะไม่ถูกต้องที่จริงแล้วมันไม่แสดงเพราะ ไฟล์ที่ถูก ignore ไม่ได้ถูกรวมอยู่ใน repository ต่างหาก ถ้าเป็นไฟล์ที่ถูก commit ไปแล้ว ก็ควรจะยังมองเห็นได้
.gitignoreภายหลัง มันก็ยังแสดงอยู่ใน UI เหมือนเดิม เพราะไฟล์นั้นยังคงเป็น ส่วนหนึ่งของ repoในทางกลับกัน ก็สามารถบังคับ commit ไฟล์ที่ถูก ignore ตั้งแต่แรกได้เหมือนกัน แต่ต้องใช้ทริกเล็กน้อย
.gitignoreมีหน้าที่แค่กำหนดว่าจะ ซ่อนไฟล์ที่ยัง untracked หรือไม่ เท่านั้น ถ้าต้องการก็ยัง commit ไฟล์ที่ถูก ignore ได้showinwebui=(true|false)😄.git/info/excludeมาก นี่คือ gitignore แบบใช้เฉพาะเครื่อง สำหรับการตั้งค่าของตัวเองล้วน ๆเช่น เวลาสืบหาบั๊กแล้วสร้างไฟล์ชั่วคราวไว้ และอยากเปลี่ยน branch ไปมาโดยไม่ให้ไฟล์หาย ฟีเจอร์นี้มีประโยชน์มาก
ผมทำ shell alias แบบนี้ไว้ใช้ แบบนี้ก็เพิ่มได้ง่าย ๆ ด้วย
git-ignore-local myfile.extบน MacOS แค่แก้ส่วน
readlinkเท่านั้น ถ้าลงทะเบียนฟังก์ชันนี้ไว้ใน PATH ด้วยชื่อgit-ignore-localก็จะเรียกใช้แบบgit ignore-localได้.git/info/excludeอยู่แล้วตั้งแต่ช่วงต้นของคำอธิบาย.gitignore/test export-ignoreลงใน.gitattributesก็จะ ตัดไฟล์ทดสอบออกตอน deploy ไปยัง production server ได้เวลามีเครื่องมือ deploy อย่าง Capistrano ใช้
git exportมันจะถูกนำไปใช้โดยอัตโนมัติ ทำให้ไฟล์ทดสอบไม่ถูกอัปโหลดขึ้นเซิร์ฟเวอร์ระหว่างพัฒนาก็ไม่กระทบอะไร แถมยังช่วยประหยัดพื้นที่ดิสก์ด้วย
git archiveกันเท่าไรแทบไม่เคยเห็นเครื่องมือ CI พื้นฐานใช้มันเลย ผมเพิ่งมารู้จักจากการที่ Capistrano เอามาใช้เป็นกรณีแรก
อนึ่ง ถ้าใช้ตัวเลือก
export-substก็สามารถแทรกข้อมูลคล้ายgit describeลงไปในไฟล์ได้โดยตรงด้วยjjผมอยากให้โฟลเดอร์.jjถูก ตัดออกจาก repo และจากทุกการทำงานของ git อย่างสมบูรณ์รวมถึงไม่อยากให้โดนลบจาก
git clean -xdfด้วย ตอนนี้เลยแก้ขัดด้วย aliasgit clean -e .jj.git/info/excludeได้เลย.mailmapมีการพูดคุยไว้ใน GitHub Community Discussion
package-lock.json merge=oursค่อนข้างเสี่ยงเพราะความหมายของ ours/theirs ในตอน merge หรือ rebase ไม่ชัดเจน
การตั้งค่าแบบนี้มีความหมายจริง ๆ เฉพาะกับเครื่องมือ merge อัตโนมัติเท่านั้น (เช่น git-annex branch)
อ้างอิง: คำอธิบายความหมายของ ours/theirs, โครงสร้างภายในของ git-annex
.git-blame-ignore-revsเป็นฟีเจอร์ที่ดี แต่ควรอยู่ในหมวด “ธรรมเนียมอื่น ๆ” มากกว่าถ้าไม่ได้ตั้งค่าใน git client, repository ที่ไม่มีไฟล์นี้จะทำให้ git blame ล้มเหลว
(:optional)เพื่อไม่ให้เกิด error แม้ไฟล์จะไม่มีอยู่ดูคำอธิบายได้ใน คำตอบบน Stack Overflow
แต่ก็น่าเสียดายที่ไม่ใช่ทุกเครื่องมือจะรองรับ
.mailmapเช่น IntelliJ ยังอยู่ในสถานะ บั๊ก/คำขอฟีเจอร์อีกทั้ง
.git-blame-ignore-revsก็เป็นเพียงธรรมเนียมอย่างหนึ่งเท่านั้น ต้องตั้งค่าเองถึงจะทำงาน.ignoreเหมือนกันเดิมคิดว่ามีแค่
.gitignoreที่มีผล แต่พอไปเปลี่ยน การตั้งค่า ripgrep ใน.ignoreแล้วผลการค้นหาก็เปลี่ยนไป ซึ่งพอมารู้ทีหลังก็ถือว่าสมเหตุสมผลลิงก์: บทความบน nesbitt.io