ยกเลิกการป๊อปสะสมใน Git


257

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

ฉันพยายามgit merge --abortแต่คอมไพล์อ้างว่าไม่มีการรวมกำลังดำเนินการ มีวิธีง่ายๆในการยกเลิกป๊อปโดยไม่ทำลายการเปลี่ยนแปลงที่ฉันเคยทำในไดเรกทอรีหรือไม่?


สำหรับการเปลี่ยนแปลงที่ไม่ได้รับการตอบรับของคุณ: การเปลี่ยนแปลงเหล่านี้มีอยู่แล้วในดัชนีหรือไม่
jørgensen

คุณช่วยโพสต์เวอร์ชั่นของ git ที่คุณใช้อยู่ได้ไหม
Tinman


2
คำตอบที่ยอมรับนั้นดูซับซ้อน ฉันคิดว่ามันเป็นวิธีปฏิบัติที่ดีโดยทั่วไปที่จะไม่ทำอะไรบางอย่างเช่นความพยายามgit stash popในการทำงานที่ไม่สะอาด ในกรณีนี้คุณสามารถทำได้อย่างง่ายดายgit reset --hardและที่เก็บของคุณยังคงเหมือนเดิม (นี่เป็นสิ่งที่เชื่อมโยงกับ @ BradKoch ของหัวข้อที่แนะนำให้มากขึ้น)
Steven Lu

1
@StevenLu ฉันเห็นด้วย แต่ปัญหาอาจเกิดขึ้นในการทำงานที่สะอาดถ้าคุณ stashing การเปลี่ยนแปลงเพื่อย้ายพวกเขาไปยังสาขาอื่น ที่เก็บข้อมูลขัดแย้งกับการกระทำที่มีอยู่ในสาขาใหม่ที่ไม่มีอยู่ในสาขาเดิม
Jake Stevens-Haas

คำตอบ:


55

ตกลงฉันคิดว่าฉันได้ทำงาน "git stash unapply" มันซับซ้อนกว่าgit apply --reverseเพราะคุณจะต้องย้อนกลับผสานการดำเนินการในกรณีที่มีการควบรวมกิจการใด ๆ git stash applyที่กระทำโดย

การผสานย้อนกลับต้องการให้มีการผลักดันการเปลี่ยนแปลงปัจจุบันทั้งหมดในดัชนี:

  • git add -u

จากนั้นกลับสิ่งmerge-recursiveที่ทำโดยgit stash apply:

  • git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1

ตอนนี้คุณจะเหลือเพียงการเปลี่ยนแปลงที่ไม่ซ่อนเร้น พวกเขาจะอยู่ในดัชนี คุณสามารถใช้git resetเพื่อเลิกการเปลี่ยนแปลงหากคุณต้องการ

ระบุว่าต้นฉบับของคุณgit stash applyล้มเหลวฉันถือว่าการย้อนกลับอาจล้มเหลวเนื่องจากบางสิ่งที่ต้องการเลิกทำไม่ได้เสร็จสิ้น

นี่คือตัวอย่างที่แสดงให้เห็นว่าสำเนาการทำงาน (ผ่านgit status) จบลงอย่างไรทำความสะอาดอีกครั้ง:

 $ git status
# On branch trunk
nothing to commit (working directory clean)
 $ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
 $ git add -u
 $ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
 $ git status
# On branch trunk
nothing to commit (working directory clean)

2
หลังจากทำเช่นนี้แล้วการแก้ไขที่ถูกซ่อนไว้ก่อนหน้านี้จะหายไปตลอดกาลหรือจะกลับไปอยู่ในที่ซ่อน
Brian H.

7
git stash applyไม่เคยลดการสะสมและเมื่อการผสานล้มเหลวแล้วgit stash popยังคงสะสมที่อยู่
Xerus

สิ่งที่ไม่ดีจะเกิดขึ้นหากมีข้อขัดแย้งในการผสานระหว่างป๊อปสะสมดั้งเดิม
3ocene

286

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

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

ง่าย.


22
ดังนั้นที่เก็บที่คุณต้องการอยู่ในรายการที่ซ่อนจนกว่าคุณจะมีป๊อปที่ประสบความสำเร็จ?
Ryan Clark

52
นี่ไม่ใช่คำตอบสำหรับคำถามเดิมเพราะมันจะลบล้างการเปลี่ยนแปลงในพื้นที่ที่ไม่ได้กระทำ
มิทรี

13
@RyanClark ดูคำตอบของ DavidGด้านล่าง โดยทั่วไปใช่มันอยู่ในรายการที่ซ่อน
fkorsa

1
ฉันคิดว่าผู้ใช้ส่วนใหญ่ที่พบว่าตัวเองอยู่ในสถานการณ์นี้จะพบว่าวิธีนี้เหมาะอย่างยิ่ง ฉันไม่สามารถจินตนาการสถานการณ์ที่ฉันมีการเปลี่ยนแปลงข้อผูกมัดในไดเรกทอรีการทำงานของฉันก่อนที่จะพยายามไปstash popเป็นมัน นั่นดูเหมือนสูตรสำหรับภัยพิบัติ
Shadoninja

2
ดี หลังจากอ่านสิ่งนี้ฉันดู git stash pop docs และมันบอกว่า "การใช้สถานะอาจล้มเหลวด้วยความขัดแย้งในกรณีนี้มันจะไม่ถูกลบออกจากรายการที่เก็บ" ดังนั้นนี่คือเหตุผลว่าทำไมจึงสามารถเก็บสะสมใหม่ได้หลังจากรีเซ็ต / เช็คเอาต์
เบรดี้โฮลท์

48

แก้ไข: จากgit help stashเอกสารในส่วนป๊อป:

การใช้สถานะอาจล้มเหลวด้วยความขัดแย้ง ในกรณีนี้มันจะไม่ถูกลบออกจากรายการที่ซ่อน คุณต้องแก้ไขข้อขัดแย้งด้วยตนเองและโทร git stash drop ด้วยตนเองหลังจากนั้น

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

ลองทำสำเนา repo ทั้งหมดของคุณให้เป็น dir ใหม่ (เพื่อให้คุณมีสำเนา) และเรียกใช้:

git stash show และบันทึกผลลัพธ์นั้นไว้ที่ใดที่หนึ่งถ้าคุณสนใจ

จากนั้น: git stash dropเพื่อวางที่เก็บที่ขัดแย้งกันไว้จากนั้น:git reset HEAD

ที่ควรปล่อยให้ repo ของคุณอยู่ในสถานะที่เคยเป็นมาก่อน (หวังว่าฉันยังไม่สามารถแก้ไขปัญหาของคุณได้)

===

ฉันพยายามที่จะแก้ไขปัญหาของคุณ แต่สิ่งที่ฉันได้รับเมื่อใช้git stash popคือ:

error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting

ในผบที่สะอาด:

git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop

ฉันไม่เห็นคอมไพล์พยายามรวมการเปลี่ยนแปลงของฉัน แต่ก็ล้มเหลว คุณมีขั้นตอนการทำซ้ำที่เราสามารถปฏิบัติตามเพื่อช่วยคุณได้หรือไม่


ลอง stashing การเปลี่ยนแปลงเป็นไฟล์อื่น
asmeurer

การพยายามที่จะซ่อนไฟล์อื่นไม่ทำงาน (ดูขั้นตอนการทำซ้ำใหม่) ฉันไม่สามารถ repro ปัญหา ...
davidg

1
วิธีนี้ไม่ทำงานหากมีการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดในไดเรกทอรีการทำงาน
ที่นี่

@ ที่นี่ไม่ใช่วิธีการแก้ปัญหาที่แท้จริงนี่เป็นเพียงการแสดงให้เห็นว่าฉันไม่สามารถทำซ้ำปัญหาที่ OP ได้และเขาไม่ได้ทำตามขั้นตอนใด ๆ เพื่อไปยังที่ที่เขาอยู่
DavidG

1
สถานการณ์จริงคือ: 1) เปลี่ยนไฟล์ A. 2) การเปลี่ยนแปลงที่เก็บ 3) ทำการเปลี่ยนแปลงที่ขัดแย้งในไฟล์ A และกระทำ (เช่นเปลี่ยนบรรทัดเดียวกัน) 4) เปลี่ยนไฟล์ B 5) ทำ 'git stash pop' ตอนนี้คุณมีความขัดแย้งและการเปลี่ยนแปลงในท้องถิ่น โดยทั่วไปแล้วไฟล์เหล่านั้นจะอยู่ในไฟล์ที่แตกต่างกัน แต่คุณจะไม่มีทางรู้ว่าไฟล์ที่ถูกแก้ไขที่ไม่ขัดแย้งกันนั้นมาจากที่เก็บของใด
มิทรี

16

ฉันมักจะใช้

git reset --merge

ฉันจำไม่ได้ว่ามันล้มเหลว


@GauravPaliwal git resetฉันจะให้ดูว่าครั้งต่อไปฉัน คุณรู้หรือไม่ว่ามันใช้งานได้จริงgit reset --mergeหรือไม่
Kenn Sebesta

5

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

git reset .
git checkout .
git clean -f

4

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

ทำการสำรองข้อมูลก่อนที่ !! ฉันไม่ทราบว่าสิ่งนี้จะใช้ได้กับคุณหรือไม่ดังนั้นคัดลอก repo ทั้งหมดของคุณในกรณีที่มันไม่ทำงาน

1) แก้ไขปัญหาการรวมและแก้ไขข้อขัดแย้งทั้งหมดโดยเลือกการเปลี่ยนแปลงทั้งหมดที่มาจากแพทช์ (ใน tortoisemerge สิ่งนี้จะปรากฏเป็นหนึ่ง REMOETE (ของพวกเขา))

git mergetool

2) ยอมรับการเปลี่ยนแปลงเหล่านี้ (พวกเขาจะถูกเพิ่มผ่านคำสั่ง mergetool) ส่งข้อความ "รวม" หรือสิ่งที่คุณจำได้

git commit -m "merge"

3) ตอนนี้คุณจะยังคงมีการเปลี่ยนแปลงที่ไม่ได้จัดทำในพื้นที่เดิมของคุณโดยเริ่มจากคอมมิชชันใหม่ (เราสามารถกำจัดมันได้ในภายหลัง) ตอนนี้ยอมรับการเปลี่ยนแปลงที่ไม่จัดทำของคุณ

git add .
git add -u .
git commit -m "local changes"

4) ย้อนกลับโปรแกรมแก้ไข สิ่งนี้สามารถทำได้ด้วยคำสั่งต่อไปนี้:

git stash show -p | git apply -R

5) ยอมรับการเปลี่ยนแปลงเหล่านี้:

git commit -a -m "reversed patch"

6) กำจัดแพทช์ / unpatch มุ่งมั่น

git rebase -i HEAD^^^

จากนี้ลบทั้งสองบรรทัดด้วย 'ผสาน' และ 'กลับแก้ไขแพทช์' ในนั้น

7) รับการเปลี่ยนแปลงที่ไม่มีการเปลี่ยนแปลงของคุณกลับมาและยกเลิกการกระทำ 'การเปลี่ยนแปลงในท้องถิ่น'

git reset HEAD^

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


หากยังไม่ได้ผลหวังว่ามันจะช่วยให้คุณได้รับประโยชน์มากที่สุด! :-)
agentgonzo

git stash show -p | git apply -Rที่ไม่ทำงานหากgit stash applyมีการผสานจริง ๆ ดูคำตอบของฉัน ...
เบนแจ็คสัน

3

ฉันแก้ไขมันด้วยวิธีที่แตกต่างออกไปเล็กน้อย นี่คือสิ่งที่เกิดขึ้น

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

ง่ายgit reset HEADยกเลิกการแก้ไขความขัดแย้งและซ้ายปราศจากข้อผูกมัด (และไม่พึงประสงค์ ) การเปลี่ยนแปลง

หลายคนgit co <filename>กลับดัชนีเป็นสถานะเริ่มต้น ในที่สุดฉันเปลี่ยนสาขาด้วยgit co <branch-name>และเรียกใช้ใหม่git stash popซึ่งแก้ไขได้โดยไม่มีข้อขัดแย้ง


2

ความคิดบางอย่าง:

  • ใช้git mergetoolเพื่อแยกไฟล์ผสานออกเป็นส่วนใหม่และต้นฉบับ หวังว่าหนึ่งในนั้นคือไฟล์ที่มีการเปลี่ยนแปลงที่ไม่ซ่อนอยู่ในไฟล์ของคุณ

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

ฉันไม่ได้ทดสอบสิ่งเหล่านี้อย่างใดอย่างหนึ่งดังนั้นฉันไม่ทราบว่าพวกเขาจะทำงานได้อย่างแน่นอน


1

ฉันสามารถสร้างใหม่ทั้งหมดgit stash popในไดเรกทอรี "สกปรก" ด้วยการเปลี่ยนแปลงปราศจากข้อผูกมัด แต่ยังไม่ปรากฏที่สร้างความขัดแย้งผสาน

ถ้าในความขัดแย้งผสานสะสมที่คุณพยายามที่จะใช้ไม่ได้หายไปคุณสามารถพยายามที่จะตรวจสอบgit show stash@{0}(ตัวเลือกที่มี--oursหรือ--theirs) และเปรียบเทียบกับและgit statis git diff HEADคุณควรจะเห็นว่าการเปลี่ยนแปลงใดมาจากการใช้ที่ซ่อน


1

หาก DavidG ถูกต้องที่ไม่ปรากฏว่ามีที่เก็บเนื่องจากข้อขัดแย้งผสานคุณเพียงแค่ล้างข้อมูลไดเรกทอรีทำงานของคุณ git commitทุกสิ่งที่คุณใส่ใจได้อย่างรวดเร็ว (คุณสามารถresetหรือsquashกระทำในภายหลังหากคุณยังไม่ได้ทำ) จากนั้นทุกสิ่งที่คุณใส่ใจเกี่ยวกับความปลอดภัยgit resetทุกอย่างอื่นที่git stash popถูกทิ้งลงในไดเรกทอรีการทำงานของคุณ


1

หากไม่มีการเปลี่ยนแปลงฉากก่อนหน้าgit stash popดังเช่นในคำถามแล้วคำสั่งสองคำสั่งต่อไปนี้ควรใช้งานได้

git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm

ครั้งแรกที่ย้อนกลับการผสานใด ๆ จากที่เก็บสำเร็จหรือไม่ ไฟล์ที่สองจะลบไฟล์ที่ไม่ได้ติดตามใด ๆ ที่แนะนำโดย stash

จากman git stash: The working directory must match the index. @DavidG ใดที่ชี้ให้เห็นว่าstash popจะล้มเหลวหากไฟล์ใด ๆ ที่ไม่ได้แก้ไขซึ่งมีการขัดแย้งกันอยู่ในปัจจุบัน HEADดังนั้นเราจึงไม่ควรต้องกังวลเกี่ยวกับการคลี่คลายความขัดแย้งผสานเกินได้รับกลับไป ไฟล์ที่ถูกแก้ไขใด ๆ ที่เหลือจะไม่เกี่ยวข้องกับที่เก็บสะสมและถูกแก้ไขก่อนstash pop

หากมีการเปลี่ยนแปลงเป็นระยะฉันไม่แน่ใจว่าเราสามารถพึ่งพาคำสั่งเดียวกันได้หรือไม่และคุณอาจต้องการลองใช้เทคนิคของ @Ben Jackson คำแนะนำชื่นชม ..

นี่คือการตั้งค่าการทดสอบสำหรับกรณีต่าง ๆ ทั้งหมดhttps://gist.github.com/here/4f3af6dafdb4ca15e804

# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d

# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c

ฉันคิดว่านี่เป็นคำตอบที่ถูกต้องที่สุด คิดออกดีมาก
ตัวแทนวันศุกร์

0

ใช้git reflogเพื่อแสดงรายการการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นในประวัติความเป็นมาของคุณ คัดลอกรหัสการกระทำและประเภทgit reset ACTION_ID


2
Git ไม่ได้สร้างรายการ reflog ก่อนที่คุณจะป๊อป (คุณต้องมีความมุ่งมั่น)
Casebash

-1

ฉันโพสต์ที่นี่หวังว่าคนอื่นจะหาคำตอบของฉันได้ ฉันมีปัญหาที่คล้ายกันเมื่อฉันพยายามที่จะทำป๊อปสะสมในสาขาที่แตกต่างจากที่ฉันเคยซ่อน ในกรณีของฉันฉันไม่มีไฟล์ที่ไม่มีข้อผูกมัดหรือในดัชนี แต่ยังคงเป็นกรณีความขัดแย้งที่ผสาน (กรณีเช่นเดียวกับ @pid) ดังที่คนอื่น ๆ ชี้ไปก่อนหน้านี้ป๊อปที่เก็บสะสมในระบบที่ล้มเหลวไม่ได้เก็บสะสมของฉันไว้อย่างแน่นอนจากนั้นการรีเซ็ต Git HEAD อย่างรวดเร็วและกลับไปที่สาขาเดิมของฉันและทำการซ่อนที่นั่นช่วยแก้ไขปัญหาของฉัน

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