git selective ยกเลิกการเปลี่ยนแปลงในเครื่องจากไฟล์


149

ใน repo git ของฉันซึ่งติดตาม repo svn ฉันได้ทำการแก้ไขเป็นไฟล์เดียว

ตอนนี้ฉันต้องการย้อนกลับการเปลี่ยนแปลงเหล่านั้น (เช่น svn revert) แต่มีเพียงบางส่วนของไฟล์

ฉันต้องการดูความแตกต่างของไฟล์ละทิ้ง (ย้อนกลับ) การเปลี่ยนแปลงที่ฉันไม่ต้องการและเก็บการเปลี่ยนแปลงที่ฉันต้องการ

git add -i 

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

คำตอบ:


91

git checkout -pคุณสามารถทำเช่นนั้นได้โดยตรงกับ ดูคำตอบของ Daniel Stutzbachด้านล่าง


คำตอบเก่า (ก่อนcheckout -pถูกแนะนำ):

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

git add -i

(เลือก hunks ที่คุณต้องการเก็บไว้)

git commit -m "tmp"

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

git reset --hard HEAD

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

git reset --mixed HEAD^

สิ่งนี้จะลบการคอมมิทสุดท้าย ('tmp') แต่จะทำการแก้ไขในไดเร็กทอรีการทำงานของคุณ

แก้ไข: แทนที่--softด้วย--mixedเพื่อล้างพื้นที่จัดเตรียม


สิ่งนี้จะยอมรับการเปลี่ยนแปลงที่ฉันต้องการเก็บไว้ใช่ไหม ฉันไม่ต้องการยอมรับการเปลี่ยนแปลงเหล่านั้น บางทีฉันอาจจะทำอย่างจริงจังเกินไป บางทีฉันควรจะผ่อนคลายตอนนี้เพราะมันมีอยู่ใน repo ท้องถิ่น btw git reset - soft HEAD ^ ทำอะไร?
Pradeep

"git reset - soft HEAD ^" ยกเลิกการกระทำในแง่ที่ทำให้ไดเรกทอรีทำงานและดัชนีเหมือนเดิมและย้ายสาขาปัจจุบันที่ยอมรับ
Jakub Narębski

ขอบคุณ Jakub เปาโลเหตุใดจึงต้องมีการรีเซ็ตแบบอ่อนที่หัว - 1 ที่นี่ การคอมมิทบางส่วนและฮาร์ดรีเซ็ตควรจะเพียงพอหรือไม่ที่จะเปลี่ยนแปลงและทิ้งสิ่งอื่น ๆ
Pradeep

1
คำตอบของ Daniel ด้านล่างนั้นง่ายมากและดูเหมือนว่าจะทำอย่างไร
Umang

309

ฉันเชื่อว่าคุณสามารถทำได้ง่ายๆด้วย:

git checkout -p <optional filename(s)>

จาก manpage:

   −p, −−patch
       Interactively select hunks in the difference between the <tree−ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree−ish> was specified, the index).
       This means that you can use git checkout −p to selectively discard
       edits from your current working tree.

1
นอกจากนี้หากคุณไม่ต้องการเลือกแบบนี้คุณสามารถใช้ "git checkout - <file> ... " เพื่อยกเลิกการเปลี่ยนแปลง
db42

มันจัดการกับไดเรกทอรีหรือไม่
bbum

1
ดูเหมือนว่าจะล้มเหลวมากสำหรับฉันเมื่อละทิ้งการเปลี่ยนแปลง ("ข้อผิดพลาด: การแก้ไขล้มเหลว <file>", "ข้อผิดพลาด: <file> โปรแกรมแก้ไขใช้ไม่ได้") พอฉันจะได้รับข้อผิดพลาดเหล่านั้นเมื่อใช้aตัวเลือกในโหมดแก้ไขเพื่อทิ้งไฟล์ทั้งหมด แต่ก็ใช้git checkout -- <file>งานได้ตามที่คาดไว้ ใครรู้ว่าทำไม
chrnola

ฉันมีข้อผิดพลาดสองสามครั้งถ้าไฟล์นั้นได้รับการแก้ไขแล้วดังนั้นแพทช์อินเทอร์แอกทีฟก็ล้าสมัยด้วยแพทช์ที่ใช้กับไฟล์ปัจจุบัน มันเกิดขึ้นเมื่อใช้เครื่องมือ gui เช่น tree source ถ้าฉันทิ้งก้อนใหญ่สองครั้งโดยไม่ตั้งใจ ครั้งที่สองจะทำให้เกิดข้อผิดพลาดนั้น
phyatt

3

คุณสามารถเรียกใช้git diffไฟล์บันทึก diff ผลแก้ไขเพื่อลบการเปลี่ยนแปลงที่คุณไม่ต้องการที่จะประหยัดแล้วเรียกมันผ่านpatch -Rเพื่อยกเลิกการ diffs เหลือ

git diff file.txt> patch.tmp
# edit patch.tmp เพื่อลบ hunks ที่คุณต้องการเก็บไว้
patch -R <patch.tmp

ฉันมี 2 hunks ในไฟล์ patch และลบมันออก ไม่แน่ใจว่าเกิดจากอะไร แต่ตัวแก้ไข -R ยังคงถูกปฏิเสธด้วยสิ่งนี้
Pradeep

2
คุณพูดถึงในความคิดเห็นอื่นที่git diffแสดงไฟล์ทั้งหมดเมื่อมีการเปลี่ยนแปลง สิ่งนี้มักจะเกิดขึ้นเมื่อคุณบันทึกไฟล์โดยใช้การสิ้นสุดบรรทัดที่แตกต่างจากที่เคยเป็นก่อนหน้านี้ นี่อาจเป็นสาเหตุpatchให้ปฏิเสธไฟล์แพตช์ เสียงเหมือนสิ่งที่อาจเกิดขึ้น?
Greg Hewgill

คุณพูดถูก การสิ้นสุดบรรทัดจะถูกสลับเมื่อใดก็ตามที่ฉันใช้คำสั่ง patch ฉันอยู่บน windows และใช้ครีม / เป็นกลุ่ม ต้องเรียงลำดับออกก่อนฉันคิดว่า
Pradeep

ฉันไม่สามารถแก้ไขปัญหาได้ด้วยการแก้ไขบน windows แม้ว่าฉันจะแน่ใจว่างานนี้ฉันชอบที่จะใช้สูตรของเปาโล สำหรับความรักของคำสั่งแบบโต้ตอบเหล่านั้นในการทำงานกับ diffs โดยใช้ git add -i
Pradeep

3

ดูเหมือนว่าคุณต้องการ

 git revert --no-commit $REVSISON 

จากนั้นคุณสามารถใช้

 git diff --cached

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

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


ฉันย้อนกลับไปตามที่คุณพูดถึงการแก้ไขก่อนหน้านี้ (ถูกต้องหรือไม่) และตอนนี้คอมไพล์ diff เพียงแสดงไฟล์ทั้งหมดที่มีการเปลี่ยนแปลง มันควรจะแสดงให้เห็นถึงการแก้ไขที่ฉันทำไปแล้ว?
Pradeep

1

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

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

git add -i <file>

จากนั้นทิ้งการเปลี่ยนแปลงที่คุณไม่ต้องการเก็บไว้โดยดูที่เวอร์ชันดัชนี:

git checkout -- <file>

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

git reset -- <file>

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

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

git reset <commit_before_first_unwanted_change> -- <file>

จากนั้นคุณสามารถติดตามสูตรก่อนหน้าของgit add -i <file>ขั้นตอนการเปลี่ยนแปลงเหล่านั้นที่คุณต้องการเก็บgit checkout -- <file>ทิ้งการเปลี่ยนแปลงที่ไม่ต้องการและgit reset -- <file>' ไม่เปลี่ยน' การเปลี่ยนแปลง


0

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

เปิดไฟล์ในตัวแก้ไข netbeans (ซึ่งมาพร้อมกับการสนับสนุน git) Netbeans ใส่เครื่องหมายสีแดง / เขียว / น้ำเงินที่หมายเลขบรรทัดเพื่อระบุว่าเนื้อหาถูกลบ / เพิ่ม / แก้ไข (ตามลำดับ)

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

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