ซ่อนไฟล์เดียวจากหลายไฟล์ที่เปลี่ยนแปลงด้วย Git หรือไม่


3068

ฉันจะซ่อนไฟล์ที่มีการเปลี่ยนแปลงเพียงไฟล์เดียวในสาขาของฉันได้อย่างไร


109
ฉันไม่คิดว่าคำตอบที่ยอมรับของ @ bukzor เป็นคำตอบที่ถูกต้องสำหรับคำถามที่ถาม git stash --keep-indexจะเก็บดัชนี แต่จะหยุดทุกอย่าง - ทั้งในดัชนีและออก
Raman

@ อันโตนิโอดูเหมือนว่าฉันชอบความโปรดปรานของคุณควรเป็นคำถามแยกต่างหากเนื่องจากคำถามดั้งเดิมไม่มีอะไรเกี่ยวข้องกับ TortoiseGit โดยเฉพาะ
JesusFreke

1
@JesusFreke อ๋อให้ผลลัพธ์ที่ฉันจะได้ไม่ไว้วางใจ 50 ตัวแทน :) เพียงแค่นี้เป็นคำถามที่คุณได้รับการเปลี่ยนเส้นทางไปถ้าคุณพยายามที่จะค้นหา Tortoisegit ดูเหมือนจะไม่เป็นหัวข้อยอดนิยมที่นี่stackoverflow.com/questions/tagged/tortoisegit
Antonio

7
>>>>>>>>> git diff -- *filename* > ~/patchจากนั้นgit checkout -- *filename*และหลังจากนั้นคุณสามารถนำ patch มาใช้ใหม่ได้ด้วยgit apply ~/patch
neaumusic

36
คำตอบที่มีอยู่ส่วนใหญ่ด้านล่างล้าสมัยแล้ว ตั้งแต่ Git 2.13 (Q2 2017) git stash push [--] [<pathspec>...]ได้รับการสนับสนุนด้วย
Ohad Schneider

คำตอบ:


1372

คำปฏิเสธ : คำตอบต่อไปนี้สำหรับคอมไพล์ก่อนคอมไพล์ 2.13 สำหรับคอมไพล์ 2.13 และมากกว่าตรวจสอบคำตอบอื่นต่อไปลง


คำเตือน

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


นี่จะซ่อนทุกอย่างที่คุณไม่ได้เพิ่มไว้ก่อนหน้านี้ เพียงแค่git addสิ่งที่คุณต้องการเก็บไว้แล้วเรียกใช้

git stash --keep-index

ตัวอย่างเช่นหากคุณต้องการแยกการมอบหมายเก่าเป็นชุดการเปลี่ยนแปลงมากกว่าหนึ่งชุดคุณสามารถใช้ขั้นตอนนี้:

  1. git rebase -i <last good commit>
  2. editทำเครื่องหมายการเปลี่ยนแปลงบางอย่าง
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. แก้ไขสิ่งต่าง ๆ ตามความจำเป็น อย่าลืมการgit addเปลี่ยนแปลงใด ๆ
  7. git commit
  8. git stash pop
  9. ทำซ้ำจาก # 5 ตามความจำเป็น
  10. git rebase --continue

47
ฉันพบว่าวิธีการนี้ง่ายกว่านี้มาก: stackoverflow.com/a/5506483/457268
k0pernikus

561
ฉันไม่แน่ใจว่าทำไมสิ่งนี้ถึงถูกยกระดับขึ้น ทุกคนต้องมีความคาดหวังที่แตกต่างจากฉัน โพสต์ต้นฉบับกำลังถามว่า "ฉันจะซ่อนส่วนของการเปลี่ยนแปลงที่ไม่ได้รับอนุญาตได้อย่างไร" เมื่อฉันใช้git stash save -kใช่ดัชนี (สีเขียวgit stat) ถูกเก็บรักษาไว้ แต่ชุดการเปลี่ยนแปลงทั้งหมด (ทั้งสีเขียวและสีแดง) จะเข้าสู่ที่เก็บ สิ่งนี้ละเมิดคำขอของ OP "ซ่อนเฉพาะการเปลี่ยนแปลง" ฉันต้องการซ่อนสีแดงบางส่วนไว้ (สำหรับการใช้งานในอนาคต)
Pistos

70
หากคุณสนใจคำตอบของคำถามที่ @Pistos (เหมือนเดิม) ให้ดูที่นี่: stackoverflow.com/questions/5506339/…
Raman

27
@Raman: ยอดเยี่ยม! git stash -pเป็นสิ่งที่ฉันกำลังมองหา ฉันสงสัยว่าสวิตช์นี้เพิ่งถูกเพิ่มเมื่อไม่นานมานี้
Pistos

14
คำเตือน: git stash --keep-indexเสีย หากคุณทำการเปลี่ยนแปลงเพิ่มเติมให้ลองทำgit stash popภายหลังเพื่อรับความขัดแย้งในการผสานเนื่องจากที่เก็บมีไฟล์ที่เปลี่ยนแปลงซึ่งคุณเก็บไว้ไม่ใช่เฉพาะไฟล์ที่คุณไม่ได้เก็บไว้ ตัวอย่างเช่นฉันเปลี่ยนไฟล์ A และ B จากนั้นซ่อน B เพราะฉันต้องการทดสอบการเปลี่ยนแปลงใน A; ฉันพบปัญหากับ A ที่ฉันแก้ไขแล้ว; ฉันยอมรับ A; ตอนนี้ฉันไม่สามารถยกเลิกการติดตั้งได้เนื่องจาก A เวอร์ชันเก่าอยู่ในที่ซ่อนเนื่องจากไม่มีเหตุผลที่ดีที่ทำให้เกิดความขัดแย้งในการผสาน ในทางปฏิบัติ A และ B อาจเป็นไฟล์จำนวนมากบางทีอาจเป็นรูปไบนารีหรืออะไรบางอย่างดังนั้นโดยทั่วไปฉันต้องยอมแพ้และแพ้ B.
rjmunro

3015

git stash save -p "my commit message"นอกจากนี้คุณยังสามารถใช้ วิธีนี้คุณสามารถเลือกว่าจะเพิ่ม Hunks ใดลงในที่ซ่อนไฟล์ทั้งหมดสามารถเลือกได้เช่นกัน

คุณจะได้รับแจ้งพร้อมกับการกระทำบางอย่างสำหรับแต่ละก้อน:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help

5
มันไม่ใช่ มันยืมมาจาก Darcs ประมาณ 7 ปีหลังจากความจริง
nomen

6
ฉันเป็นคนติด TortoiseGit อย่างไรก็ตาม TortoiseGit stash -pไม่สนับสนุน ฉันให้รางวัลคำตอบนี้เพราะมันยังคงเป็นแบบโต้ตอบ / ใช้งานง่ายที่สุด
อันโตนิโอ

27
คุณอาจต้องการเพิ่ม: git stash save -p my stash message; เนื่องจากคำสั่งของ argumenst ที่ไม่ได้เป็นอย่างที่ใช้งานง่าย ...
คริส Maes

15
ระหว่างนี้และgit log -pฉันคิดว่า-pธงต้องหมายถึง "ทำสิ่งดีๆที่ฉันต้องการ แต่ไม่รู้วิธีแสดงออก"
Kyle Strand

2
ทำไมบนโลกนี้คำตอบที่ดีอยู่ในตำแหน่งที่ 12 ?? หลังจากทั้งหมด 0, +1, +2 คำตอบ ??????
DenisFLASH

548

เนื่องจาก git เป็นพื้นฐานเกี่ยวกับการจัดการเนื้อหาและดัชนีของที่เก็บทั้งหมด(และไม่ใช่ไฟล์หนึ่งหรือหลายไฟล์) git stashข้อเสนอไม่น่าแปลกใจกับไดเรกทอรีทำงานทั้งหมด.

ที่จริงแล้วตั้งแต่ Git 2.13 (Q2 2017) คุณสามารถซ่อนไฟล์แต่ละไฟล์ด้วยgit stash push:

git stash push [--] [<pathspec>...]

เมื่อpathspecมอบให้กับ ' git stash push' stash ใหม่จะบันทึกสถานะการแก้ไขเฉพาะไฟล์ที่ตรงกับ pathspec ดู " Stash เปลี่ยนแปลงไปยังไฟล์ที่ระบุ " สำหรับข้อมูลเพิ่มเติม

ตัวอย่างที่ง่าย:

 git stash push path/to/file

กรณีทดสอบสำหรับคุณสมบัตินี้แสดงตัวเลือกเพิ่มเติมไม่กี่ตัว

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

คำตอบเดิม (ด้านล่างมิถุนายน 2010) เป็นเรื่องเกี่ยวกับการเลือกสิ่งที่คุณต้องการซ่อนด้วยตนเอง

ความคิดเห็นCasebash :

นี้ ( stash --patchโซลูชันดั้งเดิม) ดี แต่บ่อยครั้งที่ฉันแก้ไขไฟล์จำนวนมากดังนั้นการใช้โปรแกรมปะแก้น่ารำคาญ

bukzor 's คำตอบ (upvoted กันยายน 2011) แสดงให้เห็นวิธีการแก้ปัญหาการปฏิบัติมากขึ้นบนพื้นฐาน+
git add git stash --keep-index
ไปดูและโหวตคำตอบของเขาซึ่งควรจะเป็นคำตอบที่เป็นทางการ (แทนที่จะเป็นของฉัน)

เกี่ยวกับตัวเลือกนั้นchhhชี้ให้เห็นเวิร์กโฟลว์ทางเลือกในความคิดเห็น:

คุณควร " git reset --soft" หลังจาก stash ดังกล่าวเพื่อรับ staging กลับของคุณชัดเจน:
เพื่อไปยังสถานะดั้งเดิม - ซึ่งเป็นพื้นที่ staging ที่ชัดเจนและมีการปรับเปลี่ยนที่ไม่เลือกฉากบางตัวสามารถรีเซ็ตดัชนีเบา ๆ เพื่อรับ (โดยไม่ต้อง กระทำการใด ๆ เช่นคุณ - bukzor - ทำ)


(คำตอบเดิมมิถุนายน 2010: คู่มือสะสม)

ทว่าgit stash save --patchสามารถช่วยให้คุณประสบความสำเร็จในการทำบางส่วน:

ด้วย--patchคุณสามารถเลือกนักล่าจากในส่วนต่างระหว่าง HEAD และแผนผังการทำงานที่จะซ่อน
รายการ stash ถูกสร้างขึ้นเพื่อให้สถานะดัชนีเหมือนกับสถานะดัชนีของที่เก็บของคุณและ worktree มีเฉพาะการเปลี่ยนแปลงที่คุณเลือกแบบโต้ตอบ การเปลี่ยนแปลงที่เลือกจะถูกย้อนกลับจาก worktree ของคุณ

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

git stash --patch --no-keep-index

อาจจะเป็นแบบที่ดีกว่า


ถ้า--patchไม่ทำงานกระบวนการที่ทำด้วยมืออาจจะ:

สำหรับไฟล์เดียวหรือหลายไฟล์โซลูชันระดับกลางจะเป็น:

  • คัดลอกนอก Git repo
    (ที่จริงแล้วeleotlecramเสนอทางเลือกที่น่าสนใจ )
  • git stash
  • คัดลอกกลับ
  • git stash # เวลานี้เฉพาะไฟล์ที่คุณต้องการถูกซ่อน
  • git stash pop stash@{1} # นำการแก้ไขไฟล์ของคุณมาใช้อีกครั้ง
  • git checkout -- afile # รีเซ็ตไฟล์เป็นเนื้อหา HEAD ก่อนการแก้ไขใด ๆ ในเครื่อง

ในตอนท้ายของกระบวนการที่ค่อนข้างยุ่งยากคุณจะมีไฟล์เพียงไฟล์เดียวหรือหลายไฟล์


3
นี่เป็นสิ่งที่ดี แต่บ่อยครั้งที่ฉันแก้ไขไฟล์จำนวนมากดังนั้นการใช้ตัวปะแก้น่ารำคาญ
Casebash

6
@VonC: เป็นสไตล์ที่ดีที่มีเพียงหนึ่งคำตอบต่อคำตอบ นอกจากนี้การคัดลอกการวางคำตอบของผู้อื่นเป็นของคุณเองก็คือมารยาทที่ไม่ดี
bukzor

3
@bukzor: ฉันขอโทษถ้าคำตอบที่แก้ไขแล้วดูเหมือนไม่เหมาะสม ความตั้งใจเพียงอย่างเดียวของฉันคือให้คำตอบแก่คุณมากขึ้น ฉันได้แก้ไขโพสต์ของฉันอีกครั้งเพื่อให้ความตั้งใจชัดเจนยิ่งขึ้น
VonC

1
@Kal: จริงstackoverflow.com/a/13941132/6309แนะนำให้git reset(ผสม)
VonC

3
git is fundamentally about managing a all repository content and index and not one or several files- นั่นคือการดำเนินการที่ครอบคลุมปัญหาที่กำลังแก้ไข; มันเป็นคำอธิบาย แต่ไม่ใช่เหตุผล ระบบควบคุมแหล่งข้อมูลใด ๆ เกี่ยวข้องกับ "การจัดการหลายไฟล์" เพียงแค่ดูสิ่งที่ความคิดเห็นได้รับการโหวตมากที่สุด
Victor Sergienko

90

เมื่อgit stash -p(หรือgit add -pมีstash --keep-index) จะยุ่งยากเกินไปผมพบว่ามันง่ายต่อการใช้diff, checkoutและapply:

หากต้องการ "ซ่อน" ไฟล์ / dir เฉพาะ:

git diff path/to/dir > stashed.diff
git checkout path/to/dir

หลังจากนั้น

git apply stashed.diff

1
ทางเลือกที่น่าสนใจสำหรับgit add -pฉันที่กล่าวถึงในคำตอบของฉันเองข้างต้น +1
VonC

11
โปรดทราบว่าหากคุณมีไฟล์ไบนารี (เช่น PNG) ไฟล์เหล่านั้นจะไม่ถูกส่งออกไปยังไฟล์ diff ดังนั้นนี่ไม่ใช่วิธีแก้ปัญหา 100%
void.pointer

1
@ RobertDailey: นั่นเป็นจุดที่น่าสนใจสำหรับฉันgit diff > file.diffและgit applyเป็นเครื่องมือซ่อนเร้นบางส่วนตามปกติของฉัน ฉันอาจต้องพิจารณาเปลี่ยนเป็นชุดgit stash -pเซ็ตใหญ่ ๆ
thekingoftruth

1
@thekingoftruth นี่คือนามแฝงที่ผมใช้ในการสร้างไฟล์แพทช์และมันไม่patch = log --pretty=email --patch-with-stat --reverse --full-index --binaryไบนารีการสนับสนุน: อย่างไรก็ตามโปรดทราบว่าสิ่งนี้จะต้องมีการเปลี่ยนแปลงเพื่อให้แพทช์มีความมุ่งมั่น
void.pointer

2
../../foo/bar.txtนี้ไม่ได้ทำงานเรียบร้อยสำหรับผมถ้าไฟล์ที่จะซ่อนอะไรบางอย่างเช่น แพตช์สร้างตกลง แต่ฉันต้องย้ายไปที่รูทที่เก็บเพื่อให้แพตช์ใช้ ดังนั้นหากคุณมีปัญหากับสิ่งนี้ - ให้แน่ใจว่าคุณทำมันจากไดเรกทอรีรากของที่เก็บ
Michael Anderson

86

ใช้git stash pushแบบนี้:

git stash push [--] [<pathspec>...]

ตัวอย่างเช่น:

git stash push -- my/file.sh

มีให้ตั้งแต่ Git 2.13 วางตลาดในฤดูใบไม้ผลิ 2017


1
แต่ฉันพูดถึงgit stash pushแล้วในคำตอบของฉันข้างต้นเมื่อเดือนมีนาคม 5 เดือนที่ผ่านมา และผมก็มีรายละเอียดที่ใหม่ Git 2.13 คำสั่งที่นี่: stackoverflow.com/a/42963606/6309
VonC

ฉันมีความสุขที่ Git กำลังจะมาถึงอย่างรวดเร็วเป็นเวลานานไม่สามารถทำได้แล้ว 2.13 จะถูกปล่อยออกมาและในทันใดก็มีวิธีแก้ปัญหาที่ง่าย ๆ !
sandstrom

1
@VonC ถูกต้องคุณยังพูดถึงคำตอบที่ถูกต้องอย่างไรก็ตามระหว่างคำตอบทั้งสองคำนี้อ่านง่ายกว่า (ไม่มีข้อความที่สับสนและยังมีตัวอย่าง) บางทีพวกเขาควรจะแก้ไขคำตอบของคุณแทน
Utopik

@ Utopik คุณมีฉันที่ "คุณพูดถูก" ... แต่ใช่ฉันได้แก้ไขคำตอบของฉันเพื่อรวมตัวอย่าง
VonC

จากนั้นgit stash applyจะใช้เพื่อกู้คืนการเปลี่ยนแปลงที่เก็บไว้หรือไม่
ชาด

49

สมมติว่าคุณมี 3 ไฟล์

a.rb
b.rb
c.rb

และคุณต้องการซ่อนเฉพาะ b.rb และ c.rb แต่ไม่ใช่ a.rb

คุณสามารถทำอะไรเช่นนี้

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

และคุณทำเสร็จแล้ว! HTH


29

อีกวิธีในการทำสิ่งนี้:

# Save everything
git stash 

# Re-apply everything, but keep the stash
git stash apply

git checkout <"files you don't want in your stash">

# Save only the things you wanted saved
git stash

# Re-apply the original state and drop it from your stash
git stash apply stash@{1}
git stash drop stash@{1}

git checkout <"files you put in your stash">

ฉันมากับสิ่งนี้หลังจากฉัน (อีกครั้ง) มาที่หน้านี้และไม่ชอบคำตอบสองคำแรก (คำตอบแรกไม่ตอบคำถามและฉันไม่ชอบทำงานกับ-pโหมดโต้ตอบ)

แนวคิดนี้เหมือนกับที่ @VonC แนะนำโดยใช้ไฟล์นอกที่เก็บคุณบันทึกการเปลี่ยนแปลงที่คุณต้องการจากนั้นลบการเปลี่ยนแปลงที่คุณไม่ต้องการออกจากที่เก็บของคุณจากนั้นนำการเปลี่ยนแปลงที่คุณย้ายออกไปใช้ใหม่ อย่างไรก็ตามฉันใช้ git stash เป็น "ที่ไหนสักแห่ง" (และเป็นผลให้มีขั้นตอนพิเศษหนึ่งตอนท้าย: ลบ cahnges ที่คุณใส่ไว้ใน stash เพราะคุณย้ายสิ่งเหล่านี้ออกไปให้พ้น)


1
ฉันชอบวิธีนี้มากที่สุด มันให้ขั้นตอนการทำงานที่ง่ายในการ tortoisegit โดยใช้คำสั่ง stash และย้อนกลับเท่านั้น
Mark Ch

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

2
@BryanAsh ก็ไม่เหมือนที่มันสำคัญนี่ ฉันให้เกร็ดเล็กเกร็ดน้อยมากกว่าที่จะอ้างถึงคำตอบอื่น ๆ ข้อความคือฉันไม่ชอบคำตอบที่ชุมชนชอบและไม่ใช่สิ่งที่คำตอบเหล่านี้มีอยู่จริง นอกจากนี้ช่องว่าง 900 คะแนนระหว่างคำตอบที่สองและสามทำให้สิ่งนี้ไม่น่าจะมีการเปลี่ยนแปลงในอนาคตอันใกล้และหากมันควรจะมีการเปลี่ยนแปลงฉันสามารถแก้ไขได้เสมอเพื่อพูดว่า "สุดยอดคำตอบในเวลานั้น" จริง ๆ ฉันไม่เห็นว่าปัญหานี้เกิดขึ้นได้อย่างไรในสถานการณ์เช่นนี้
แจสเปอร์

23

อัปเดต (2/14/2015) - ฉันเขียนสคริปต์ใหม่เพื่อให้จัดการกับกรณีของความขัดแย้งได้ดีขึ้นซึ่งตอนนี้ควรแสดงเป็นข้อขัดแย้งที่ไม่ถูกรวมแทนที่จะเป็นไฟล์. rej


ฉันมักจะพบว่ามันง่ายกว่าที่จะทำสิ่งที่ตรงกันข้ามกับ @ bukzor นั่นคือการเปลี่ยนแปลงขั้นตอนแล้วสะสมเฉพาะการเปลี่ยนแปลงที่จัดฉาก

น่าเสียดายที่ git ไม่ได้เสนอ git stash - เฉพาะ index หรือคล้ายคลึงกันดังนั้นฉันจึง whipped สคริปต์เพื่อทำสิ่งนี้

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it's safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

คุณสามารถบันทึกสคริปต์ด้านบนเป็นที่git-stash-indexใดที่หนึ่งบนเส้นทางของคุณและสามารถเรียกใช้เป็น git stash-index

# <hack hack hack>
git add <files that you want to stash>
git stash-index

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

ในบางกรณีการเปลี่ยนแปลงแผนผังการทำงานอาจขึ้นอยู่กับการเปลี่ยนแปลงดัชนีดังนั้นเมื่อคุณซ่อนการเปลี่ยนแปลงดัชนีการเปลี่ยนแปลงแผนผังการทำงานมีข้อขัดแย้ง ในกรณีนี้คุณจะได้รับข้อขัดแย้งแบบไม่มีการแก้ไขที่คุณสามารถแก้ไขได้ด้วย git merge / git mergetool / etc


แนะนำpushdแทนcdและpopdท้ายสคริปต์ดังนั้นหากสคริปต์สำเร็จผู้ใช้จะอยู่ในไดเรกทอรีเดียวกับก่อนเรียกใช้
Nate

1
@ เนท: เท่าที่ฉันรู้มันก็ควรเปลี่ยนไดเรกทอรีสำหรับผู้ใช้ถ้าพวกเขามาสคริปต์ หากคุณเรียกใช้สคริปต์ตามปกติ (~ / bin / git-stash-index) หรือผ่าน git (git stash-index) สคริปต์จะทำงานในเซสชันเทอร์มินัลแยกต่างหากและการเปลี่ยนแปลงไดเรกทอรีที่ทำงานในเซสชันนั้นจะไม่ส่งผลกระทบต่อ ไดเรกทอรีการทำงานในเซสชั่นขั้วของผู้ใช้ คุณตระหนักถึงกรณีการใช้งานทั่วไปเมื่อไม่เป็นจริงหรือไม่? (นอกเหนือจากการจัดหาสคริปต์ซึ่งฉันจะไม่พิจารณา "ทั่วไป")
JesusFreke

20

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

$ git stash -- filename.ext

หากเป็นไฟล์ที่ไม่ได้ติดตาม / ใหม่คุณจะต้องดำเนินการก่อน

วิธีนี้ใช้ได้กับ git เวอร์ชั่น 2.13+


คำตอบนั้นเป็นคำพูดที่กระชับ ถ้ามันช่วยใครซักคนฉันจะทิ้งมันไป ไม่มีใครในหน้านี้กล่าวถึงไวยากรณ์และผลลัพธ์นี้ - แทนที่จะกล่าวถึง "git stash push`"
sealocal

นี่คือคำตอบที่ฉันต้องการ ขอบคุณ! +1
nicodp

19

เนื่องจากการสร้างสาขาใน Git นั้นสำคัญมากคุณสามารถสร้างสาขาชั่วคราวและตรวจสอบแต่ละไฟล์ได้


2
คุณไม่สามารถสร้างสาขาที่ไม่มีการแก้ไขแบบไม่ต่อเนื่องได้ คุณสามารถย้ายการแก้ไขทั้งหมดไปยังสาขาใหม่ (ป๊อปอัพ / ที่เก็บของ) ได้อย่างง่ายดายแต่จากนั้นคุณกลับไปที่ตารางที่หนึ่ง: คุณจะทดสอบสาขาของคุณด้วยการแก้ไขเหล่านั้นเพียงบางส่วนได้อย่างไร
bukzor

7
คุณไม่สามารถสลับสาขาได้หากคุณมีการเปลี่ยนแปลงในท้องถิ่น อย่างไรก็ตามคุณสามารถสร้างสาขาใหม่และเลือกเพิ่ม / กระทำไฟล์แล้วสร้างสาขาอื่นและทำแบบเดียวกันซ้ำ ๆ ... จากนั้นเช็คสาขาเดิมและเลือกรวมเข้าด้วยกันฉันเพิ่งทำมัน ดูเหมือนจริงแล้ววิธีธรรมชาติในการทำสิ่งต่าง ๆ ในขณะที่คุณกำลังสร้างสาขาคุณลักษณะ
Iain

3
@Iain คุณสามารถสลับสาขาได้หากคุณมีการเปลี่ยนแปลงในท้องถิ่นตราบใดที่พวกเขาไม่ต้องการการผสาน ดูตัวอย่างสรุปสาระสำคัญ สิ่งนี้เป็นจริงตั้งแต่ Git v2.7.0 เป็นอย่างน้อย
Colin D Bennett

18

คุณสามารถทำได้:

git stash push "filename"

หรือด้วยข้อความเพิ่มเติม

git stash push -m "Some message" "filename"

1
สิ่งนี้ไม่ได้เพิ่มอะไรใหม่ การกดปุ่ม Git Stash ถูกกล่าวถึงแล้วในหลายคำตอบ
JesusFreke

12

stashบันทึกรหัสต่อไปนี้ไปยังแฟ้มตัวอย่างเช่นการตั้งชื่อ stash <filename_regex>การใช้งาน อาร์กิวเมนต์เป็นนิพจน์ปกติสำหรับพา ธ เต็มของไฟล์ ตัวอย่างเช่นการซ่อน / b / c.txt stash a/b/c.txtหรือstash .*/c.txtอื่น ๆ

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

รหัสที่จะคัดลอกลงไฟล์:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}

2
วิธีการที่ยอดเยี่ยม ฉันจะเลือกคำตอบนี้เป็นคำตอบ เคล็ดลับสำหรับผู้อ่านในอนาคต: คุณต้องจับคู่บนเส้นทางแบบเต็ม เช่น stash subdir / foo.c
er0

12

ในกรณีที่คุณหมายถึงยกเลิกการเปลี่ยนแปลงทุกครั้งที่คุณใช้git stash(และไม่ได้ใช้ git stash เพื่อซ่อนไว้ชั่วคราว) ในกรณีนี้คุณสามารถใช้

git checkout -- <file>

[ หมายเหตุ ]

นี่git stashเป็นทางเลือกที่รวดเร็วและง่ายในการแยกและทำสิ่งต่างๆ


8

ปัญหาเกี่ยวกับการแก้ปัญหา 'สื่อกลาง' ของ VonC ในการคัดลอกไฟล์ไปยังนอก Git repo คือการที่คุณสูญเสียข้อมูลพา ธ

พบว่าการใช้ tar (เครื่องมือที่คล้ายกันอาจทำได้ง่ายกว่า) แทนการทำสำเนา:

  • tar cvf /tmp/stash.tar พา ธ / ถึง / some / พา ธ ไฟล์ / ถึง / some / อื่น ๆ / ไฟล์ (... ฯลฯ )
  • git checkout path / to / some / path path / to / some / other / file
  • คอมไพล์สะสม
  • tar xvf /tmp/stash.tar
  • เป็นต้น (ดูคำแนะนำ 'ขั้นกลาง' ของ VonC)

checkout -fไม่จำเป็นcheckout(โดยไม่มี-f) ก็เพียงพอแล้วฉันได้อัปเดตคำตอบแล้ว
eleotlecram

8

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

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

โปรดทราบว่าสามารถยกเลิกstash& แรกstash popคุณสามารถดำเนินการเปลี่ยนแปลงทั้งหมดของคุณไปยังmasterสาขาเมื่อคุณชำระเงิน แต่เฉพาะในกรณีที่ไม่มีความขัดแย้ง นอกจากนี้หากคุณกำลังสร้างสาขาใหม่สำหรับการเปลี่ยนแปลงบางส่วนคุณจะต้องสะสม

คุณสามารถทำให้มันง่ายขึ้นโดยไม่มีข้อขัดแย้งและไม่มีสาขาใหม่:

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

ที่เก็บไม่จำเป็นต้องใช้ ...


8

สามารถทำได้อย่างง่ายดายใน 3 ขั้นตอนโดยใช้ SourceTree

  1. กระทำการชั่วคราวทุกสิ่งที่คุณไม่ต้องการให้ถูกเก็บชั่วคราว
  2. Git เพิ่มทุกอย่างจากนั้นซ่อน
  3. แสดงการกระทำชั่วคราวของคุณโดยเรียกใช้การรีเซ็ต git และกำหนดเป้าหมายการกระทำก่อนที่คุณจะส่ง

ทั้งหมดนี้สามารถทำได้ภายในไม่กี่วินาทีใน SourceTree ซึ่งคุณสามารถคลิกที่ไฟล์ (หรือแม้กระทั่งแต่ละบรรทัด) ที่คุณต้องการเพิ่ม เมื่อเพิ่มเข้ามาแล้วให้คอมมิทเข้าไปยังการคอมมิตชั่วคราว จากนั้นคลิกช่องทำเครื่องหมายเพื่อเพิ่มการเปลี่ยนแปลงทั้งหมดจากนั้นคลิกที่เก็บเพื่อซ่อนทุกอย่าง เมื่อมีการเปลี่ยนแปลงที่ทำไปแล้วให้มองไปที่รายการการกระทำของคุณและจดแฮชสำหรับการกระทำก่อนที่จะส่งการกระทำชั่วคราวแล้วเรียกใช้ 'git reset hash_b4_temp_commit' ซึ่งโดยพื้นฐานแล้วก็คือ "popping" การกระทำโดยการรีเซ็ตสาขาของคุณ กระทำก่อนหน้ามัน ตอนนี้คุณเหลือสิ่งที่คุณไม่ต้องการซ่อน


8

git stash save --patchผมจะใช้ ฉันไม่พบว่าการโต้ตอบนั้นน่ารำคาญเพราะมีตัวเลือกให้ใช้การดำเนินการที่ต้องการกับไฟล์ทั้งหมด


3
ประหลาดใจที่มีการสนับสนุนเล็กน้อยสำหรับคำตอบนี้มันเป็นทางออกที่ดีที่สุดโดยไม่จำเป็นต้องมีบทความ
robstarbuck

คำตอบที่ดีแน่นอนgit stash -pช่วยให้คุณซ่อนไฟล์ทั้งหมดได้อย่างรวดเร็วและเลิกหลังจากนั้น
Richard Dally

7

ทุกคำตอบที่นี่ซับซ้อนมาก ...

สิ่งนี้เกี่ยวกับ "ซ่อน":

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

สิ่งนี้จะปรากฏการเปลี่ยนแปลงไฟล์กลับ:

git apply /tmp/stash.patch

พฤติกรรมแบบเดียวกันทุกประการเช่นเดียวกับการจัดเก็บไฟล์หนึ่งไฟล์และเปิดอีกครั้ง


ฉันพยายาม แต่ไม่มีอะไรเกิดขึ้น เมื่อฉันgit applyฉันไม่มีข้อผิดพลาด แต่การเปลี่ยนแปลงจะไม่ถูกนำกลับมาไม่มี
ClementWalter

ไฟล์แพทช์ที่คุณสร้างใน / tmp อาจถูกลบ คุณอาจรีบูทระหว่างส่วนต่างและส่วนที่ใช้ ลองอีกตำแหน่งถาวร มันใช้งานได้ดี ตรวจสอบเนื้อหาของไฟล์แพตช์
Christophe Fondacci

4

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

  • git stash -p (--patch): เลือก hunks ด้วยตนเองไม่รวมไฟล์ที่ไม่ได้ติดตาม
  • git stash -k (--keep-index): ซ่อนไฟล์ที่ถูกติดตาม / ไม่ได้ติดตามทั้งหมดและเก็บไว้ในไดเรกทอรีการทำงาน
  • git stash -u (--include-untracked): ซ่อนไฟล์ที่ถูกติดตาม / ไม่ได้ติดตามทั้งหมด
  • git stash -p (--patch) -u (--include-untracked): คำสั่งไม่ถูกต้อง

ปัจจุบันวิธีที่เหมาะสมที่สุดในการซ่อนไฟล์ที่ถูกติดตามหรือไม่ได้ติดตามคือ:

  • ส่งมอบไฟล์ที่คุณไม่ต้องการซ่อนชั่วคราว
  • เพิ่มและซ่อน
  • ป๊อปกระทำชั่วคราว

ผมเขียนสคริปต์ง่ายสำหรับขั้นตอนนี้ในการตอบคำถามอื่นและมีขั้นตอนในการดำเนินการขั้นตอนใน SourceTree ที่นี่


4

สารละลาย

การเปลี่ยนแปลงในท้องถิ่น:

  • file_A (แก้ไขแล้ว) ไม่ได้จัดเตรียมไว้
  • file_B (แก้ไขแล้ว) ไม่ได้จัดเตรียมไว้
  • file_C (แก้ไข) ไม่จัดฉาก

หากต้องการสร้างที่เก็บ "my_stash" โดยมีการเปลี่ยนแปลงเฉพาะกับfile_C :

1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop stash@#{1}

เสร็จสิ้น


คำอธิบาย

  1. เพิ่มfile_Cไปยังพื้นที่จัดเตรียม
  2. สร้างที่เก็บชั่วคราวที่ชื่อ "temp_stash" และเก็บการเปลี่ยนแปลงใน file_C
  3. สร้างที่เก็บที่ต้องการ ("my_stash") ด้วยการเปลี่ยนแปลงเฉพาะใน file_C
  4. ใช้การเปลี่ยนแปลงใน "temp_stash" (file_A และ file_B) กับรหัสท้องถิ่นของคุณและลบที่เก็บ

คุณสามารถใช้สถานะ Gitระหว่างขั้นตอนต่าง ๆ เพื่อดูว่าเกิดอะไรขึ้น


3

เมื่อคุณพยายามสลับระหว่างสองสาขาสถานการณ์นี้จะเกิดขึ้น

ลองเพิ่มไฟล์โดยใช้ " git add filepath"

เรียกใช้บรรทัดนี้ในภายหลัง

git stash --keep-index


3

git stash --patch [file]จะสะสมการใช้งานไฟล์เดียว

นี่จะเป็นพรอมต์: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?. เพียงแค่พิมพ์a(ซ่อนก้อนใหญ่นี้และตามล่าทั้งหมดในไฟล์) และคุณก็สบายดี


พลาดpushในgit stash push --patch [file]
Filipe Esperandio

@FilipeEsperandio pushทำงานเฉพาะในรุ่นล่าสุดของ Git saveเคยเป็น ไม่ว่าในกรณีใดpushหรือsaveโดยนัยโดยการโทรstash: "การเรียก git stash โดยไม่มีข้อโต้แย้งใด ๆ เทียบเท่ากับ git stash push", docs
patrick

2

สถานการณ์ที่คล้ายกัน ได้กระทำและตระหนักว่ามันไม่เป็นไร

git commit -a -m "message"
git log -p

จากคำตอบนี้ช่วยฉันได้

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push

2

ในสถานการณ์เช่นนี้ฉันgit add -p(โต้ตอบ) git commit -m blahแล้วซ่อนสิ่งที่เหลือไว้หากจำเป็น


2

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

  1. เวทีทุกอย่าง
  2. ดำเนินการเปลี่ยนแปลงสำเนาทำงานของคุณที่ยกเลิกการเปลี่ยนแปลงทั้งหมดในไฟล์ A (เช่นเรียกใช้เครื่องมือ diff ภายนอกและทำให้ไฟล์ตรงกัน)
  3. ทำให้ไฟล์ B ดูราวกับว่ามีการเปลี่ยนแปลงครั้งที่สองเท่านั้น (เช่นเรียกใช้เครื่องมือ diff ภายนอกและยกเลิกการเปลี่ยนแปลงครั้งแรก)
  4. สร้างที่เก็บโดยใช้ "เก็บการเปลี่ยนแปลงที่มีการจัดฉาก"
  5. unstage ทุกอย่าง
  6. ทำ!

2
git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)

1
คุณไม่ควรทำอย่างนั้น คำตอบควรจัดให้มีการแก้ปัญหาให้กับคำถามที่ คุณสามารถถามคำถามของคุณเอง
L_J

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

สิ่งนี้จะไม่ทำงานเนื่องจากคำสั่งที่สาม "git stash" จะไม่ให้เกียรติกับไฟล์ที่จัดฉาก ทั้งไฟล์ staged และ nonstaged จะไปที่ stash คำถามจะถามเฉพาะว่าจะซ่อนไฟล์เพียงไฟล์
อย่างไร

0

วิธีที่ซับซ้อนวิธีหนึ่งคือการมอบทุกสิ่งก่อน:

git add -u
git commit // creates commit with sha-1 A

รีเซ็ตกลับสู่การส่งต้นฉบับ แต่เช็กเอาต์ the_one_file จากการส่งใหม่:

git reset --hard HEAD^
git checkout A path/to/the_one_file

ตอนนี้คุณสามารถซ่อน the_one_file:

git stash

ล้างข้อมูลโดยบันทึกเนื้อหาที่กำหนดไว้ในระบบไฟล์ของคุณในขณะที่รีเซ็ตกลับสู่การส่งต้นฉบับ:

git reset --hard A
git reset --soft HEAD^

ใช่ค่อนข้างอึดอัด ...


0

ฉันไม่พบคำตอบว่าเป็นสิ่งที่ฉันต้องการและนั่นง่ายเหมือน:

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

สิ่งนี้ทำให้ไฟล์หนึ่งไฟล์ตรงกัน


0

คำตอบที่รวดเร็ว


สำหรับแปลงไฟล์ที่ถูกเปลี่ยนกลับเป็น git คุณสามารถทำบรรทัดต่อไปนี้:

git checkout <branch-name> -- <file-path>

นี่คือตัวอย่างจริง:

git checkout master -- battery_monitoring/msg_passing.py


0

หากคุณต้องการซ่อนไฟล์ที่เปลี่ยนแปลงบางไฟล์เพียงแค่

เพิ่มไฟล์ที่คุณไม่ต้องการซ่อนในสเตจแล้วเรียกใช้งานgit stash save --keep-index

มันจะสะสมทุกunstagedไฟล์ที่มีการเปลี่ยนแปลง

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