Stashing เฉพาะการเปลี่ยนแปลงที่ไม่มีการจัดฉากใน Git


229

ฉันต้องการทำกระบวนการทำงานต่อไปนี้:

  1. เพิ่มการเปลี่ยนแปลงไปยังเวที
  2. สะสมการเปลี่ยนแปลงอื่น ๆ ทั้งหมดที่ไม่ได้จัดฉากไว้
  3. ทำบางสิ่งบางอย่างกับสิ่งต่าง ๆ บนเวที (เช่นการสร้างรันการทดสอบ ฯลฯ )
  4. ใช้ที่เก็บ

มีวิธีการทำขั้นตอนที่ 2 หรือไม่?

ตัวอย่าง

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

ทำไมไม่ยอมรับการเปลี่ยนแปลงของคุณหลังจากแสดงเสร็จแล้ว?
Shizzmo

3
IIRC --keepindex ทำเช่นนั้น
sehe

4
เพราะถ้าพูดว่าการสร้างล้มเหลวฉันไม่ต้องการทำสิ่งนี้ ฉันรู้ว่าฉันสามารถลบการคอมมิชชันได้ แต่ฉันต้องการทำสิ่งนี้โดยไม่ต้องส่งคำาขอ
Unapiedra

Sehe ขอบคุณ ฉันสามารถยืนยันงานนี้ได้ ฉันดูคู่มือที่linux.die.net/man/1/git-stashซึ่งล้าสมัยแล้ว man git stashดีกว่ามาก
Unapiedra

มัน - เก็บดัชนี fwiw
jaf0

คำตอบ:


288

git stash saveมีตัวเลือก--keep-indexที่ทำสิ่งที่คุณต้องการ

git stash save --keep-indexดังนั้นการเรียกใช้


9
จริง ผมให้ใช้กับsave git stashบางทีมันเป็นโปรแกรมเมอร์ในตัวฉันที่ยืนยันในการให้เกียรติสมมาตรด้วยการใช้ / ป๊อป :)
vhallac

104
หมายเหตุ: สิ่งนี้จะยังคงเป็นการเปลี่ยนแปลงทั้งหมดของคุณ ข้อแตกต่างจากปกติgit stash saveคือจะทำให้การเปลี่ยนแปลงที่มีอยู่แล้วในสำเนาการทำงานของคุณเช่นกัน ในเวิร์กโฟลว์ด้านบนสิ่งนี้จะทำงานได้ดีเนื่องจากคุณเพิ่งใช้ stash ที่ด้านบนของสำเนาโลคัลที่มีการเปลี่ยนแปลงของ stash อยู่ครึ่งหนึ่งแล้ว (ซึ่ง git นั้นฉลาดพอที่จะเพิกเฉย) แต่ถ้าคุณแก้ไขรหัสก่อนที่จะใช้ stash อีกครั้งคุณอาจเห็นข้อขัดแย้งในการรวมเมื่อคุณไปใช้งาน FYI
peterflynn

2
@ytpete ที่กัดฉันมาหลายครั้ง ฉันหวังว่าจะมีวิธีสำหรับคอมไพล์ที่จะซ่อนเฉพาะสิ่งที่คุณไม่ได้เก็บ ... ฉันมักจะทำสิ่งต่าง ๆ แล้วทำคอมไพล์เต็มรู้ว่าgit commit --ammendถ้าฉันมีปัญหาในสิ่งที่ฉันมุ่งมั่น
rjmunro

1
--amend(มากกว่า--ammend)
Rhubbarb

19
วิธีแก้ปัญหานี้ใช้ไม่ได้สำหรับฉันเนื่องจากปัญหาที่อธิบายโดย peterflynn มันไม่ได้เป็นคำตอบที่ดีสำหรับคำถามเพราะมันยังคงหยุดการเปลี่ยนแปลงฉาก ใครมีทางออกที่ดีกว่า
user643011

43

สิ่งนี้สามารถทำได้ใน 3 ขั้นตอน: บันทึกการเปลี่ยนแปลงที่มีการจัดเก็บซ่อนทุกอย่างอื่นคืนค่าดัชนีพร้อมการเปลี่ยนแปลงที่จัดเตรียมไว้ ซึ่งโดยทั่วไป:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

สิ่งนี้จะทำสิ่งที่คุณต้องการ


3
หมายเหตุ: หยุด-uไฟล์ที่ไม่ได้ติดตาม
ma11hew28

วิธีการนี้ซ้ำซ้อนกับสิ่งที่git stash save --keep-indexเกิดขึ้นกับการทำงานมากขึ้น ฉันไม่เห็นข้อได้เปรียบใด ๆ
Inigo

1
@vas ไม่วิธีการไม่ซ้ำกัน ดูความคิดเห็นของ peterflynn ต่อคำตอบที่ยอมรับ
Alexander Klauer

28
git stash save --keep-index

นอกจากนี้ Re:

ทำไมไม่ยอมรับการเปลี่ยนแปลงของคุณหลังจากแสดงเสร็จแล้ว? - ชิน

ตอบ: เนื่องจากคุณควรตรวจสอบรหัสทดสอบเสมอนั่นหมายความว่าคุณจำเป็นต้องเรียกใช้การทดสอบด้วย เพียงการเปลี่ยนแปลงที่คุณกำลังจะส่งมอบเท่านั้น

ทั้งหมดนี้นอกเหนือจากความจริงที่ว่าแน่นอนว่าในฐานะโปรแกรมเมอร์ที่มีประสบการณ์คุณมีความต้องการโดยธรรมชาติในการทดสอบและตรวจสอบเฉพาะการเปลี่ยนแปลงเหล่านั้น - ล้อเล่นบางส่วนเท่านั้น


14

ด้วยgit version 2.7.4คุณสามารถทำได้:

git stash save --patch

gitจะขอให้คุณเพิ่มหรือไม่การเปลี่ยนแปลงของคุณให้เป็นที่ซ่อน
แล้วคุณก็ตอบyหรือn

คุณสามารถกู้คืนไดเร็คทอรี่สำหรับใช้ทำงานได้ตามที่คุณต้องการ

git stash pop

หรือหากคุณต้องการเก็บการเปลี่ยนแปลงที่เก็บไว้ในที่เก็บ:

git stash apply

นี่มันเจ๋งมาก. มันใช้แรงงานน้อย แต่อย่างน้อยคุณก็สามารถข้ามและเพิ่มไฟล์ทั้งหมดได้
ดัสติน Oprea

5

ในการขยายคำตอบก่อนหน้านี้บางครั้งฉันมีชุดของการเปลี่ยนแปลงที่ซับซ้อนจัดฉากไว้ แต่ต้องการจะทำการเปลี่ยนแปลงแยกต่างหากก่อน ตัวอย่างเช่นฉันอาจพบข้อบกพร่องหรือรหัสที่ไม่ถูกต้องที่ฉันต้องการแก้ไขก่อนการเปลี่ยนแปลงระยะของฉัน เส้นทางเดียวที่เป็นไปได้คือ:

ก่อนอื่นเก็บทุกอย่างไว้ แต่ให้ทิ้งการเปลี่ยนแปลงไว้ตามเดิม

$ git stash save --keep-index [- รวม-untracked]

ตอนนี้สะสมการเปลี่ยนแปลงที่จัดฉากแยกกันด้วย

$ git stash save

ทำการเปลี่ยนแปลงเพื่อแก้ไข และทดสอบ กระทำพวกเขา:

$ git เพิ่ม [- แบบโต้ตอบ] [- ชุด]

$ git กระทำ -m "แก้ไข ... "

ตอนนี้คืนค่าการเปลี่ยนแปลงที่จัดเตรียมไว้ก่อนหน้านี้:

$ git stash pop

แก้ไขข้อขัดแย้งใด ๆ และโปรดทราบว่าหากมีข้อขัดแย้ง git จะถูกนำไปใช้ แต่ไม่ได้ลดลงในรายการที่เก็บบนสุด

(... จากนั้นส่งการเปลี่ยนแปลงแบบ staged และคืนค่าการเปลี่ยนแปลงอื่น ๆ ทั้งหมดและดำเนินการต่อ ... )


4

ในการเพิ่มไฟล์ unstagged (ไม่ได้เพิ่มเพื่อส่ง) ไปยังที่ซ่อนให้เรียกใช้คำสั่งต่อไปนี้:

git stash -k

จากนั้นคุณสามารถคอมมิตไฟล์ staged หลังจากนั้นคุณสามารถเรียกคืนไฟล์ที่ถูกซ่อนครั้งล่าสุดโดยใช้คำสั่ง:

git stash pop

4

การซ่อนต้นไม้ที่ใช้งาน (การเปลี่ยนแปลงแบบไม่สเตจ) ใน Git นั้นยากกว่าที่ควร คำตอบที่ยอมรับจะหยุดการเปลี่ยนแปลงที่ไม่มีการจัดฉากแต่หยุดการจัดฉากการเปลี่ยนแปลง (และใบพวกเขาจัดฉากเช่นกัน) ซึ่งจะไม่ค่อยมีสิ่งที่คุณต้องการ

นามแฝงนี้ทำงานได้ดี:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

มันกระทำการเปลี่ยนแปลงฉากชั่วคราวสร้างที่ซ่อนจากการเปลี่ยนแปลงที่เหลือ (และอนุญาตให้มีการขัดแย้งเพิ่มเติมเช่น--include-untrackedและ--messageจะถูกส่งผ่านเป็นอาร์กิวเมนต์นามแฝง) และจากนั้นรีเซ็ตการกระทำชั่วคราวเพื่อกลับการเปลี่ยนแปลงตามขั้นตอน

มันคล้ายกับคำตอบของ @Simon Knapp แต่มีความแตกต่างเล็กน้อย - ใช้--quietในการดำเนินการชั่วคราวที่รับและยอมรับพารามิเตอร์จำนวนมากสำหรับการซ่อนpushแทนที่จะเข้ารหัสยาก-mและเพิ่ม--softไปยังขั้นสุดท้าย รีเซ็ตเพื่อให้ดัชนียังคงอยู่เมื่อเริ่มต้น

สำหรับปัญหาตรงข้ามของการ stashing เพียงแค่การเปลี่ยนแปลงฉาก (นามแฝงstash-index) ดูคำตอบนี้


2

เคล็ดลับอื่นที่เกี่ยวข้องกับคำถาม:

เมื่อคุณซ่อนการเปลี่ยนแปลงที่ไม่มีการจัดเก็บโดยใช้อย่างมีประสิทธิภาพ

$ git stash save --keep-index

คุณอาจต้องการที่จะให้ข้อความที่ซ่อนดังนั้นเมื่อคุณทำgit stash listมันชัดเจนมากขึ้นสิ่งที่คุณเคยซ่อนมาก่อนโดยเฉพาะอย่างยิ่งถ้าคุณทำตามการดำเนินการที่ซ่อนโดยการบันทึกเพิ่มเติม ตัวอย่างเช่น

$ git stash save - ให้ดัชนี "การเปลี่ยนแปลงที่ยังไม่จัดฉาก"

(แม้ว่าจริงๆแล้วมันจะมีการเปลี่ยนแปลงทั้งหมดตามที่ระบุไว้ในคำตอบอื่น ๆ )

ตัวอย่างเช่นข้างต้นอาจตามมาทันทีโดย:

$ git stash บันทึก "การเปลี่ยนแปลงสถานะสำหรับคุณสมบัติ X"

อย่างไรก็ตามระวังว่าคุณไม่สามารถใช้งานได้

$ git stash ใช้ "stash @ {1}" ### ✘ไม่ได้ทำสิ่งที่คุณต้องการ

เพื่อเรียกคืนการเปลี่ยนแปลงที่ไม่ได้จัดเตรียมไว้


2

Git ไม่มีคำสั่งที่ซ่อนเฉพาะการเปลี่ยนแปลงที่ไม่ได้จัดทำของคุณ

อย่างไรก็ตาม Git ทำเช่นนั้นให้คุณระบุไฟล์ที่คุณต้องการซ่อน

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

หากคุณต้องการซ่อนการเปลี่ยนแปลงเฉพาะในไฟล์เหล่านั้นให้เพิ่ม--patchตัวเลือก

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

--include-untrackedตัวเลือกที่ช่วยให้คุณสามารถซ่อนไฟล์ที่ไม่ได้ติดตาม

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

เรียกใช้git help stash(หรือman git-stash) สำหรับข้อมูลเพิ่มเติม

หมายเหตุ: หากการเปลี่ยนแปลงที่ไม่มีการจัดเรียงของคุณค่อนข้างไม่สอดคล้องกัน@ alesguzikอาจเป็นคำตอบที่ง่ายกว่า


0

รูปแบบที่ทันสมัยของคำสั่งนั้นคือgit stash push [--] [<pathspec>...]ตั้งแต่ Git 2.16+ ( git stash saveเลิกใช้แล้ว )

คุณสามารถรวมสิ่งนั้นเข้ากับฟอร์มตัวแทนตัวอย่างเช่น:

git stash push --all --keep-index ':(glob)**/*.testextension' 

แต่มันใช้งานไม่ได้กับ Git สำหรับ Windows จนถึง Git 2.22 (Q2 2019) ดูที่ปัญหา 2037 การพิจารณาgit stashได้ถูกนำมาใช้ใหม่ใน C (แทนที่จะเป็นเชลล์สคริปต์)

ดูกระทำ 7db9302 (11 มีนาคม 2019) โดยโทมัส Gummerer (tgummerer )
ดูกระทำ 1366c78 , กระทำ 7b556aa (7 มีนาคม 2019) โดยโยฮันเน Schindelin (dscho )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 0ba1ba4 , 22 เมษายน 2019)

ในตัวstash: จัดการ:(glob) pathspecs อีกครั้ง

เมื่อส่งรายการ pathspecs ไปให้พูดว่า git addเราต้องระมัดระวังในการใช้รูปแบบดั้งเดิมไม่ใช่รูปแบบการแยกวิเคราะห์ของ pathspecs

สิ่งนี้สร้างความแตกต่างเช่นเมื่อโทร

git stash -- ':(glob)**/*.txt'

โดยที่รูปแบบดั้งเดิมจะมี:(glob)คำนำหน้าในขณะที่แบบแยกวิเคราะห์ไม่

อย่างไรก็ตามในตัวgit stashเราผ่านรูปแบบการแยกวิเคราะห์ (เช่นไม่ถูกต้อง) และgit addอาจล้มเหลวด้วยข้อความผิดพลาด:

fatal: pathspec '**/*.txt' did not match any files

ที่ระยะที่git stashปล่อยการเปลี่ยนแปลงจาก worktree แม้ว่าจะrefs/stashได้รับการอัพเดตสำเร็จแล้วก็ตาม


0

ฉันใช้นามแฝงซึ่งยอมรับสตริงเพื่อใช้เป็นข้อความไปยังรายการที่ซ่อน

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

ที่:

  • กระทำทุกอย่างในดัชนี
  • หยุดสิ่งที่มีการเปลี่ยนแปลงในแผนผังการทำงาน (อาจเพิ่ม-uหรือ-a )
  • รีเซ็ตการกระทำครั้งสุดท้ายกลับไปเป็นความพยายามในการทำงาน (อาจต้องการใช้--softเพื่อเก็บไว้ในดัชนี)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.