Code review มาถึงระหว่างที่สามไฟล์แก้ครึ่ง ๆ กลาง ๆ และมีไฟล์เดียวที่ขยับได้ การ stash ทุกอย่างแล้วพิมพ์ไฟล์อีกสองใหม่คือพิธีกรรมที่ไม่มีใครคิดถึง
TL;DR: git stash push -m "เหตุผล" -- <path> จะ stash เฉพาะพาธที่ระบุและปล่อยส่วนที่เหลือของ tree ที่ยังไม่ได้คอมมิตให้เป็นอิสระ ดึงการเปลี่ยนแปลงกลับด้วย git stash pop (หรือดึงไฟล์เดียวจาก stash ไหนก็ได้ด้วย git restore --source stash@{0} -- <path>) รูปแบบ pathspec มาพร้อม git 2.13 ที่ปล่อยเมื่อพฤษภาคม 2017 — ทุก toolchain ในแปดปีหลังมีมัน
git stash push -m "app.conf prod tweak" -- app.conf
git stash list
# stash@{0}: On main: app.conf prod tweak
git stash pop stash ไฟล์ ไม่ใช่ทั้งต้นไม้
จะ stash เฉพาะไฟล์เดียวใน git ได้อย่างไร
git stash เปล่า ๆ จะกวาดทั้ง working tree — การแก้ไขทุกอย่างที่ถูกติดตามพากันเข้า stash และทุกอย่างกลับไปที่ HEAD ซึ่งเป็นรูปทรงที่ผิดเมื่อ tree ที่ยังไม่คอมมิต ปนกัน: ไฟล์หนึ่งพร้อมส่งต่อ ส่วนที่เหลือตรงไปตรงมาคือยังไม่เสร็จ คำตอบคือกริยา push พร้อม pathspec ตามเอกสาร git-stash:
# ก่อนหน้า: สามไฟล์ที่ยังไม่คอมมิต
$ git status --short
M app.conf
M notes.md
M main.py
# stash เฉพาะ app.conf
$ git stash push -m "app.conf prod tweak" -- app.conf
Saved working directory and index state On main: app.conf prod tweak
$ git status --short
M notes.md
M main.py app.conf กลับสู่สถานะที่คอมมิตไว้และไปอยู่ใน stash@{0}; notes.md กับ main.py ไม่ขยับแม้นิด ข้อความ -m เป็นทางเลือก แต่คุ้มสามวินาทีทันทีที่ git stash list เริ่มมีมากกว่าหนึ่งรายการ — stash ที่ตั้งชื่อว่า “WIP” แก่เร็ว
สองรายละเอียดที่สำคัญ:
- pathspec อยู่หลัง
--ทุกอย่างหลังขีดคู่คือพาธ ไม่ใช่แฟล็ก เป็นธรรมเนียมเดียวกับgit checkout -- <path>และไม่ใช่ของประดับ: ในเวอร์ชันเก่าgit stash push -- main.pyกับgit stash push main.pyต่างกันได้ เมื่อพาธเปล่าถูกอ่านผิด - ไฟล์ untracked ต้องการ
-uไฟล์เกิดใหม่ไม่มีประวัติที่ถูกติดตามให้ stash ดังนั้นpushปกติจะข้ามมันgit stash push -u -- newfile.pyจะรวมเข้ามา;-aไปไกลกว่านั้นและกวาดไฟล์ที่ถูก ignore ด้วย
จะ stash เฉพาะบางส่วนของไฟล์เดียวได้อย่างไร
เมื่อไฟล์นั้นเองยังครึ่งเสร็จ — สาม hunk ที่โอเค หนึ่ง hunk ที่อาย — โหมดโต้ตอบจะซอยมัน:
git stash -p # หรือ: git stash push -p Git เดินผ่านทีละ hunk และถาม Stash this hunk [y,n,q,a,d,j,g,/,e,p,?]? ตอบ y สำหรับ hunk ที่เข้า stash, n สำหรับที่อยู่ต่อ ผลลัพธ์คือ stash ที่มีเฉพาะส่วนที่อนุมัติ ส่วนที่เหลือของไฟล์ยังอยู่ใน tree กลไกทีละ hunk ชุดเดียวกันนี้ยังขับเคลื่อน git add -p ดังนั้นสัญชาตญาณย้ายบ้านได้ทันที
git stash push -- <path> | git stash -p | |
|---|---|---|
| ความละเอียด | ทั้งไฟล์ | hunk ราย hunk |
| ความเร็ว | คำสั่งเดียว เขียนสคริปต์ได้ | โต้ตอบ ทีละ hunk |
| ทำซ้ำใน CI | ได้ (พาธเป็นอาร์กิวเมนต์) | ไม่ได้ — ต้องมีคนยืนที่ prompt |
| เหมาะที่สุดกับ | “ไฟล์นี้ ที่เหลือไม่เอา” | “การเปลี่ยนนี้ อันนั้นไม่เอา” |
| ตั้งแต่ | git 2.13 (พ.ค. 2017) | มีมานานแล้ว |
กฎละมือจากโมเดลของเอกสารเอง: pathspec เมื่อเส้นแบ่งคือไฟล์, -p เมื่อมันอยู่ข้างใน
จะดึงไฟล์ที่ stash ไว้กลับมาได้อย่างไร
git stash pop คืน stash@{0} และลบรายการ นั่นคือเส้นทางปกติ — แต่ pop เป็นทุกอย่างหรือไม่มีอะไรเลยต่อหนึ่ง stash และเมื่อชน conflict จะหยุดกลางคันโดยรายการยังอยู่ สองทางเลือกที่ละเอียดกว่า:
# 1. ใช้งานโดยไม่ลบ (ทำซ้ำได้ปลอดภัย)
git stash apply stash@{0}
# 2. ดึงไฟล์เดียวออกจาก stash โดยรายการยังยืนอยู่
git restore --source stash@{0} -- app.conf
# รูปเขียนก่อน 2.23 ของการทำงานเดียวกัน:
git checkout stash@{0} -- app.conf รูปแบบ restore/checkout ตอบกรณี “stash รวมสามการเปลี่ยนไว้ด้วยกัน ตอนนี้ต้องการแค่อันเดียว” — มันคัดลอกเนื้อหาใน stash ของพาธนั้นเข้า working tree และปล่อยให้ stash@{0} ยังยืน ข้อควรระวัง: มันเขียนทับสำเนาใน working tree; ถ้าการแก้ปัจจุบันบนพาธนั้นสำคัญ ขอ diff ก่อน:
git diff stash@{0} -- app.conf stash ถูกเก็บเป็นคอมมิตจริงบนกองที่คล้าย reflog — นั่นคือเหตุที่ stash@{0} รับวากยสัมพันธ์ commit-ish ได้ทุกแบบ และ stash ที่โดนทิ้งผิดพลาดยังกู้จาก reflog ได้จนกว่า garbage collection จะกินมัน
stash เป็นเครื่องมือที่ผิดเมื่อไหร่
stash คือกระดาษทด ไม่ใช่ branch: ไม่มีชื่อใน git branch, ไม่มี review, ไม่แสดง diff ตามค่าเริ่มต้น และรายการกองสะสมอย่างเงียบ ๆ จนลืม ถ้างานที่กำลังทำต้องรอดจากการเปลี่ยนบริบทข้ามเครื่องหรือข้ามวัน คอมมิตลง branch เถอะ — ประวัติที่แนบมาดีกว่ากองไร้นาม เมื่อคอมมิตที่จอดไว้ต้องลงจอดที่อื่น git cherry-pick ขนส่งให้ และถ้าเป้าหมายคือย้อน ไม่ใช่จอด ให้ใช้ต้นไม้การตัดสินใจจากย้อนคอมมิตล่าสุด
สมุดบัญชีความพังที่ซื่อสัตย์ ทุกกรณีมาจากพฤติกรรมที่เอกสารระบุ:
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
| ไฟล์หายไปหลัง stash | พาธ untracked ถูกข้าม | git stash push -u -- <path> |
error: Your local changes ... would be overwritten ตอน pop | พาธเปลี่ยนไปหลังจาก stash | คอมมิตหรือ stash สถานะใหม่ แล้ว pop |
| การเปลี่ยนที่ดึงมาหายวับ | pop เจอ conflict แล้วหยุด | แก้ conflict แล้ว git stash apply |
| “stash อันไหนนะ?” | กอง stash ไร้นาม | ใส่ข้อความ -m ทุกครั้ง |
หน้า release note พฤษภาคม 2017 ที่เติม pathspec ให้ git stash push อายุแปดปีแล้ว และความจำกล้ามเนื้อส่วนใหญ่ของ git stash แก่กว่านั้น น่าเรียนใหม่สักรอบ: การกวาดทั้งต้นทุกวันนี้คือกรณีพิเศษ ไม่ใช่ค่าเริ่มต้น
FAQ
จะ stash เฉพาะไฟล์เดียวใน git ได้อย่างไร
git stash push -m "โน้ต" -- path/to/file — รูปแบบ pathspec จะ stash เฉพาะพาธที่ระบุและปล่อยไฟล์ที่แก้ไขไฟล์อื่นไว้ตามเดิม ต้องใช้ git 2.13 ขึ้นไป (พฤษภาคม 2017)
จะดึงไฟล์เดียวออกจาก stash ได้อย่างไร
git restore --source stash@{0} -- path/to/file (หรือรูปแบบเก่า git checkout stash@{0} -- path/to/file) คัดลอกเวอร์ชันใน stash ไปยัง working tree ของคุณโดยไม่ลบรายการ stash
ทำไม git stash ถึงข้ามไฟล์ใหม่ของฉันไป
ไฟล์ที่ยังไม่ถูกติดตาม (untracked) ไม่ได้อยู่ใน stash ปกติ ใส่ -u เพื่อรวมเข้ามา: git stash push -u -- path/to/file ส่วนไฟล์ที่ถูก ignore ต้องใช้ -a
— mrsaynothing
— mrsaynothing
บันทึกหน้างานเรื่อง AI, Linux และ self-hosted
รับวิธีแก้ฉบับถัดไปทางอีเมล
อีเมลหนึ่งฉบับต่อหนึ่งโพสต์ แก้เสร็จแล้วไปต่อ
นี่คืออะไร?บันทึกหน้างาน #1 เว็บที่เอเจนต์ดูแล: เครื่อง deploy คนอนุมัติ
ถ้าอ่านแล้วชอบ — ผมสร้างงานแบบนี้เป็นอาชีพ จ้างผม