Git 3.0 เตรียมเปลี่ยน branch เริ่มต้นเป็น main และ hash เป็น SHA-256 ใน repo ใหม่ สิ่งที่ต้องระวังคือสคริปต์ที่อิงค่าเริ่มต้นเดิม
Git 3.0 ยังไม่ออก แต่มีแผนให้ repo ใหม่ใช้ main, SHA-256 และ reftable จุดที่ต้องระวังคือสคริปต์ที่ถือว่า branch ชื่อ master หรือ hash ยาว 40 ตัวอักษร

ระบบจัดการเวอร์ชันโค้ดอย่าง Git 3.0 กำลังจะเปลี่ยนสิ่งคุ้นตาที่นักพัฒนาเห็นกันอยู่ทุกวันไป 2 อย่าง นั่นคือ รหัส commit hash ความยาว 40 ตัวอักษรใน git log และชื่อ branch เริ่มต้นที่เคยชื่อ master
เมื่อสร้าง repo หรือคลังเก็บโค้ดใหม่ด้วย Git 3.0 ค่า hash จะเปลี่ยนมายาว 64 ตัวอักษร และ branch แรกจะใช้ชื่อว่า main เป็นค่าเริ่มต้น
แต่ตอนนี้ Git 3.0 ยังไม่ได้ปล่อยออกมา เวอร์ชันล่าสุดบนเว็บไซต์ทางการ git-scm.com ยังอยู่ที่ 2.56.0 เท่านั้น
ทีมพัฒนาใช้หน้าเอกสาร BreakingChanges บันทึกแผนการเปลี่ยนแปลงของ Git 3.0 ที่อาจกระทบการทำงานเดิม และหน้านี้ก็ระบุไว้ชัดเจนว่ายังไม่มีกำหนดวันปล่อยอย่างเป็นทางการ
การอัปเกรดเวอร์ชันใหญ่ที่เปลี่ยนเยอะขนาดนี้ นานๆ Git จะมีสักครั้ง โดยครั้งล่าสุดคือ Git 2.0 เมื่อเดือนพฤษภาคม 2014
ทุกหัวข้อในหน้า BreakingChanges ยังเป็นเพียงแผนงานที่ทีม Git ประกาศไว้ล่วงหน้า และยังไม่ใช่ข้อสรุปตายตัว เพราะเอกสารระบุไว้เองว่าเรื่องที่ตัดสินใจไปแล้วก็ยังนำกลับมาทบทวนใหม่ได้
ข่าวดีคือ การเปลี่ยนแปลงหลักส่วนใหญ่มีผลเฉพาะค่าเริ่มต้นของ repo ที่สร้างขึ้นใหม่ สิ่งที่มีโอกาสพังจริงๆ คือ สคริปต์ CI สำหรับทดสอบและ build อัตโนมัติ รวมถึงเครื่องมือต่างๆ ที่เคยเขียนโค้ดเดาค่าเริ่มต้นเอาไว้ เช่น เดาว่า branch แรกต้องชื่อ master เสมอ หรือ commit hash จะต้องยาว 40 ตัวอักษรเท่านั้น นอกจากนี้ก็มีคำสั่งเก่าอีกไม่กี่ตัวที่จะตัดออกไป
main กับ SHA-256 สองเรื่องแรกที่จะได้เจอ

ในหน้า BreakingChanges ปัจจุบันมีแผนการเปลี่ยนแปลงหลักอยู่ 5 ข้อ เรื่องแรกที่ทุกคนจะสังเกตเห็นก่อนคือชื่อ branch เริ่มต้น
ทุกวันนี้ถ้าเราสั่ง git init โดยไม่ระบุชื่อ branch เราจะได้ branch แรกชื่อ master และเอกสารของ git init ก็ระบุไว้แล้วว่าค่าเริ่มต้นนี้จะเปลี่ยนเป็น main เมื่อ Git 3.0 ออกมา
เรื่องนี้ไม่ใช่เรื่องใหม่ Git เคยแจ้งเตือนล่วงหน้ามาตั้งแต่เดือนธันวาคม 2020 แล้ว และชื่อ main ก็ตรงกับที่บริการฝาก repo สำหรับทำงานร่วมกันอย่าง Git forge เจ้าใหญ่ๆ หลายเจ้าใช้เป็นค่าเริ่มต้นอยู่แล้ว
เรื่องที่สองคือสูตรคำนวณ hash สำหรับ repo ใหม่ จะเปลี่ยนจาก SHA-1 เป็น SHA-256 โดย Git ใช้ค่า hash เป็นตัวระบุ commit และข้อมูลทุกชิ้นที่จัดเก็บไว้ รหัสแบบ SHA-1 จะยาว 40 ตัวอักษร ส่วนแบบ SHA-256 จะยาว 64 ตัวอักษร
เหตุผลที่ต้องเปลี่ยนคือ SHA-1 ปลอดภัยน้อยลงเรื่อยๆ โดย NIST หน่วยงานกำหนดมาตรฐานของสหรัฐฯ ประกาศเลิกแนะนำให้ใช้ SHA-1 มาตั้งแต่ปี 2011 และหลังจากนั้นก็มีงานวิจัยที่โจมตีระบบสำเร็จตามมาหลายครั้ง
ตัวอย่างที่เห็นภาพชัดที่สุดคือการโจมตี SHAttered ในปี 2017 ที่สามารถสร้างไฟล์ PDF สองไฟล์ที่มีเนื้อหาไม่เหมือนกัน แต่ได้ค่า hash SHA-1 ตรงกันเป๊ะ สำหรับระบบอย่าง Git ที่ใช้ hash เป็นตัวระบุข้อมูล การที่ค่า hash ชนกันแบบนี้หมายความว่า Git อาจมองไฟล์คนละไฟล์เป็นข้อมูลชุดเดียวกัน
ที่ผ่านมา Git มีระบบป้องกันการโจมตีรูปแบบนี้อยู่แล้ว โดยตั้งแต่เวอร์ชัน 2.13.0 Git ได้เปลี่ยนมาใช้ Hardened SHA-1 หรือ SHA-1 รุ่นเสริมความปลอดภัย เป็นค่าเริ่มต้น ซึ่งป้องกันการโจมตีแบบ SHAttered ได้
แต่ทีมพัฒนามองว่าในอนาคตอาจมีงานวิจัยที่ค้นพบวิธีโจมตีแบบใหม่ๆ อีก จึงต้องเตรียมแผนเปลี่ยนผ่านไว้ล่วงหน้า
จุดสำคัญที่ต้องเข้าใจคือ การเปลี่ยนค่าเริ่มต้นไม่ได้หมายความว่าจะเลิกใช้ SHA-1 โดยเอกสารระบุชัดเจนว่าตอนนี้ยังไม่มีแผนตัด SHA-1 ทิ้ง ส่วนเงื่อนไขสำคัญก่อนจะเปลี่ยนค่าเริ่มต้นคือ library, แอปพลิเคชัน และ forge ต่างๆ ที่นิยมใช้งานจะต้องรองรับ SHA-256 ให้เรียบร้อยก่อน
แค่ cd เข้าโฟลเดอร์ก็อาจโดนเล่นงานได้
เรื่องที่สามเป็นประเด็นด้านความปลอดภัยเกี่ยวกับ bare repo ซึ่งเป็น repo ที่เก็บเฉพาะข้อมูลระบบโดยไม่มีโฟลเดอร์ทำงานปกติ โดยเราสามารถตั้งคำสั่งอัตโนมัติอย่าง hook เอาไว้ให้ทำงานเมื่อเกิดเหตุการณ์ตามที่กำหนดได้
รูปแบบการโจมตีของช่องโหว่นี้มี 3 ขั้นตอน:
- ผู้โจมตีหลอกให้เรา clone repo ที่แอบฝัง bare repo ไว้ในโฟลเดอร์ย่อย และฝัง hook อันตรายไว้ข้างในนั้น
- เมื่อเราเข้าไปในโฟลเดอร์ย่อยนั้นแล้วรันคำสั่ง Git อะไรก็ได้ Git จะค้นหาโฟลเดอร์ย้อนขึ้นไปจนเจอ bare repo ตัวนั้น แล้วสั่งรัน hook ทันที
- ยิ่งไปกว่านั้น เราอาจไม่ต้องพิมพ์คำสั่ง Git เองด้วยซ้ำ เพราะ shell prompt ในหน้าต่าง terminal หลายตัวมักรัน
git statusอยู่เบื้องหลังเพื่อดึงชื่อ branch และสถานะไฟล์ที่ยังไม่ commit มาแสดง ซึ่งคำสั่งgit statusก็อาจเรียก fsmonitor hook ขึ้นมาทำงานได้ถ้าตั้งค่าไว้ ทำให้แค่เราcdเข้าไปในโฟลเดอร์ สคริปต์อันตรายก็อาจทำงานได้ทันที
Git 3.0 จึงเปลี่ยนค่าเริ่มต้นของ safe.bareRepository จาก all เป็น explicit หมายความว่า Git จะไม่ยอมทำงานกับ bare repo ที่ค้นเจอเองระหว่างไล่โฟลเดอร์อีกต่อไป ถ้าต้องการใช้ bare repo จะต้องระบุพาธตรงๆ ผ่านออปชัน --git-dir หรือตัวแปรสภาพแวดล้อม GIT_DIR เท่านั้น ส่วน repo ทั่วไปที่มีโฟลเดอร์ .git รวมถึง Git worktree และ submodule จะไม่ได้รับผลกระทบใดๆ
reftable กับ Rust สองเรื่องเบื้องหลังที่เปลี่ยนไป
เรื่องที่สี่คือ วิธีจัดเก็บตัวชี้ตำแหน่ง commit อย่าง ref (เช่น ชื่อ branch หรือ tag) ใน repo ใหม่ จะเปลี่ยนจากรูปแบบไฟล์เดิมไปเป็น reftable
เรื่องที่ห้าคือการ build หรือคอมไพล์ Git จะต้องติดตั้ง Rust ไว้ในเครื่องด้วย ข้อนี้กระทบเฉพาะคนที่ build Git ใช้เองและผู้ดูแลแพ็กเกจของระบบปฏิบัติการ โดยทีม Git ได้วางแผนเปลี่ยนผ่านทีละขั้นดังนี้:
- 2.49: เริ่มมีส่วนที่เขียนด้วย Rust เข้ามา แต่ยังเปิดเป็นทางเลือก
- 2.55: เปิดใช้ Rust เป็นค่าเริ่มต้น หากเครื่องที่ build ไม่มี Rust จะคอมไพล์ไม่ผ่าน เว้นแต่จะระบุ build flag เพื่อสั่งปิดเอง
- 3.0: ตัดตัวเลือกสั่งปิดทิ้ง ทำให้ Rust กลายเป็นข้อกำหนดบังคับ
ตลอดช่วงการเปลี่ยนผ่าน ทีม Git ได้เตรียมแผนรับมือไว้สองทาง โดยเวอร์ชันสุดท้ายก่อนเข้าสู่ 3.0 จะเป็นรุ่น LTS ที่ดูแลระยะยาว ซึ่งจะมีอัปเดตแก้บั๊กสำคัญอย่างน้อย 4 รอบ release และออกแพตช์ความปลอดภัยให้อีก 6 รอบ นอกจากนี้ หากประเมินแล้วพบว่าส่งผลกระทบต่อ Linux distro ต่างๆ มากเกินไป ทีมงานก็อาจเลื่อนการบังคับใช้ Rust ออกไปเป็นเวอร์ชันย่อยหลังจากนั้น
คำสั่งที่จะถูกตัดออก และ git checkout ที่ยังอยู่ต่อ
นอกจาก 5 เรื่องหลักข้างต้นแล้ว Git 3.0 ยังมีแผนตัดคำสั่งและฟีเจอร์เก่าออกอีกหนึ่งชุด ซึ่งเกือบทุกตัวมีแนวทางใหม่มาทดแทนเรียบร้อยแล้ว
| คำสั่งหรือฟีเจอร์ที่จะตัดออก | คำสั่งหรือแนวทางที่แนะนำให้ใช้แทน |
|---|---|
git whatchanged | ใช้ git log --raw ซึ่งแสดงผลใกล้เคียงกัน |
git pack-redundant | ตัดออกถาวร เนื่องจากทีม Git ระบุว่าทำงานช้าจนไม่เหมาะกับการใช้งานจริง |
| Grafts หรือระบบแก้ไขประวัติ commit เฉพาะในเครื่องตัวเอง | เปลี่ยนไปใช้ git replace |
โฟลเดอร์ .git/branches/ และ .git/remotes/ | กำหนด remote ผ่าน config ของ repo แทน |
git name-rev --stdin | เปลี่ยนไปใช้ git name-rev --annotate-stdin |
core.commentString=auto | ยกเลิกการรองรับ |
core.preferSymlinkRefs=true | บันทึก symbolic ref เป็นไฟล์ข้อความธรรมดาแทน (ส่วน symlink เดิมยังอ่านได้) |
สองคำสั่งแรกควรตรวจในสคริปต์ทันที เพราะตอนนี้ทั้ง git whatchanged และ git pack-redundant ไม่ยอมทำงานแล้วถ้าไม่ใส่แฟล็ก --i-still-use-this ต่อท้าย ดังนั้นสคริปต์ไหนที่ยังเรียกสองคำสั่งนี้แบบเดิมๆ ก็จะเริ่มพังตั้งแต่ตอนนี้โดยไม่ต้องรอถึง Git 3.0
อีกจุดที่ชวนสับสนคือ git checkout เพราะมีทั้งคำสั่งสลับ branch อย่าง git switch และคำสั่งคืนค่าไฟล์อย่าง git restore ที่ทำแทนได้ครบแล้ว แต่เอกสารทางการยืนยันชัดเจนว่า git checkout ไม่ได้อยู่ในรายการที่จะตัดออก และทั้งสามคำสั่งจะยังคงอยู่ต่อไป เนื่องจาก checkout ยังเป็นคำสั่งที่คนใช้กันอย่างแพร่หลาย
origin master กับ origin/master ต่างกันตรงไหน

ลองสังเกตสองคำสั่งนี้:
git fetch origin master
git switch -c my-feature origin/masterทำไมคำสั่งแรกถึงเขียนแยกวรรคเป็น origin master แต่คำสั่งที่สองกลับเขียนติดกันด้วยเครื่องหมายทับเป็น origin/master?
คำถามนี้มาจากบทความ On Git Refs ที่ matklad นักพัฒนาซอฟต์แวร์เขียนไว้เมื่อ 7 ตุลาคม 2026 คำตอบของคำถามนี้จะช่วยให้เราเข้าใจเรื่องตัวชี้ตำแหน่งอย่าง Git reference หรือ ref ได้อย่างชัดเจน
นอกจากพื้นที่เก็บ commit ที่ใช้ค่า hash เป็นรหัสระบุแล้ว Git ยังมีตารางข้อมูลอีกชุดที่ปรับแก้ค่าได้ โดยฝั่งหนึ่งคือชื่อ และอีกฝั่งคือ hash ที่ชี้ไปยังข้อมูลใน Git (เช่น commit) ชื่อที่อยู่ในตารางนี้เราเรียกว่า ref ซึ่งมีรูปแบบลำดับชั้นคล้ายกับพาธของไฟล์
branch ที่เราเรียกกันสั้นๆ ว่า my-feature แท้จริงแล้วคือ ref ชื่อเต็มว่า refs/heads/my-feature ส่วน tag หรือ git notes ก็จัดเก็บเป็น ref ในลักษณะเดียวกัน
ส่วน origin/master เป็นชื่อย่อของ refs/remotes/origin/master ซึ่งใช้จดไว้ในเครื่องเราว่า ตอนที่สั่ง fetch ครั้งล่าสุด branch master บนเซิร์ฟเวอร์ปลายทาง (remote ที่ชื่อ origin) ชี้อยู่ที่ commit ไหน
Git ต้องแยกเก็บแบบนี้เพราะออกแบบมาให้ทำงานแบบออฟไลน์เป็นหลัก โดยจะซิงก์ข้อมูลกับเครื่องอื่นเฉพาะตอนที่เราสั่ง fetch หรือ push เท่านั้น Git จึงต้องจดจำไว้ในเครื่องว่าสถานะของฝั่ง remote ล่าสุดเป็นอย่างไร นอกจากนี้ การแยกเก็บตามชื่อ remote ยังช่วยป้องกันไม่ให้ชื่อ ref จากคนละแหล่งมาชนกัน เช่น กรณีที่เรา fork โปรเจกต์ออกมาทำงานเทียบกับ repo ต้นฉบับ
เมื่อเข้าใจโครงสร้างนี้แล้ว เราก็จะได้คำตอบของคำถามตอนต้นทันที:
- ในคำสั่งแรก
git fetch origin master: คำว่าoriginกับmasterเป็นข้อมูลคนละชิ้นกัน โดยoriginบอกว่าจะไปดึงข้อมูลจาก repo ไหน (Git จะไปเปิดหา URL จาก.git/config) ส่วนmasterคือชื่อ ref บนเซิร์ฟเวอร์ปลายทาง เมื่อดึงข้อมูลมาเสร็จ Git จะนำมาอัปเดตลงในrefs/remotes/origin/masterในเครื่องเรา - ในคำสั่งที่สอง
git switch -c my-feature origin/master: คำว่าorigin/masterเป็นชื่อเดียวทั้งก้อน คือชื่อย่อของ ref ในเครื่องเราเอง ซึ่งใช้เป็นจุดตั้งต้นในการสร้าง branch ใหม่ชื่อrefs/heads/my-feature
หากเขียนสองคำสั่งนี้แบบเต็มโดยไม่ใช้ชื่อย่อ จะมีหน้าตาดังนี้:
git fetch origin refs/heads/master:refs/remotes/origin/master
git switch -c my-feature refs/remotes/origin/masterในบรรทัดแรก ข้อความฝั่งซ้ายของเครื่องหมาย : คือชื่อ ref บนฝั่ง origin ส่วนฝั่งขวาคือชื่อ ref ที่จะใช้เก็บไว้ในเครื่องเรา โดยปกติ Git อนุญาตให้พิมพ์แค่ส่วนท้ายของชื่อ ref ได้ เราจึงคุ้นกับคำสั่งแบบย่อมากกว่า
จุดที่พลาดง่ายคือ origin/master ไม่ใช่ข้อมูลแบบเรียลไทม์ เมื่อเรา commit งานในเครื่อง ค่าของ refs/heads/master จะขยับไปข้างหน้า แต่ refs/remotes/origin/master จะยังอยู่ที่เดิมจนกว่าจะซิงก์ข้อมูลอีกครั้ง
ผู้เขียนบทความ On Git Refs เล่าว่าตัวเขาเองก็เพิ่งเข้าใจเรื่องนี้อย่างถ่องแท้ไม่กี่สัปดาห์ก่อนเขียนบทความ เขายังเล่าว่าตลอดชีวิตการทำงานเกือบครึ่งหนึ่ง เขาใช้วิธี clone repo ใหม่แทนการแก้ rebase ที่พัง และย้ำว่าไม่มีอะไรต้องอาย ใครที่เคย clone ใหม่เพราะกลัวทำ Git พัง คุณไม่ใช่คนเดียวที่ทำแบบนั้น
ในปัจจุบัน ตาราง ref ทั้งหมดจัดเก็บเป็นไฟล์ธรรมดา โดยแยกเก็บ 1 ref ต่อ 1 ไฟล์ย่อยใต้โฟลเดอร์ .git/refs ร่วมกับไฟล์ packed-refs ที่ใช้รวม ref หลายตัวไว้ในไฟล์เดียว หากลองเข้าไปดูใน .git/refs เราจะเห็นชื่อ branch เป็นไฟล์จริงๆ ตามโครงสร้างนี้:
.git/refs/
├── heads/
│ ├── master
│ └── my-feature
├── remotes/
│ └── origin/
│ └── master
└── tags/reftable เข้ามาแก้ปัญหาอะไรที่รูปแบบไฟล์เดิมทำไม่ได้
แม้การเก็บ ref แยกเป็นไฟล์จะดูตรงไปตรงมา แต่ก็มีข้อจำกัดตามระบบไฟล์ติดมาด้วย หน้า BreakingChanges ระบุปัญหาไว้หลายข้อ โดย 3 ข้อหลักที่ผู้ใช้ทั่วไปจะเจอคือ:
- ปัญหาชื่อที่ต่างกันแค่ตัวพิมพ์เล็ก-ใหญ่: ระบบไฟล์ที่ไม่แยกตัวพิมพ์เล็ก-ใหญ่ ซึ่งพบบ่อยบน Windows และ macOS ทำให้รูปแบบไฟล์เดิมไม่สามารถเก็บ ref อย่าง
fix-loginและFix-Loginพร้อมกันได้ - การลบ branch ใน repo ขนาดใหญ่: Git ต้องเขียนไฟล์
packed-refsใหม่ทั้งไฟล์ ซึ่งใน repo ที่มี ref จำนวนมากๆ ไฟล์นี้อาจมีขนาดใหญ่หลายสิบ MB ทำให้ทำงานช้าลง - การเขียนหลาย ref พร้อมกัน: รูปแบบเดิมไม่ได้เขียนทั้งชุดให้เสร็จในจังหวะเดียว ถ้า Git อ่าน ref ระหว่างที่ยังเขียนลงดิสก์ไม่ครบ ก็อาจเห็นข้อมูลที่ค้างอยู่ครึ่งๆ กลางๆ
reftable เข้ามาแก้ปัญหาเหล่านี้โดยไม่ใช้พาธของไฟล์เป็นชื่อ ref อีกต่อไป ปัญหาเรื่องตัวพิมพ์เล็ก-ใหญ่จึงหมดไป และเวลาลบ ref ระบบจะใช้วิธีทำเครื่องหมายกำกับว่าถูกลบแล้ว หรือ tombstone แทนการเขียนไฟล์ข้อมูลใหม่ทั้งก้อน
นอกจากนี้ เอกสารยังระบุว่าเมื่อต้องเขียนหรืออัปเดต ref จำนวนมากๆ ในคราวเดียว reftable ทำงานได้เร็วกว่ารูปแบบไฟล์เดิมมาก
ข้อควรรู้คือ ใน repo ที่ใช้ reftable ชื่อ ref จะไม่ได้เก็บเป็นไฟล์ตามโฟลเดอร์อีกต่อไป โครงสร้างโฟลเดอร์ใน .git/refs ที่เห็นในตัวอย่างก่อนหน้านี้จึงมีเฉพาะในรูปแบบไฟล์เดิมเท่านั้น ดังนั้น สคริปต์ที่เคยแอบเข้าไปเปิดอ่านไฟล์ใน .git/refs โดยตรงเพื่อดึงข้อมูล จะใช้ไม่ได้อีกต่อไป หากต้องการดูรายการ ref แนะนำให้เรียกผ่านคำสั่งมาตรฐานของ Git แทน:
git refs listคำสั่ง git refs list เป็นคำสั่งชื่อย่อหรือ alias ของ git for-each-ref ซึ่งทำงานเหมือนกันทุกประการ
repo เก่าจำเป็นต้องย้ายไหม
คำตอบสั้นๆ คือ branch main, SHA-256 และ reftable เป็น ค่าเริ่มต้นสำหรับ repo ที่สร้างขึ้นใหม่ ถ้าอยากให้ repo เดิมใช้ reftable ก็สั่งย้ายเองได้ด้วย git refs migrate ส่วน SHA-1 ยังไม่มีแผนเลิกใช้
ข้อยกเว้นคือ repo ที่ยังใช้ grafts หรือยังเก็บ remote ไว้ใน .git/branches/ หรือ .git/remotes/ repo กลุ่มนี้ต้องย้ายไปใช้ git replace และเก็บ remote ไว้ใน config ของ repo แทน
นอกจากนั้น สิ่งที่ควรตรวจสอบตั้งแต่วันนี้คือ สคริปต์และเครื่องมือต่างๆ รอบตัวเรา:
- สคริปต์หรือระบบ CI ที่สั่ง
git initแล้วอ้างอิงถึง branch master: ควรระบุชื่อ branch ให้ชัดเจน เช่นgit init --initial-branch=mainหรือตั้งค่าinit.defaultBranchไว้ล่วงหน้า ไม่เช่นนั้นเมื่อเครื่อง CI อัปเกรดเป็น Git 3.0 ขั้นตอนที่เรียกหา master อาจทำงานไม่ผ่านเพราะหา branch ไม่เจอ - โค้ดที่ตรวจสอบหรือตัดสตริงของ commit hash โดยถือว่าต้องยาว 40 ตัวอักษรเสมอ: ต้องปรับให้รับความยาว 64 ตัวอักษรได้ด้วย เพื่อรองรับ repo ที่ใช้ SHA-256
- สคริปต์ที่ยังเรียกใช้
git whatchangedหรือคำสั่งอื่นๆ ในตารางข้างต้น: ให้เปลี่ยนไปใช้คำสั่งทดแทนตามที่เอกสารแนะนำ เช่นgit log --raw - ใครที่เคยเก็บ bare repo แล้ว
cdเข้าไปใช้งานโดยตรง: ให้เปลี่ยนมาระบุตำแหน่งอย่างชัดเจนด้วย--git-dirหรือตัวแปรGIT_DIRแทน (แม้จะตั้งค่าsafe.bareRepository=allใน config ระดับ global ให้กลับไปทำงานแบบเดิมได้ แต่นั่นเท่ากับเปิดช่องโหว่ความปลอดภัยที่ Git 3.0 ตั้งใจปิดไว้) - คนที่ build Git จากซอร์สโค้ดด้วยตัวเอง: จำเป็นต้องติดตั้งคอมไพเลอร์ Rust ไว้ในเครื่องตั้งแต่เวอร์ชัน 2.55 เป็นต้นไป หรือสั่งปิดผ่าน build flag ชั่วคราวจนกว่าจะถึง Git 3.0
ถ้าอยากลอง reftable ตั้งแต่วันนี้
สำหรับ repo ใหม่ สามารถสั่งสร้างได้ทันทีด้วยคำสั่ง:
git init --ref-format=reftableส่วน repo เดิมที่มีอยู่แล้ว สามารถแปลงโครงสร้างได้ด้วยคำสั่ง git refs migrate เราควรทดสอบด้วยแฟล็ก --dry-run ดูก่อน เพื่อให้ Git จำลองขั้นตอนการย้ายข้อมูลทั้งหมดโดยยังไม่แก้ไขไฟล์จริง ซึ่ง ref ที่แปลงแล้วจะเก็บไว้ในโฟลเดอร์แยกต่างหาก และ Git จะแจ้งชื่อโฟลเดอร์ให้เข้าไปตรวจดู เมื่อเห็นว่าเรียบร้อยดี ค่อยรันคำสั่งจริงเพื่อแปลงข้อมูล:
git refs migrate --ref-format=reftable --dry-run
git refs migrate --ref-format=reftableก่อนเริ่มย้ายข้อมูล เอกสารของ git refs ระบุข้อจำกัดสำคัญไว้ 3 ข้อ:
- repo ที่ใช้ Git worktree จะย้ายไม่ได้
- Git ไม่ได้ล็อกการเขียนข้อมูลระหว่างการย้าย หากมีคำสั่งอื่นเขียนข้อมูลลง repo ในระหว่างนั้น ผลลัพธ์อาจไม่ถูกต้องหรือไม่ตรงกัน เราจึงต้องหยุดการเขียนข้อมูลทั้งหมดด้วยตัวเอง
- หาก repo ลงทะเบียนงานบำรุงรักษาอัตโนมัติตามเวลาอย่าง scheduled maintenance ไว้ ควรถอนการลงทะเบียนด้วยคำสั่ง
git maintenanceก่อน
ถ้าแค่อยากลองใช้ ระบุแฟล็กเป็นราย repo ก็พอแล้ว ไม่จำเป็นต้องไปตั้งค่า init.defaultRefFormat ในระดับระบบ เพราะค่านี้จะมีผลกับทุก repo ที่สร้างใหม่หลังจากนั้น
ส่วนการทดลองใช้ hash SHA-256 สามารถสั่งได้ด้วย git init --object-format=sha256 แต่แนะนำให้ใช้กับ repo ที่สร้างขึ้นมาเพื่อทดลองเท่านั้น เพราะเอกสารของ git init ระบุไว้ชัดเจนว่า ในปัจจุบัน repo ที่ใช้ SHA-256 กับ repo ที่ใช้ SHA-1 ยังทำงานร่วมกันไม่ได้
Git 3.0 ไม่ได้เกิดขึ้นในวันเดียว
การเปลี่ยนแปลงที่กำลังจะเกิดขึ้นใน Git 3.0 ไม่ใช่สิ่งที่โผล่มาอย่างกะทันหัน แต่เป็นการทยอยปรับปรุงในเวอร์ชัน 2.x มาอย่างต่อเนื่องตลอดหลายปีที่ผ่านมา ทั้งการแจ้งเตือนเรื่อง branch main ตั้งแต่ปี 2020, การกำหนดให้คำสั่งเก่าต้องใส่แฟล็ก --i-still-use-this, การเปิดใช้ Rust เป็นค่าเริ่มต้นตั้งแต่เวอร์ชัน 2.55 รวมถึงการที่ทีมพัฒนามีระบบ CI ที่รัน Git ในสภาพแวดล้อมที่เปิดการเปลี่ยนแปลงของ 3.0 ไว้ล่วงหน้า ผ่าน build switch หรือตัวเลือกสั่งคอมไพล์ชื่อ WITH_BREAKING_CHANGES
การเปลี่ยนค่าเริ่มต้นเหล่านี้แทบไม่กระทบคนที่ระบุค่าในคำสั่งไว้ชัดเจนเลย แต่จะกระทบเฉพาะสคริปต์หรือเครื่องมือที่เคยเดาค่าเริ่มต้นเอาเองเท่านั้น
ที่มา:
- เอกสารทางการของ Git
- โปรเจกต์ Git บน GitHub
- บทความ On Git Refs จาก matklad
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
ChatGPT Work ฉบับเข้าใจง่าย มอบงานให้ AI ทำจนจบ ตั้งแต่งานแรกจนถึงงานอัตโนมัติ พร้อม workflow ใช้ได้จริง 8 แบบ
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
Claude Cowork · The Business Playbook

ฉบับภาษาไทย 15 บท เรียนรู้ผ่านโปรเจกต์จำลองต่อเนื่องทั้งเล่ม ตั้งแต่ตั้งค่า Workspace จัดการไฟล์ เชื่อมแอป ตั้งระบบอัตโนมัติ จนถึงสร้าง Plugin


