git stash -> ผสานการเปลี่ยนแปลงที่เก็บไว้กับการเปลี่ยนแปลงปัจจุบัน


187

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

มีวิธีทำเช่นนี้หรือไม่?

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


อาจเป็นข้อมูลซ้ำซ้อนของstackoverflow.com/q/1360712/72178
ks1322

คำตอบของโจชัวควรเป็นคำตอบที่ยอมรับได้ โพสต์ stackoverflow นี้เป็นลิงค์ google แรกสำหรับคำถามนี้ให้คำตอบที่ถูกต้องกับอินเทอร์เน็ต!
Jérôme

คำตอบ:


272

ฉันเพิ่งค้นพบว่าถ้าการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดของคุณนั้นถูกเพิ่มเข้าไปในดัชนี (เช่น "staged" โดยใช้git add ...) จากนั้นgit stash apply(และสมมุติว่าgit stash pop) จะทำการผสานที่เหมาะสมจริง ๆ หากไม่มีความขัดแย้งแสดงว่าคุณเป็นทอง หากไม่มีให้แก้ไขตามปกติด้วยgit mergetoolหรือแก้ไขด้วยตนเองด้วยตนเอง

เพื่อให้ชัดเจนนี่คือกระบวนการที่ฉันพูดถึง:

mkdir test-repo && cd test-repo && git init
echo test > test.txt
git add test.txt && git commit -m "Initial version"

# here's the interesting part:

# make a local change and stash it:
echo test2 > test.txt
git stash

# make a different local change:
echo test3 > test.txt

# try to apply the previous changes:
git stash apply
# git complains "Cannot apply to a dirty working tree, please stage your changes"

# add "test3" changes to the index, then re-try the stash:
git add test.txt
git stash apply
# git says: "Auto-merging test.txt"
# git says: "CONFLICT (content): Merge conflict in test.txt"

... ซึ่งอาจเป็นสิ่งที่คุณกำลังมองหา


TL; DR

เรียกใช้git addก่อน


8
แฮ็คดังกล่าว แต่เฮ้มันใช้งานได้และดูเหมือนจะเป็นวิธีเดียวที่จะทำเช่นนี้ ฉันหวังว่าจะมีgit stash apply --forceหรืออะไร
Matt Kantor

13
ที่จริงแล้วมันไม่ใช่แฮ็ค แต่เป็นการปรับปรุงสิ่งที่คุณต้องการเนื่องจากคุณสามารถย้อนกลับไปสู่การเปลี่ยนแปลงในดัชนีได้อย่างง่ายดาย
hoffmanc

2
ว้าวพฤติกรรมนี้ตั้งใจจริง ๆ โดยคอมไพล์หรือไม่?
edi9999

9
ฉันไม่คิดว่าจะมีอะไร "ตั้งใจ" โดยคอมไพล์ ตอนนี้ลางสังหรณ์ของฉันอยู่ที่อะไรก็ตามที่มันทำได้โดยบังเอิญ
Profpatsch

5
นี่คือทางออกที่สมบูรณ์แบบ ผมก็ไม่ได้git add ., git stash applyจากนั้นgit resetจะนำไปใช้ในการสะสมการเปลี่ยนแปลงการทำงานของฉันและการผสานโดยไม่ต้องทำการกระทำ
สตีเฟ่นสมิ ธ

70

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

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

ในกรณีนี้คุณไม่สามารถใช้การซ่อนการเปลี่ยนแปลงปัจจุบันของคุณในขั้นตอนเดียว คุณสามารถคอมมิชชันการเปลี่ยนแปลง, ใช้ stash, คอมมิชชันอีกครั้ง, และสควอชทั้งสองคอมมิชชันที่ใช้git rebaseหากคุณไม่ต้องการคอมมิทสองตัว, แต่นั่นอาจเป็นปัญหามากกว่าที่ควร.


1
ฉันได้รับข้อความนั้น - การเปลี่ยนแปลงไม่ขัดแย้ง แต่แชร์ไฟล์เดียวกันรอบ ๆ ด้วย stashes / Apply's?
Bemis

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

3
ฉันจะไม่พิจารณาคำตอบนี้ในทุกกรณี คุณอาจซ่อนส่วนหนึ่งของชุดการเปลี่ยนแปลงในไฟล์เฉพาะเพราะคุณต้องการทดสอบบางอย่างขณะกำลังพัฒนา และคุณอาจไม่ต้องการยอมรับเนื้อหาปัจจุบันของไฟล์ ณ จุดนี้ในเวลา (หรือไม่เลย) เนื่องจากเป็น WIP มันเป็นปัญหาจริงของคอมไพล์ที่การเปลี่ยนแปลงที่ถูกซ่อนไม่สามารถรวมเข้ากับสาขาปัจจุบันของคุณได้
Thomas Watson

21
คำตอบของ Joshua Warner ควรเป็นคำตอบที่ถูกต้อง หากต้องการรวมที่สะสมให้หยุดการเปลี่ยนแปลงของคุณนำไปใช้สะสมจัดการกับความขัดแย้งใด ๆ แล้ว (ถ้าต้องการ) unstage การเปลี่ยนแปลงของคุณ
Vroo

4
"คุณสามารถคอมมิชชันการเปลี่ยนแปลง, ใช้ stash, คอมมิชชันอีกครั้ง, และสควอชทั้งสองคอมมิชชันโดยใช้ git rebase ถ้าคุณไม่ต้องการคอมมิทสองตัว, แต่นั่นอาจเป็นปัญหาที่คุ้มค่ามากกว่า" แทนที่จะนี้คุณสามารถทำ: git commit --amendกระทำการเปลี่ยนแปลงที่ใช้ซ่อนแล้ว
gabe

27

สิ่งที่ฉันต้องการคือวิธีผสานการเปลี่ยนแปลงที่ถูกจัดเก็บกับการเปลี่ยนแปลงปัจจุบัน

นี่เป็นอีกทางเลือกในการทำ:

git stash show -p|git apply
git stash drop

git stash show -pจะแสดงชุดข้อมูลแก้ไขที่บันทึกล่าสุด git applyจะใช้มัน git stash dropหลังจากที่ผสานจะทำซ่อนผสานสามารถลดลงด้วย


1
ขอบคุณสำหรับสิ่งนี้ - ฉันไม่รู้ว่าทำไมgit stash popไม่เพียงแค่ทำสิ่งนี้ในกรณีที่การผสานทั้งหมดใช้ ...
Iguananaut

เวอร์ชันเพิ่มเติม: git stash show -p --no-color | git apply --3way( --3way= ถอยกลับไปบนการผสาน 3 ทางหากแพทช์ล้มเหลว)
DmitrySandalov

แต่git stash show -pจะสร้างความแตกต่างระหว่างเนื้อหา stashed และกระทำกลับเมื่อรายการสะสมที่ถูกสร้างขึ้นเป็นครั้งแรก ดังนั้นสิ่งนี้จะแทนที่ไฟล์การทำงานที่เปลี่ยนแปลงที่ OP ทำ
Paul F. Wood

ทำไมเขียนทับ? diff ที่ผลิตด้วยgit stash show -pจะถูกรวมเข้าด้วยกันgit applyหากเป็นไปได้ที่จะทำโดยไม่มีข้อขัดแย้ง
ks1322

1

วิธีที่ผมจะทำคือการนี้เป็นครั้งแรกแล้วgit add git stash apply <stash code>มันเป็นวิธีที่ง่ายที่สุด


4
นี่ไม่ใช่สำเนาที่แท้จริงของ tl; dr ของคำตอบที่ยอมรับได้อย่างไร
RomainValeri

0

ตามที่ @Brandan แนะนำนี่คือสิ่งที่ฉันต้องทำเพื่อให้ได้รอบ

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

ทำตามขั้นตอนนี้:

git status  # local changes to `file`
git stash list  # further changes to `file` we want to merge
git commit -m "WIP" file
git stash pop
git commit -m "WIP2" file
git rebase -i HEAD^^  # I always use interactive rebase -- I'm sure you could do this in a single command with the simplicity of this process -- basically squash HEAD into HEAD^
# mark the second commit to squash into the first using your EDITOR
git reset HEAD^

และคุณจะถูกทิ้งให้อยู่กับการเปลี่ยนแปลงในท้องถิ่นที่ผสานเข้าด้วยกันอย่างเต็มที่fileพร้อมที่จะทำงาน / ทำความสะอาดต่อไปหรือทำการคอมมิชชันเดียว หรือถ้าคุณรู้ว่าเนื้อหาที่ผสานของจะถูกต้องคุณสามารถเขียนข้อความที่เหมาะสมและข้ามfilegit reset HEAD^


0

อาจจะไม่ใช่ความคิดที่แย่ที่สุดที่จะรวม (ผ่าน difftool) จาก ... ใช่ ... สาขา!

> current_branch=$(git status | head -n1 | cut -d' ' -f3)
> stash_branch="$current_branch-stash-$(date +%yy%mm%dd-%Hh%M)"
> git stash branch $stash_branch
> git checkout $current_branch
> git difftool $stash_branch

0

คุณสามารถได้อย่างง่ายดาย

  1. ยอมรับการเปลี่ยนแปลงปัจจุบันของคุณ
  2. ยกเลิกการซ่อนที่อยู่ของคุณและแก้ไขข้อขัดแย้ง
  3. ยอมรับการเปลี่ยนแปลงจากที่เก็บ
  4. ซอฟต์รีเซ็ตเพื่อส่งคอมมิทคุณกำลังส่งจาก

-1

อีกตัวเลือกหนึ่งคือการทำ "git stash" อีกอันของการเปลี่ยนแปลงที่ไม่ได้รับการแมปแล้วรวมทั้งสอง stit git น่าเสียดายที่คอมไพล์ดูเหมือนจะไม่มีวิธีในการรวมสอง stashes อย่างง่ายดาย ดังนั้นทางเลือกหนึ่งคือการสร้างไฟล์. diff สองไฟล์และใช้ทั้งสองอย่างเพื่อมิให้เป็นการกระทำพิเศษและไม่เกี่ยวข้องกับกระบวนการสิบขั้นตอน: |

วิธีการ: https://stackoverflow.com/a/9658688/32453


มันเปลี่ยนปัญหาของการใช้หนึ่งดิฟไปเป็นปัญหาของการใช้ดิฟสอง นอกจากนี้โซลูชันที่ได้รับการยอมรับนั้นไม่เกี่ยวข้องกับการคอมมิตเพียงแค่สเตจและเป็นเพียงคำสั่งเดียว (git add) (ฉันไม่ใช่ผู้ลงคะแนน)
Eike

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