วิธี unstage ไฟล์จำนวนมากโดยไม่ลบเนื้อหา


454

ฉันบังเอิญเพิ่มไฟล์ชั่วคราวจำนวนมากโดยใช้ git add -A

ฉันจัดการเพื่อ unstage ไฟล์โดยใช้คำสั่งต่อไปนี้และจัดการเพื่อลบดัชนีสกปรก

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

git help rmคำสั่งดังกล่าวข้างต้นมีการระบุไว้ใน แต่น่าเสียดายที่ไฟล์ของฉันถูกลบด้วยเช่นกันแม้ว่าฉันจะมีตัวเลือกแคชก็ตาม ฉันจะล้างดัชนีโดยไม่สูญเสียเนื้อหาได้อย่างไร

นอกจากนี้ยังจะเป็นประโยชน์หากมีใครสามารถอธิบายวิธีการทำงานของท่อนี้ได้


8
rm -fไม่ใช่คำสั่ง git และไม่มี--cachedตัวเลือก ไฟล์ในเครื่องของคุณถูกลบก่อนที่คุณจะดำเนินการgit rmดังนั้นฉันไม่คิดว่าคุณจะโทษความผิดgit rmใด ๆ
CB Bailey

8
@sarat โปรดพิจารณาเปลี่ยนคำตอบที่ถูกต้องเพื่อให้คำตอบ upvoted สูงจากเอียนแมดดอกซ์เป็นgit reset --hardเป็นไม่ได้คำตอบที่ถูกต้องและในความเป็นจริงลบเนื้อหา สิ่งนี้จะสร้างความสับสนให้กับผู้ใช้ - เช่นเดียวกับฉัน
Marco Pashkov

2
@sarat ตามที่มาร์โกพูดต่อไป หน้านี้ได้รับการเข้าชมจำนวนมาก
Ross

@MarcoPashkov & Ross ขอบคุณพวกคุณ เสร็จสิ้น
sarat

คำตอบ:


986

git reset

หากสิ่งที่คุณต้องการคือการยกเลิกการเรียกใช้ "git add" overzealous:

git reset

การเปลี่ยนแปลงของคุณจะไม่มีการจัดเตรียมและพร้อมให้คุณเพิ่มอีกครั้งตามที่คุณต้องการ


git reset --hardไม่ได้ทำงาน

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


15
ฉันติดหนี้คุณ Ian
DasBooten

1
ฉันมักจะพบว่าฉันต้องแสดงgit checkout -- *เช่นกัน
Den-Jason

1
คุณบันทึกความพยายามมากมาย Thanks man
RajnikantDixit

35

หากคุณมี repo ที่สมบูรณ์ (หรือไม่ได้ตั้งค่า HEAD) [1]คุณสามารถทำได้ง่ายๆ

rm .git/index

แน่นอนว่าสิ่งนี้จะทำให้คุณต้องเพิ่มไฟล์ที่คุณไม่ต้องการเพิ่มอีกครั้ง


[1]หมายเหตุ (ตามที่อธิบายไว้ในความคิดเห็น) สิ่งนี้มักจะเกิดขึ้นก็ต่อเมื่อ repo เป็นแบรนด์ใหม่ ("เก่าแก่") หรือหากไม่มีข้อผูกมัดใด ๆ เทคนิคเพิ่มเติมทุกครั้งที่ไม่มีการชำระเงินหรือต้นไม้ทำงาน

เพียงทำให้ชัดเจนยิ่งขึ้น :)


ใช่มันเป็นเหมือนการลบดัชนีที่สร้างขึ้นเอง สิ่งที่ดีคือฉันไม่ต้องการเริ่มต้นคอมไพล์ใหม่ ขอบคุณ!
sarat

แน่ใจหรือว่าเป็นการทำงานที่ปลอดภัย? ฉันเพิ่งทำสิ่งนี้ (ย้ายดัชนีออกนอกเส้นทางจริง ๆ ) และทำให้ไฟล์อื่น ๆ ทั้งหมดถูกลบทิ้ง
inger

@inger "ถ้าคุณมี repo ที่เก่าแก่" เห็นได้ชัดว่าคุณไม่มี
sehe

ที่จริงแล้วฉันสงสัยว่าคุณหมายถึงอะไรโดย "pristine repo" (ฉันไม่รู้สึกโชคดีกับ google ด้วย) .. ดังนั้นคุณหมายถึง repo ที่ว่างเปล่าจริง ๆ ไหม?
inger

1
@inger เห็นด้วย ฉันต้องสมมติว่า OP เกิดขึ้นกับสถานการณ์ที่แน่นอน - เขาไม่ได้ระบุ แต่คำอธิบายของเขาก็มีความเป็นไปได้ ยังไงก็ตามฉันแค่แบ่งปันข้อมูลและไม่สามารถมีอิทธิพลต่อการลงคะแนน :( ได้เพิ่มคำเตือนไปยังข้อความคำตอบในกรณีที่มันช่วยคนอื่นในอนาคต
sehe

15

ใช้git reset HEADเพื่อรีเซ็ตดัชนีโดยไม่ลบไฟล์ (หากคุณต้องการรีเซ็ตไฟล์เฉพาะในดัชนีคุณสามารถใช้git reset HEAD -- /path/to/fileเพื่อทำเช่นนั้น)

ตัวดำเนินการไพพ์ในเชลล์ใช้stdoutกระบวนการทางด้านซ้ายและส่งผ่านstdinไปยังกระบวนการทางด้านขวา เป็นหลักเทียบเท่ากับ:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

แต่มันเป็น$ proc1 | proc2กระบวนการที่สองสามารถเริ่มรับข้อมูลได้ก่อนที่จะทำการส่งออกครั้งแรกและไม่มีไฟล์จริงเข้ามาเกี่ยวข้อง


แต่สำหรับวิธีใช้กับไฟล์หลาย ๆ ไฟล์ ฉันไม่เคยยอมรับไฟล์เหล่านี้มาก่อน
sarat

3
เพียงพิมพ์git reset HEADโดยไม่ระบุสิ่งอื่นใดและจะรีเซ็ตดัชนีทั้งหมด จากนั้นคุณสามารถเพิ่มไฟล์ที่คุณต้องการได้อีกครั้งเท่านั้น
เหลืองอำพัน

ฉันได้รับข้อผิดพลาดดังต่อไปนี้ ฉันไม่เคยทำรายการเหล่านี้มาก่อน $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
sarat

1
ลองเพียงแค่นั้นโดยไม่ต้องgit reset HEAD
แอมเบอร์

ฉันลองแล้วว่าฉันลงเอยด้วยข้อผิดพลาดต่อไปนี้ $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
sarat

9
git stash && git stash pop

2
ฉันจะทำ 'git stash && git stash pop' เพื่อให้ stash นั้นถูกลบด้วย 'ใช้' จะออกจากที่เก็บในรายการที่ซ่อน
chitti

8

หาก HEAD ยังไม่ได้ตั้งค่า (เช่นคุณยังไม่มีข้อผูกมัด แต่คุณยังไม่ต้องการที่จะระเบิด.gitเพราะคุณได้ตั้งค่า repo อื่น ๆ ที่คุณต้องการเก็บไว้แล้ว) คุณสามารถทำได้

git rm -rf --cached .

เพื่อ unstage ทุกอย่าง สิ่งนี้มีประสิทธิภาพเช่นเดียวกับโซลูชันของ sehe แต่หลีกเลี่ยงการล้อเลียน Git internals


นี่เป็นการบอกให้ Git ลบทุกอย่างในพื้นที่แคช
Visionary Software Solutions

1
แคชยังเป็นที่รู้จักกันในชื่อพื้นที่การจัดเตรียมดังนั้นฉันไม่แน่ใจว่าสิ่งที่คุณได้รับ
jjlin

จาก sehe, rm .git / index นั้นอันตรายมาก - อย่าลืมอ่าน NOTE ที่เขามีเกี่ยวกับ repo ใหม่! ปลอดภัยกว่านี้มากเมื่อเทียบกับ 99.999% ของเวลา ฉันไม่ได้อ่านอย่างถี่ถ้วนและต้องทำให้สำเนาการทำงานและโคลนซ้ำหลังจากทำสำเนา rm .git / index บนสำเนาการทำงานของฉัน
phpguru

อย่าใช้คำสั่งนี้! มันจะเปลี่ยนโครงการทั้งหมดเป็นสถานะที่ไม่ได้ติดตาม (รวมถึงโครงการที่ไม่ได้จัดฉาก) นี่ไม่ใช่วิธีแก้ปัญหาสำหรับคำถามเดิม ทางออกที่ถูกต้องโดยใช้คำสั่ง 'git rm' คือการระบุไฟล์ที่คุณต้องการ unstaged เท่านั้น: git rm -rf --cached <files ที่คุณต้องการ unstage>
Monte Creasor

คุณควรใช้คำสั่งนี้เฉพาะเมื่อคุณมี repo ใหม่ที่ยังไม่มีการกระทำ (นี่คือสิ่งที่ "HEAD ไม่ได้ตั้งค่า" หมายถึง) แต่คุณไม่ต้องการที่จะระเบิด.gitเพราะคุณตั้งค่า repo อื่น ๆ ที่คุณ ต้องการเก็บ ฉันได้แก้ไขเพื่ออธิบายสิ่งนี้
jjlin

5

คำเตือน: อย่าใช้คำสั่งต่อไปนี้จนกว่าคุณจะสูญเสียงานที่ไม่มีข้อผูกมัด!

การใช้git resetที่ได้รับการอธิบาย แต่คุณถามหาคำอธิบายของคำสั่งประปาเช่นกันดังนั้นที่นี่จะไป:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

คำสั่งgit ls-filesแสดงรายการไฟล์ทั้งหมดที่คอมไพล์รู้ ตัวเลือกจะ-zกำหนดรูปแบบเฉพาะของรูปแบบนั้นรูปแบบที่คาดหวังจากxargs -0นั้นจะเรียกใช้รูปแบบrm -fดังกล่าวซึ่งหมายถึงการลบออกโดยไม่ตรวจสอบเพื่อขออนุมัติ

กล่าวคือ "แสดงรายการไฟล์ทั้งหมดที่ git รู้จักและลบสำเนาในเครื่องของคุณ"

จากนั้นเราไปถึงgit diffซึ่งจะแสดงการเปลี่ยนแปลงระหว่างเวอร์ชันต่าง ๆ ของรายการที่ git รู้จัก สิ่งเหล่านี้สามารถเปลี่ยนแปลงได้ระหว่างต้นไม้ที่ต่างกันความแตกต่างระหว่างสำเนาภายในเครื่องและสำเนาระยะไกลและอื่น ๆ
ตามที่ใช้ที่นี่จะแสดงการเปลี่ยนแปลงแบบไม่สเตจ ไฟล์ที่คุณเปลี่ยนแปลง แต่ยังไม่ได้ยืนยัน ตัวเลือกนี้--name-onlyหมายถึงคุณต้องการชื่อไฟล์ (เต็ม) เท่านั้นและ--diff-filter=Dคุณสนใจไฟล์ที่ถูกลบเท่านั้น (เดี๋ยวก่อนเราไม่ได้ลบสิ่งต่าง ๆ ใช่ไหม?) จากนั้นสิ่งนี้จะถูกส่งเข้าไปในสิ่งที่xargs -0เราเห็นมาก่อนซึ่งเรียกร้องgit rm --cachedพวกเขาซึ่งหมายความว่าพวกมันจะถูกลบออกจากแคชในขณะที่ต้นไม้ทำงานควรถูกทิ้งไว้ตามลำพัง คุณเพิ่งลบไฟล์ทั้งหมดออกจากแผนผังการทำงานของคุณ ตอนนี้พวกเขาจะถูกลบออกจากดัชนีของคุณเช่นกัน

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


TL; DR: คุณเพิ่งปิดบังทุกอย่าง เริ่มต้นใหม่และใช้git resetนับจากนี้ไป


2

ฉันกลัวว่าบรรทัดแรกของบรรทัดคำสั่งเหล่านั้นถูกลบโดยไม่มีเงื่อนไขจากการทำงานคัดลอกไฟล์ทั้งหมดที่อยู่ในพื้นที่จัดเตรียมของคอมไพล์ ไฟล์ที่สองทำ unstaged ไฟล์ทั้งหมดที่ถูกติดตาม แต่ถูกลบไปแล้ว น่าเสียดายที่นี่หมายความว่าคุณจะสูญเสียการแก้ไขที่ไม่มีข้อผูกมัดใด ๆ กับไฟล์เหล่านั้น

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

git reset --hard

ฉันพูดว่า "อย่างระมัดระวัง" เนื่องจากgit reset --hard จะกำจัดการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดในสำเนาการทำงานและดัชนีของคุณ อย่างไรก็ตามในสถานการณ์เช่นนี้ดูเหมือนว่าคุณเพียงแค่ต้องการกลับไปสู่สถานะในการกระทำครั้งสุดท้ายของคุณและการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดได้สูญหายไปแล้ว

อัปเดต: ฟังจากความเห็นของคุณเกี่ยวกับคำตอบของแอมเบอร์ที่คุณยังไม่ได้สร้างความมุ่งมั่นใด ๆ (เนื่องจาก HEAD ไม่สามารถแก้ไขได้) ดังนั้นสิ่งนี้จะไม่ช่วยฉันกลัว

สำหรับวิธีท่อเหล่านั้นทำงาน: git ls-files -zและการส่งออกทั้งรายชื่อไฟล์ที่คั่นด้วยไบต์git diff --name-only --diff-filter=D -z 0(สิ่งนี้มีประโยชน์เนื่องจากไม่เหมือนกับ newlines 0ไบต์รับประกันได้ว่าจะไม่เกิดขึ้นในชื่อไฟล์บนระบบที่เหมือน Unix) โปรแกรมนี้xargsสร้างบรรทัดคำสั่งจากอินพุตมาตรฐานโดยค่าเริ่มต้นจากการรับบรรทัดจากอินพุตมาตรฐานและเพิ่มไปยังจุดสิ้นสุด ของบรรทัดคำสั่ง -0ตัวเลือกว่าจะคาดหวังว่าเข้ามาตรฐานโดยแยกจากกันโดย0ไบต์ xargsอาจเรียกใช้คำสั่งหลาย ๆ ครั้งเพื่อใช้พารามิเตอร์ทั้งหมดจากอินพุตมาตรฐานทำให้แน่ใจว่าบรรทัดคำสั่งไม่ยาวเกินไป

ตัวอย่างง่ายๆหากคุณมีไฟล์ชื่อtest.txtมีเนื้อหาดังต่อไปนี้:

hello
goodbye
hello again

... จากนั้นคำสั่งxargs echo whatever < test.txtจะเรียกใช้คำสั่ง:

echo whatever hello goodbye hello again

ฉันไม่เคยทำอะไรเลยดังนั้นมันจะบอกว่าไม่สามารถแก้ไข HEAD ได้ สิ่งที่เราทำในสถานการณ์เช่นนี้ ขอบคุณมากสำหรับการอธิบายไปป์ในรายละเอียด
sarat

8
หากคุณเพิ่งเปลี่ยนการเพิกเฉยของคอมไพล์และเพิ่มคอมไพล์ - ทั้งหมดเพื่อรวมไฟล์จำนวนมากห้ามรัน git reset - ฮาร์ดเพื่อยกเลิกการขึ้นเวที พวกเขาจะถูกลบ !!
Ajoy

5
Uwaaahh !! บางทีคุณอาจจะต้องเน้นคำว่า"อย่างรอบคอบ" ฉันเพิ่งเห็นคำสามคำว่า "git reset - ฮาร์ด" และไฟล์ที่ไม่มีการจัดเก็บของฉันคือ ... fufff !! ที่ไปแล้ว!!!!!
Vineeth Chitteti

1

หากคุณต้องการยกเลิกการเปลี่ยนแปลงทั้งหมดให้ใช้คำสั่งด้านล่าง

git reset --soft HEAD

ในกรณีที่คุณต้องการยกเลิกการเปลี่ยนแปลงและเปลี่ยนกลับจากไดเรกทอรีการทำงาน

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