คู่มือ

ไฟล์ .gitignore: วิธีไม่ให้ Git ติดตามไฟล์และนำไฟล์ที่เพิ่มแล้วออก

อัปเดต: · Skillaria.Top

ไฟล์ .gitignore ที่รากของรีโพซิทอรีระบุรูปแบบของไฟล์และโฟลเดอร์ที่ Git จะไม่ติดตาม เช่น dependencies ไฟล์บิลด์ ล็อก และความลับ มีผลเฉพาะกับไฟล์ที่ยังไม่ถูกติดตาม ดังนั้นไฟล์ที่คอมมิตไปแล้วต้องนำออกจากดัชนีด้วยคำสั่ง git rm --cached

git ignore คือวิธีบอก Git ว่า "อย่าแตะไฟล์เหล่านี้ อย่าแสดงใน git status และอย่าเพิ่มผ่าน git add ." กฎเขียนไว้ในไฟล์ข้อความชื่อ .gitignore ซึ่งถูกคอมมิตไปพร้อมโปรเจกต์และใช้ได้กับทั้งทีม ประเด็นสำคัญคือ การละเว้นมีผลเฉพาะกับไฟล์ที่ Git ยังไม่ได้ติดตาม

สิ่งที่มักใส่ใน .gitignore

  • Dependencies: node_modules/, vendor/, .venv/ เพราะตัวจัดการแพ็กเกจกู้คืนได้เสมอ
  • ผลลัพธ์จากการบิลด์: dist/, build/, *.class, __pycache__/
  • ล็อกและไฟล์ชั่วคราว: *.log, tmp/, *.swp
  • ความลับและการตั้งค่าในเครื่อง: .env, คีย์, คอนฟิกส่วนตัว
  • ไฟล์ขยะจากระบบปฏิบัติการและเอดิเตอร์: .DS_Store, Thumbs.db, .idea/ แม้ว่าควรเก็บไว้ในการละเว้นทั่วทั้งเครื่อง ซึ่งจะอธิบายด้านล่าง

กฎง่าย ๆ: ในรีโพซิทอรีควรมีสิ่งที่คนเขียน ไม่ใช่สิ่งที่โปรแกรมสร้างหรือขึ้นกับเครื่องใดเครื่องหนึ่ง

วิธีสร้าง .gitignore

เป็นไฟล์ข้อความธรรมดาที่รากของรีโพซิทอรี สร้าง ใส่รูปแบบทีละบรรทัด และคอมมิต:

cat > .gitignore <<'EOF'
# dependencies
node_modules/
# ไฟล์บิลด์
dist/
# ล็อก
*.log
# ความลับ
.env
EOF

git add .gitignore
git commit -m "chore: เพิ่ม .gitignore"

เทมเพลตพร้อมใช้สำหรับภาษาและเฟรมเวิร์กยอดนิยมมีอยู่ในรีโพซิทอรี github/gitignore GitHub และ GitLab ก็ให้เลือกเทมเพลตเมื่อสร้างโปรเจกต์ ใช้เป็นพื้นฐานแล้วตัดส่วนที่ไม่จำเป็นออก

ไวยากรณ์ของรูปแบบใน .gitignore

รูปแบบสิ่งที่ละเว้น
*.logไฟล์นามสกุล .log ในทุกโฟลเดอร์
build/โฟลเดอร์ build ในทุกระดับ (เครื่องหมายทับท้ายหมายถึงเฉพาะโฟลเดอร์)
/buildเฉพาะ build ที่รากเท่านั้น (ทับนำหน้าผูกกับโฟลเดอร์ของ .gitignore)
docs/*.pdfpdf ที่อยู่ใน docs โดยตรง แต่ไม่รวม docs/old/
docs/**/*.pdfpdf ใน docs และโฟลเดอร์ย่อยทั้งหมด
**/temptemp ในทุกโฟลเดอร์
!keep.logข้อยกเว้น: ไม่ละเว้น keep.log
file?.txt? คืออักขระใดก็ได้หนึ่งตัว
[ab].txta.txt หรือ b.txt
# คอมเมนต์บรรทัดคอมเมนต์

ข้อควรรู้: รูปแบบที่ไม่มีทับอยู่ข้างใน (config.json) ทำงานกับทุกระดับ ส่วนรูปแบบที่มีทับนำหน้าหรือตรงกลาง (/config.json, src/config.json) จะอ้างอิงจากโฟลเดอร์ที่มีไฟล์ .gitignore นี้

ข้อยกเว้นด้วยเครื่องหมายอัศเจรีย์

*.log
!important.log

กับดัก: ไม่สามารถ "คืน" ไฟล์ได้หากโฟลเดอร์แม่ถูกละเว้น Git ไม่เข้าไปในโฟลเดอร์ที่ถูกละเว้น จึงใช้ไม่ได้:

logs/
!logs/keep.txt     # ไม่ทำงาน

วิธีที่ถูกต้องคือละเว้นเนื้อหาแทนโฟลเดอร์:

logs/*
!logs/keep.txt

เทคนิคเดียวกันใช้เก็บโฟลเดอร์ว่างไว้ในรีโพซิทอรี เนื่องจาก Git ไม่เก็บไดเรกทอรีว่าง จึงใส่ไฟล์ .gitkeep ไว้ข้างใน และอนุญาตเฉพาะไฟล์นี้

ตั้งค่าการละเว้นที่อื่นได้อีก

ตำแหน่งมีผลกับเข้ารีโพซิทอรีหรือไม่
.gitignore ที่รากและโฟลเดอร์ย่อยทั้งทีมใช่
.git/info/excludeเฉพาะโคลนนี้ไม่
ไฟล์ส่วนกลาง core.excludesFileรีโพซิทอรีทั้งหมดของคุณไม่

ขยะของระบบปฏิบัติการและ IDE ควรนำไปไว้ในการละเว้นส่วนกลางเพื่อไม่ให้ .gitignore ทั่วไปรก:

git config --global core.excludesFile ~/.gitignore_global
echo ".DS_Store" >> ~/.gitignore_global
echo ".idea/" >> ~/.gitignore_global

หากไม่ได้ตั้ง core.excludesFile Git จะอ่าน ~/.config/git/ignore หากไฟล์นั้นมีอยู่

ทำไม .gitignore ถึงไม่ทำงาน

ข้อร้องเรียนที่พบบ่อยที่สุดคือ "เพิ่มไฟล์ลงใน .gitignore แล้ว แต่ Git ยังแสดงการเปลี่ยนแปลง" สาเหตุเกือบทุกครั้งคือไฟล์นั้นถูกติดตามอยู่แล้ว การละเว้นไม่มีผลกับไฟล์ที่เคยเข้าสู่คอมมิต

หากต้องการตรวจว่ากฎใดทำงาน (หรือทำไมไม่ทำงาน) ใช้ git check-ignore:

git check-ignore -v logs/app.log
# .gitignore:3:*.log	logs/app.log

ผลลัพธ์แสดงไฟล์และบรรทัดของกฎ หากไม่มีผลลัพธ์ แปลว่าไฟล์ไม่ถูกละเว้น อีกสาเหตุหนึ่งของความล้มเหลวคือมีช่องว่างท้ายบรรทัดของรูปแบบ หรือไฟล์มี encoding ผิด (เช่น UTF-16 เมื่อสร้างผ่าน PowerShell)

นำไฟล์ที่คอมมิตแล้วออกจากรีโพซิทอรี: git rm --cached

คำสั่ง git rm ลบไฟล์ออกจากดัชนีและจากดิสก์ เมื่อใช้แฟล็ก --cached จะลบออกจากดัชนีเท่านั้น ไฟล์ยังอยู่ในเครื่องของคุณแต่หยุดถูกติดตาม

echo ".env" >> .gitignore
git rm --cached .env
git commit -m "chore: .env ไม่ถูกติดตามแล้ว"
git push

สำหรับโฟลเดอร์ต้องใช้ -r:

git rm -r --cached node_modules/

หากมีกฎจำนวนมากและไม่แน่ใจว่าอะไรเข้ารีโพซิทอรีไปแล้ว สามารถสร้างดัชนีใหม่ทั้งหมดได้: git rm -r --cached . จากนั้น git add . และคอมมิต ก่อนคอมมิตให้ตรวจ git status จะเห็นไฟล์ที่ถูกนำออกจากดัชนี

คำเตือน: ความลับยังอยู่ในประวัติ

git rm --cached นำไฟล์ออกจากคอมมิตถัดไป แต่ไม่ได้นำออกจากคอมมิตเดิม หากรหัสผ่านหรือโทเคนหลุดเข้ารีโพซิทอรี มันจะเข้าถึงได้ผ่านประวัติสำหรับทุกคนที่มีโคลน ต้องถือว่าความลับนั้นถูกเปิดเผยและออกใหม่ การเขียนประวัติใหม่ทำได้ด้วยเครื่องมืออย่าง git filter-repo แต่จะเปลี่ยนแฮชของทุกคอมมิตหลังจากนั้น และต้องประสานงานกับทีม

ผลที่ตามมาอีกอย่าง: เพื่อนร่วมทีมที่ทำ git pull หลังจากไฟล์ถูกนำออกจากดัชนีด้วย --cached จะพบว่าไฟล์ถูกลบออกจากดิสก์ของพวกเขาด้วย สำหรับ .env ให้แจ้งทีมล่วงหน้า หรือเก็บเทมเพลต .env.example ไว้ในรีโพซิทอรี

git rm: การลบไฟล์

git rm old.py              # ลบจากดิสก์และจากดัชนี
git rm -r legacy/          # ลบโฟลเดอร์
git rm -n '*.tmp'          # dry run: แสดงสิ่งที่จะถูกลบ
git rm -f changed.py       # ลบไฟล์ที่มีการแก้ไขที่ยังไม่คอมมิต

หากลบไฟล์ด้วย rm ธรรมดา Git จะเห็นว่าไฟล์ "deleted" และการลบต้องถูกเพิ่มผ่าน git add หรือ git rm git rm ทำสองขั้นตอนนี้พร้อมกัน หากไม่ใส่ -f มันจะปฏิเสธการลบไฟล์ที่มีการแก้ไขที่ยังไม่คอมมิต ซึ่งเป็นการป้องกันการสูญเสียงาน

git mv: การเปลี่ยนชื่อและย้ายไฟล์

git mv utils.py helpers.py
git mv helpers.py src/helpers.py

git mv คือ mv + git rm ของพาธเดิม + git add ของพาธใหม่ Git ไม่เก็บข้อมูลว่ามีการเปลี่ยนชื่อ แต่คำนวณจากความคล้ายของเนื้อหาเมื่อแสดง git status, git log --follow และ git diff ดังนั้นการใช้ git mv และการใช้ mv ตามด้วย git add -A ให้ผลเหมือนกัน

คำแนะนำเชิงปฏิบัติ: เปลี่ยนชื่อและแก้เนื้อหาไฟล์ในคอมมิตที่ต่างกัน หากไฟล์เปลี่ยนไปมากพร้อมกับการเปลี่ยนชื่อ Git อาจไม่รู้จักว่าเป็นไฟล์เดิม และประวัติด้วย --follow จะขาดตอน

สำหรับการเปลี่ยนเฉพาะตัวพิมพ์ใหญ่เล็กของชื่อบน Windows และ macOS (ระบบไฟล์ที่ไม่สนใจตัวพิมพ์) ใช้ git mv readme.md README.md เพราะการเปลี่ยนชื่อธรรมดาใน File Explorer อาจไม่ถูกสังเกตโดย Git

ลำดับกฎและความสำคัญ

ภายในไฟล์เดียวกันกฎอ่านจากบนลงล่าง และกฎที่ตรงกันล่าสุดชนะ ดังนั้นข้อยกเว้น !keep.log ต้องอยู่ต่ำกว่ากฎ *.log มิฉะนั้นจะถูกทับ ระหว่างไฟล์ ลำดับความสำคัญคือ: .gitignore ในโฟลเดอร์ย่อยมีความสำคัญกว่าที่ราก ส่วนการละเว้นส่วนกลางและ .git/info/exclude มีความสำคัญต่ำที่สุด

ตัวอย่าง .gitignore สำหรับเว็บโปรเจกต์

ด้านล่างคือเวอร์ชันที่ใช้งานได้จริงสำหรับโปรเจกต์ Node.js ที่มีแบ็กเอนด์ Python ให้สังเกตคอมเมนต์ ผ่านไปครึ่งปีจะไม่มีใครจำได้ว่าทำไมต้องมีกฎแต่ละข้อ

# --- dependencies ---
node_modules/
.venv/

# --- บิลด์และแคช ---
/dist
/build
__pycache__/
*.pyc
.pytest_cache/
coverage/

# --- ล็อก ---
*.log
npm-debug.log*

# --- สภาพแวดล้อมและความลับ ---
.env
.env.*
!.env.example

# --- ไฟล์ที่ผู้ใช้อัปโหลด แต่เก็บโฟลเดอร์ไว้ ---
uploads/*
!uploads/.gitkeep

ที่นี่ใช้เทคนิคข้อยกเว้นทั้งสองแบบ: .env.* ซ่อนไฟล์สภาพแวดล้อมในเครื่องทั้งหมด แต่เทมเพลต .env.example ยังอยู่ในรีโพซิทอรี และโฟลเดอร์ uploads มีอยู่ในโคลนเพราะมี .gitkeep

สิ่งที่ไม่ควรละเว้น

การละเว้นมากเกินไปก็เป็นอันตราย ไฟล์ล็อกของ dependencies อย่าง package-lock.json, poetry.lock, composer.lock โดยทั่วไปถูกคอมมิตในแอปพลิเคชัน เพราะรับประกันว่านักพัฒนาทุกคนและ CI ติดตั้งแพ็กเกจเวอร์ชันเดียวกัน การตั้งค่าการจัดรูปแบบร่วม (.editorconfig และคอนฟิกของลินเตอร์) ก็ควรอยู่ในรีโพซิทอรี

กรณีที่ถกเถียงกันคือการตั้งค่า IDE โฟลเดอร์ .vscode/ มักถูกละเว้นทั้งหมด แต่บางครั้งคอมมิตคำแนะนำส่วนขยายและงานบิลด์: .vscode/* แล้วตามด้วย !.vscode/extensions.json การตัดสินใจเป็นของทีม สิ่งสำคัญคืออย่าเก็บพาธส่วนตัวและคีย์ในรีโพซิทอรีร่วม

สถานการณ์: คอมมิต node_modules โดยไม่ตั้งใจ

ความผิดพลาดคลาสสิกของมือใหม่: รัน git add . ก่อนสร้าง .gitignore ทำให้ไฟล์หลายหมื่นไฟล์เข้าคอมมิต วิธีแก้มีสามขั้นตอน:

echo "node_modules/" >> .gitignore
git rm -r --cached node_modules
git commit -m "chore: นำ node_modules ออกจากรีโพซิทอรีแล้ว"

หากคอมมิตยังไม่ได้ส่งขึ้นเซิร์ฟเวอร์ ควรเขียนคอมมิตใหม่เพื่อไม่ให้ไฟล์หนัก ๆ ค้างในประวัติ: git reset --soft HEAD~1 แล้วรันคำสั่งชุดเดิมและคอมมิตใหม่ หลังจาก push ไฟล์อยู่ในประวัติแล้ว และขนาดของโคลนจะไม่ลดลงหากไม่เขียนประวัติใหม่

เพื่อไม่ให้เกิดเหตุการณ์แบบนี้ซ้ำ ให้สร้าง .gitignore ก่อน git add ครั้งแรก และตรวจ git status ก่อนคอมมิตทุกครั้ง รายการไฟล์ใหม่ที่ยาวผิดปกติคือสัญญาณให้หยุด

สรุป

ไฟล์ .gitignore คือไฟล์แรกที่ควรคอมมิตในโปรเจกต์ใหม่ ไม่ต้องให้ dependencies บิลด์ ล็อก และความลับเข้ารีโพซิทอรี การละเว้นทำงานเฉพาะกับไฟล์ที่ยังไม่ถูกติดตาม ดังนั้นสิ่งที่ถูกเพิ่มไปแล้วให้นำออกด้วย git rm --cached และตรวจกฎด้วย git check-ignore -v สำหรับการลบและเปลี่ยนชื่อใช้ git rm และ git mv เพื่อให้การเปลี่ยนแปลงเข้าดัชนีทันที การทำงานกับดัชนีและรีโพซิทอรีแรกถูกอธิบายและฝึกจริงในหลักสูตร Git

คำถามที่พบบ่อย

ต้องคอมมิตไฟล์ .gitignore เองหรือไม่?

ใช่ เพื่อให้กฎมีผลกับทั้งทีม ส่วนข้อยกเว้นส่วนตัวใส่ไว้ใน .git/info/exclude หรือการละเว้นส่วนกลาง

มีไฟล์ .gitignore หลายไฟล์ได้หรือไม่?

ได้ วางไว้ในโฟลเดอร์ย่อยใดก็ได้ กฎจะอ้างอิงจากโฟลเดอร์นั้นและเสริมกฎที่ราก

จะเพิ่มไฟล์ที่ถูกละเว้นเข้าคอมมิตได้อย่างไร?

ใช้ git add -f พาธ/ของไฟล์ หลังจากนั้นไฟล์จะถูกติดตาม และ .gitignore จะไม่มีผลกับไฟล์นั้นอีก

จะดูไฟล์ที่ถูกละเว้นทั้งหมดในโปรเจกต์ได้อย่างไร?

รัน git status --ignored หรือ git ls-files --others --ignored --exclude-standard

จะหยุดติดตามการเปลี่ยนแปลงของไฟล์ที่คอมมิตแล้วชั่วคราวได้อย่างไร?

ใช้ git update-index --skip-worktree ไฟล์ แต่เป็นการตั้งค่าในเครื่อง และไม่ใช่ทางเลือกแทน .gitignore

เรียนหัวข้อนี้ผ่านวิดีโอ

หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Git с нуля до уверенного разработчика”

ไปที่คอร์ส