Skip to main content
Case Studies

BFG Repo-Cleaner — เมื่อ Git Repository อ้วนเกินไป ลบ Secrets และไฟล์ใหญ่ออกจาก History อย่างปลอดภัย

Git เก็บทุกอย่างตลอดไป — ไฟล์ 500MB ที่ลบไปแล้ว 2 ปีก่อนยังอยู่ใน history, API key ที่ commit พลาดยังค้นเจอได้ BFG Repo-Cleaner ช่วยลบให้หมดจดเร็วกว่า git filter-branch 10-720 เท่า

19 Mar 202612 min
GitDevOpsSecurityBFG Repo-CleanerCI/CD

BFG Repo-Cleaner — เมื่อ Git Repository อ้วนเกินไป ลบ Secrets และไฟล์ใหญ่ออกจาก History อย่างปลอดภัย

ลองนึกภาพ: คุณ clone โปรเจกต์ที่ทำงาน รอ 12 นาทีกว่าจะเสร็จ หรือเช้าวันจันทร์ คุณได้อีเมลจาก GitHub แจ้งว่า API key ของบริษัทถูกเผยแพร่ต่อสาธารณะ — ทั้งๆ ที่คุณลบมันไปตั้งแต่เดือนที่แล้ว

ปัญหาเหล่านี้มีรากฐานเดียวกัน: Git เก็บทุกอย่างตลอดไป และ BFG Repo-Cleaner คือเครื่องมือที่ช่วยแก้ปัญหานี้ได้อย่างรวดเร็วและปลอดภัย


ทำไม Git Repository ถึง "อ้วน"?

Secrets และ Credentials ที่หลุดเข้าไปใน History

ทุกทีมพัฒนาซอฟต์แวร์เคยเจอสถานการณ์นี้ — ไม่ว่าจะเป็น API key, ไฟล์ .env, รหัสผ่านฐานข้อมูล หรือ private key ที่ถูก commit ไปโดยไม่ตั้งใจ สิ่งที่หลายคนไม่รู้คือ แม้คุณจะลบไฟล์เหล่านั้นและ commit ใหม่แล้ว ข้อมูลเดิมยังอยู่ใน Git history ทุกประการ ใครก็ตามที่เข้าถึง repository สามารถย้อนดู commit เก่าและเห็น secrets เหล่านั้นได้

ไฟล์ขนาดใหญ่ที่ไม่ควรอยู่ใน Git

Binary files, ไฟล์วิดีโอ, รูปภาพความละเอียดสูง, ไฟล์ build artifacts, หรือแม้แต่ node_modules ที่ถูก commit ไปโดยไม่ตั้งใจ — ไฟล์เหล่านี้ไม่ได้ถูกออกแบบมาให้เก็บใน Git ทุกครั้งที่มีคนแก้ไขหรือเพิ่มไฟล์เหล่านี้ Git จะเก็บ snapshot ใหม่ทุก version

History ที่สะสมมานาน

Repository ที่เริ่มต้นด้วยขนาด 10MB สามารถเติบโตเป็น 2GB ได้ภายในไม่กี่ปี เพราะ Git ออกแบบมาให้เป็น append-only — ทุกการเปลี่ยนแปลงถูกบันทึกและไม่มีการลบออก แม้ว่าไฟล์จะถูก "ลบ" ใน commit ล่าสุด แต่ทุก version เก่ายังคงอยู่ในฐานข้อมูลของ Git

ทำไมแค่ลบแล้ว commit ใหม่ไม่พอ?

คำตอบอยู่ที่สถาปัตยกรรมของ Git — ทุก commit คือ snapshot ที่สมบูรณ์ของโปรเจกต์ ณ จุดเวลานั้น เมื่อคุณ "ลบ" ไฟล์ คุณแค่สร้าง commit ใหม่ที่ไม่มีไฟล์นั้น แต่ commit เดิมที่มีไฟล์อยู่ยังคงอยู่ใน history ตลอดไป การจะลบข้อมูลออกจาก Git อย่างแท้จริง ต้อง rewrite history — ซึ่งเป็นสิ่งที่ BFG Repo-Cleaner ทำได้อย่างเชี่ยวชาญ


BFG Repo-Cleaner คืออะไร?

BFG Repo-Cleaner เป็นเครื่องมือ open-source ที่สร้างขึ้นโดย Roberto Tyley เพื่อ rewrite Git history อย่างรวดเร็วและปลอดภัย ชื่อ "BFG" ได้แรงบันดาลใจจากอาวุธทรงพลังในเกม Doom — เพราะมันทำลายปัญหาใน Git repository ได้อย่างรวดเร็วเช่นกัน

ความเร็วที่เหนือชั้น

จุดเด่นที่สำคัญที่สุดของ BFG คือ ความเร็ว — เร็วกว่า git filter-branch ถึง 10-720 เท่า ตามตัวเลขจาก official benchmarks ในการทดสอบกับ GCC repository ที่มี 148,495 commits การลบไฟล์เดียวด้วย BFG ใช้เวลาเพียง 3.5 นาที ในขณะที่ git filter-branch ใช้เวลาถึง 8 ชั่วโมง — เร็วกว่า 135 เท่า

เขียนด้วย Scala/Java — Cross-platform

BFG เขียนด้วย Scala ที่ทำงานบน JVM ทำให้รันได้บนทุก platform ที่ Java รองรับ ไม่ว่าจะเป็น Windows, macOS หรือ Linux

ออกแบบมาเพื่อ 2 งานหลัก

BFG ไม่ได้พยายามทำทุกอย่าง — แต่ถูกออกแบบมาเพื่อ 2 งานที่พบบ่อยที่สุด:

  1. ลบไฟล์ขนาดใหญ่ ออกจาก history ทั้งหมด
  2. ลบ secrets และ credentials ออกจากทุก commit ที่เคยมี

ความเรียบง่ายนี้ทำให้ BFG ใช้งานง่ายกว่าเครื่องมืออื่นอย่างมาก — ไม่ต้องเขียน script ซับซ้อน ไม่ต้องเข้าใจ Git internals ลึกๆ


Use Cases จริงที่เจอบ่อย

1. Leaked Credentials — เมื่อ Secrets หลุดเข้า Repository

นักพัฒนา commit ไฟล์ .env ที่มี API key, database password หรือ OAuth secret ไปยัง repository แม้จะรู้ตัวและลบออกใน commit ถัดไป แต่ ข้อมูลยังค้นเจอได้ใน history ทุกคนที่เข้าถึง repo สามารถย้อน commit และเห็น secrets เหล่านั้น BFG ช่วยลบข้อมูลเหล่านี้ออกจาก ทุก commit ในประวัติ ไม่ใช่แค่ HEAD

2. Repo Bloat — ใครสักคน Commit วิดีโอ 500MB

สถานการณ์คลาสสิก — ใครสักคนใน commit วิดีโอ demo ขนาด 500MB หรืออัพโหลด dataset ขนาดใหญ่เมื่อ 2 ปีก่อน แม้ไฟล์จะถูกลบไปแล้ว ทุกคนที่ clone repository ต้อง download ข้อมูล 500MB นั้นทุกครั้ง ทำให้ clone ใช้เวลานานมาก โดยเฉพาะในสภาพแวดล้อมที่ internet ช้า

3. Compliance — PDPA/GDPR บังคับให้ลบข้อมูลส่วนบุคคล

เมื่อข้อมูลส่วนบุคคล (PII) หลุดเข้าไปใน repository ไม่ว่าจะเป็นชื่อ-นามสกุลลูกค้า, เลขบัตรประชาชน หรืออีเมล — กฎหมาย PDPA ของไทยและ GDPR ของ EU บังคับให้ต้องลบข้อมูลเหล่านั้นให้หมดจด การลบแค่ใน commit ล่าสุดไม่เพียงพอ ต้องลบจาก ทุก commit ใน history เพื่อ compliance ที่สมบูรณ์

4. CI/CD Performance — Pipeline ช้าเพราะ Repository ใหญ่

ทุกครั้งที่ CI/CD pipeline ทำงาน ระบบต้อง clone repository ใหม่ Repository ที่ใหญ่ 2GB ทำให้ขั้นตอน clone ช้า → build ช้า → deploy ช้า → ทีมรอนาน → productivity ลด เมื่อ pipeline รันวันละ 20-50 ครั้ง เวลาที่เสียไปกับ clone สะสมเป็นชั่วโมงต่อสัปดาห์

5. Migration — ย้ายจาก Monorepo สู่ Multi-repo

เมื่อองค์กรตัดสินใจแยก monorepo ออกเป็นหลาย repository ย่อย history เก่าที่ไม่เกี่ยวข้องจะถูกนำไปด้วย ทำให้ repo ใหม่แต่ละตัวใหญ่เท่า monorepo เดิม BFG ช่วย clean history ให้เหลือเฉพาะส่วนที่เกี่ยวข้องกับ repo ใหม่

6. Storage Costs — Git Hosting คิดค่า Storage

GitHub, GitLab และ Bitbucket มีข้อจำกัดด้าน storage สำหรับแต่ละ repository และแต่ละองค์กร Repository ที่ใหญ่ผิดปกติอาจทำให้ต้องอัพเกรด plan หรือจ่ายค่า storage เพิ่ม การ cleanup repository ที่อ้วนเกินไปสามารถ ลดค่าใช้จ่ายได้โดยตรง


BFG vs git filter-branch vs git filter-repo

การเลือกเครื่องมือที่เหมาะสมสำหรับ Git history cleanup เป็นสิ่งสำคัญ แต่ละเครื่องมือมีจุดเด่นและข้อจำกัดที่แตกต่างกัน

ตารางเปรียบเทียบ

เกณฑ์ BFG Repo-Cleaner git filter-branch git filter-repo
ความเร็ว เร็วมาก (10-720x กว่า filter-branch) ช้ามาก เร็ว
ความง่ายในการใช้ ง่ายมาก — ออกแบบมาเพื่อ 2 งาน ยาก — ต้องเข้าใจ Git internals ปานกลาง
ความปลอดภัย สูง — ไม่แตะ HEAD commit ต่ำ — อาจ corrupt repo ได้ สูง
ความยืดหยุ่น จำกัด — ลบไฟล์ใหญ่/secrets สูงมาก — ทำได้ทุกอย่าง สูง
สถานะปัจจุบัน Active (maintained) Deprecated (Git ไม่แนะนำ) Active — Git official แนะนำ
ภาษา Scala (JVM) Shell script Python

ทำไม BFG ถึงเร็วกว่า?

ความลับอยู่ที่สถาปัตยกรรม — git filter-branch ทำงานแบบ sequential โดยตรวจสอบ file hierarchy ของทุก commit ทีละ commit ซึ่งเป็นวิธีที่สิ้นเปลืองมากสำหรับงานที่ต้องการแค่ลบไฟล์บางตัว

BFG ใช้ระบบ unique identification ของ Git ในการระบุไฟล์และโฟลเดอร์ แล้วประมวลผลแต่ละชิ้นเพียงครั้งเดียว ประกอบกับ multi-core parallel processing ที่ใช้ CPU ได้เต็มประสิทธิภาพ ทำให้เร็วกว่าหลายสิบถึงหลายร้อยเท่า

เมื่อไหร่ควรใช้อะไร?

  • BFG Repo-Cleaner — เหมาะที่สุดเมื่อต้องการลบไฟล์ใหญ่หรือ secrets ออกจาก history ใช้ง่าย เร็ว และปลอดภัย
  • git filter-repo — เหมาะสำหรับงาน rewrite history ที่ซับซ้อนกว่า เช่น เปลี่ยนชื่อผู้เขียน, แยก subdirectory ออกเป็น repo ใหม่ หรือปรับโครงสร้าง path ทั้งหมด Git project official แนะนำให้ใช้แทน filter-branch
  • git filter-branchไม่แนะนำให้ใช้แล้ว Git documentation เองก็เตือนว่ามี gotchas มากมายที่อาจ corrupt repository ได้

กระบวนการทำ Git History Cleanup อย่างปลอดภัย

การ rewrite Git history เป็นเรื่องที่ต้องทำอย่างระมัดระวัง เพราะผลกระทบกระจายไปถึงทุกคนในทีม นี่คือ methodology ที่เราใช้เมื่อช่วยลูกค้าทำ cleanup:

ขั้นที่ 1: สำรองข้อมูลก่อนเสมอ

ก่อนทำอะไรก็ตาม ต้อง backup repository ทั้งหมดไว้ที่อื่น ไม่ว่าจะเป็น bare clone, zip file หรือ mirror ไปยัง remote อื่น ไม่มีทางย้อนกลับได้หาก rewrite ผิดพลาด — นี่คือกฎข้อแรกที่ต้องปฏิบัติตามทุกครั้ง

ขั้นที่ 2: วิเคราะห์ว่าอะไรทำให้ Repository ใหญ่

ก่อนลงมือลบ ต้องเข้าใจก่อนว่า อะไร ที่ทำให้ repo อ้วน เครื่องมือวิเคราะห์จะช่วยระบุว่าไฟล์ไหนที่กิน storage มากที่สุดใน history ข้อมูลนี้จะช่วยวางแผนว่าจะลบอะไรบ้าง และผลลัพธ์ที่คาดหวังจะเป็นอย่างไร

ขั้นที่ 3: วางแผนว่าจะลบอะไร

สร้างรายการชัดเจนว่าจะลบไฟล์ใดบ้าง กำหนด threshold ขนาดไฟล์ (เช่น ลบทุกไฟล์ที่ใหญ่กว่า 10MB) และระบุ patterns ของ secrets ที่ต้องลบ การวางแผนที่ดีป้องกันไม่ให้ลบสิ่งที่ไม่ควรลบ

ขั้นที่ 4: ทำใน Clone แยก

อย่าทำกับ repository ที่ใช้งานจริงโดยตรง ให้ clone มาทำใน copy แยกต่างหาก เพื่อให้สามารถตรวจสอบผลลัพธ์ได้ก่อนที่จะ push กลับ

ขั้นที่ 5: ตรวจสอบผลลัพธ์

หลังจาก cleanup เสร็จ ต้องตรวจสอบว่า:

  • ขนาด repository ลดลงตามที่คาดหวัง
  • ไม่มีไฟล์หรือ secrets ที่ต้องการลบหลงเหลืออยู่
  • โปรเจกต์ยังคง build และทำงานได้ปกติ
  • History ยังคงสมเหตุสมผล

ขั้นที่ 6: Force Push — ประสานทีมก่อน

นี่คือขั้นตอนที่อันตรายที่สุด Force push จะเปลี่ยน history ของ remote repository ทั้งหมด ต้องแจ้งทุกคนในทีมล่วงหน้า ให้ทุกคน save งานที่ค้างอยู่ และกำหนดเวลาที่ชัดเจนว่าจะทำเมื่อไหร่ — ควรทำในช่วงที่ทีมไม่ได้ทำงาน เช่น ช่วงเย็นวันศุกร์หรือวันหยุด

ขั้นที่ 7: ทุกคนต้อง Re-clone

หลังจาก force push แล้ว ห้ามใช้ repo เก่า ทุกคนในทีมต้อง clone repository ใหม่ เพราะ local copy เก่ามี history ที่ไม่ตรงกับ remote แล้ว การพยายาม pull จะทำให้เกิดปัญหา

ขั้นที่ 8: Rotate Secrets ที่หลุดไป

สำคัญมาก — BFG ลบ secrets ออกจาก Git history แต่ไม่ได้หมายความว่า secrets เหล่านั้นปลอดภัย เพราะอาจมีคนเคย clone ไปแล้ว หรือ GitHub/GitLab อาจ cache commit เก่าอยู่ ต้อง rotate (เปลี่ยน) ทุก secret ที่เคยหลุดไป ทันที — เปลี่ยน API key, เปลี่ยนรหัสผ่าน, revoke token เก่า


ตัวเลขจริง — ผลลัพธ์ที่ได้จากการ Cleanup

ผลลัพธ์จากการทำ Git repository cleanup ที่เราเคยเห็นในโปรเจกต์จริง:

ขนาด Repository

ตัวชี้วัด ก่อน Cleanup หลัง Cleanup การปรับปรุง
ขนาด Repository 2.1 GB 45 MB ลด 98%
จำนวน Objects 850,000+ 120,000 ลด 86%
Pack file size 1.8 GB 38 MB ลด 98%

ความเร็วในการทำงาน

ตัวชี้วัด ก่อน Cleanup หลัง Cleanup การปรับปรุง
Clone time 12 นาที 8 วินาที เร็วขึ้น 90x
CI/CD Pipeline (clone step) 5 นาที 12 วินาที ลด 3-5 นาทีต่อ build
git fetch 45 วินาที 2 วินาที เร็วขึ้น 22x
git status 3 วินาที < 1 วินาที เร็วขึ้น 3x

ผลกระทบทางธุรกิจ

  • CI/CD savings: หากทีมรัน pipeline 30 ครั้ง/วัน ลด clone time 4 นาที/ครั้ง = ประหยัด 2 ชั่วโมง/วัน = 40 ชั่วโมง/เดือน
  • Developer productivity: ไม่ต้องรอ clone นาน ทำงานได้เร็วขึ้นทันที
  • Storage costs: ลดค่า hosting จาก repo ที่ใหญ่เกินจำเป็น
  • Onboarding: developer ใหม่ clone โปรเจกต์ได้ภายในไม่กี่วินาที แทนที่จะรอ 12 นาที

ข้อควรระวังที่ต้องรู้ก่อนทำ Cleanup

Force Push เปลี่ยน History ถาวร

เมื่อ force push แล้ว commit hash ทั้งหมดจะเปลี่ยน ซึ่งหมายความว่า:

  • ทุกคนในทีมต้อง re-clone
  • Pull requests ที่เปิดอยู่จะมี diff ที่ผิดพลาด
  • Links ไปยัง commit เก่าจะใช้ไม่ได้
  • Comments บน PR ที่อ้างอิง commit เก่าอาจหายไป

Protected Branches อาจ Block Force Push

หลาย organization ตั้ง branch protection rules ที่ห้าม force push ไปยัง main/master ต้องปิด protection ชั่วคราว ทำ force push แล้วเปิดกลับ — ซึ่งต้องมีสิทธิ์ admin

Secrets ที่หลุดไปอาจถูก Copy แล้ว

BFG ลบ secrets ออกจาก Git history ได้ แต่ ไม่สามารถลบออกจากที่อื่นได้ — ใครก็ตามที่เคย clone repo ในช่วงที่ secrets ยังอยู่ จะมี copy ของ secrets เหล่านั้นอยู่ในเครื่อง ดังนั้น ต้อง rotate secrets ทุกครั้ง ไม่มีข้อยกเว้น

GitHub/GitLab Caching

แม้ลบ secrets ออกจาก repo แล้ว GitHub และ GitLab อาจ cache commit เก่าไว้ระยะหนึ่ง ต้องติดต่อ support ของ hosting provider เพื่อขอให้ลบ cache ของ commit เก่าออก — โดยเฉพาะ GitHub ที่ commit เก่าอาจเข้าถึงได้ผ่าน URL ตรงแม้จะไม่แสดงใน history แล้ว

Fork Repositories

หาก repository มี forks อยู่ commit ที่มี secrets จะยังคงอยู่ใน forks เหล่านั้น ต้องประสานกับเจ้าของ fork ให้ลบหรือ re-fork จาก repo ที่ clean แล้ว


Best Practices — ป้องกันปัญหาตั้งแต่แรก

การ cleanup repository เป็นการแก้ปัญหาที่ปลายเหตุ วิธีที่ดีที่สุดคือ ป้องกันไม่ให้เกิดตั้งแต่แรก

.gitignore ที่ครอบคลุม

ไฟล์ .gitignore ที่ดีคือด่านป้องกันแรก ต้องครอบคลุมทุกไฟล์ที่ไม่ควรเข้า Git ไม่ว่าจะเป็น environment files, build outputs, IDE configs, binary files และ dependency directories ทบทวน .gitignore เป็นประจำ และใช้ template จาก GitHub เป็นจุดเริ่มต้น

Git Hooks สำหรับตรวจจับ Secrets

ติดตั้ง pre-commit hooks ที่สแกนหา patterns ของ secrets ก่อนที่จะอนุญาตให้ commit ได้ หาก hook ตรวจพบ API key, password หรือ private key จะบล็อก commit ทันที — เป็นการป้องกันที่ทำงานอัตโนมัติโดยไม่ต้องพึ่งวินัยของนักพัฒนาแต่ละคน

Git LFS สำหรับไฟล์ขนาดใหญ่

หากโปรเจกต์จำเป็นต้องมีไฟล์ขนาดใหญ่ (เช่น assets สำหรับเกม, ไฟล์ design, datasets) ให้ใช้ Git Large File Storage (LFS) ที่เก็บไฟล์ใหญ่แยกจาก repository หลัก โดย Git จะเก็บแค่ pointer เล็กๆ ไว้ใน repo

Secret Scanning Tools

เครื่องมือสแกน secrets อัตโนมัติเช่น GitHub Secret Scanning, GitLeaks หรือ TruffleHog สามารถตรวจสอบ repository ทั้งหมด (รวมถึง history) หา secrets ที่อาจหลุดเข้าไป บางเครื่องมือรันเป็น CI/CD step ที่ตรวจทุก commit ใหม่โดยอัตโนมัติ

Code Review ที่ครอบคลุม

Code review ไม่ควรดูแค่ logic — ต้องตรวจสอบด้วยว่ามีไฟล์ที่ไม่ควรอยู่ใน commit หรือไม่ ตรวจ .gitignore ว่าอัพเดทแล้วหรือยัง และดูว่ามี hardcoded credentials ซ่อนอยู่ในไฟล์ config หรือไม่

CI/CD Shallow Clone

สำหรับ CI/CD pipeline ที่ไม่ต้องการ history ทั้งหมด ใช้ shallow clone (clone เฉพาะ commit ล่าสุดไม่กี่ commit) เพื่อลด clone time ไม่ว่า repository จะใหญ่แค่ไหนก็ตาม วิธีนี้ไม่ได้แก้ปัญหา repo อ้วน แต่ช่วยลดผลกระทบต่อ pipeline ได้ทันที


Enersys ช่วยอะไรได้?

ทีม Enersys มีประสบการณ์ในการช่วยองค์กรจัดการปัญหา Git repository ตั้งแต่:

  • Git Repository Audit — วิเคราะห์ repository เพื่อหาไฟล์ขนาดใหญ่, secrets ที่หลุด และปัญหาอื่นๆ
  • History Cleanup — วางแผนและดำเนินการ cleanup อย่างปลอดภัย โดยมีกระบวนการที่ผ่านการทดสอบแล้ว
  • DevOps Consulting — วางระบบป้องกัน (Git hooks, secret scanning, CI/CD optimization) เพื่อไม่ให้เกิดปัญหาซ้ำ
  • Security Assessment — ตรวจสอบว่ามี secrets หลุดอยู่ใน repository ใดบ้างในองค์กร

หาก repository ของคุณใหญ่เกินไป clone ช้า หรือกังวลเรื่อง credentials ที่อาจหลุดอยู่ใน history — ติดต่อเราเพื่อปรึกษาได้ทันที


แหล่งข้อมูล

Related Articles

JMeter Use Cases ที่ใช้จริงในองค์กร — 20 สถานการณ์ทดสอบ Performance ระดับ Enterprise

รวม 20 สถานการณ์ทดสอบ Performance ด้วย JMeter ที่องค์กรใช้จริง — ตั้งแต่ Flash Sale 50,000 คนพร้อมกัน, API Gateway Stress Test, Database Connection Pool จนถึง Chaos Engineering และ SLA Compliance

JMeter ใน Pipeline + On-Demand — วิธีทดสอบ Performance ทั้งแบบอัตโนมัติและแบบสั่งรัน

องค์กรที่ตรวจจับปัญหา Performance ได้ก่อน Deploy มีโอกาสเกิด Downtime น้อยกว่า 70% — บทความนี้เปิดวิธีคิดการวาง JMeter ทั้งใน CI/CD Pipeline แบบอัตโนมัติ และ On-Demand แบบสั่งรันตามสถานการณ์

JMeter ครบทุกมิติ — คู่มือทดสอบ Performance ที่ครอบคลุมทุกรูปแบบสำหรับองค์กร

Downtime 1 ชั่วโมงอาจสูญเสียกว่า 300,000 ดอลลาร์ — บทความนี้ครอบคลุมทุกมิติของ JMeter ตั้งแต่ Load Test, Stress Test, Spike Test, Soak Test ไปจนถึง Distributed Testing และ Real-Time Monitoring

"Empowering Innovation,
Transforming Futures."

Contact us to make your project a reality.