วิธีการแก้ไขข้อขัดแย้งซ่อนเร้น Git โดยไม่ต้องกระทำ?


495

ตามที่ถามในคำถามนี้ฉันต้องการทราบวิธีแก้ไขข้อขัดแย้งgit stash popโดยไม่เพิ่มการแก้ไขทั้งหมดในการคอมมิชชัน (เช่น "git stash pop" โดยไม่มีข้อขัดแย้ง)

วิธีการปัจจุบันของฉันไม่ดีมากเพราะฉันทำเช่นนี้

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[อัพเดต] วิธีสร้างภาพซ้ำ:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

2016-06-27: เพิ่มไฟล์ใหม่ที่ชื่อว่า 'third' ลงในตัวอย่างเพื่อแสดงวิธีแก้ไขปัญหาเช่นวิธีแก้ปัญหาจาก scy ใช้งานได้เฉพาะกับ HEADs ที่ว่างเปล่า แต่ไม่แก้ไขปัญหาเริ่มต้นที่ HEAD ไม่มีเนื้อหาเดียวกันเช่น สำหรับที่git stash popปราศจากความขัดแย้ง


ดังนั้นgit addไฟล์ความขัดแย้งที่ได้รับการแก้ไขแล้วของคุณจัดแสดงไว้ในดัชนีอย่างมีประสิทธิภาพและคุณต้องการที่จะไม่ได้อยู่ในดัชนีของเราหรือไม่
Romain

ใช่ถูกแล้ว. ฉันต้องการพฤติกรรมที่git stash popมีเมื่อไม่มีข้อขัดแย้งเกิดขึ้น (แต่ด้วยการแจ้งเตือนว่าต้องรวมไฟล์ใด)
สเวน

2
ดูเหมือนว่าคำตอบของเรื่องนี้อยู่ที่นี่: stackoverflow.com/questions/3945826/git-stash-questions ในคำตอบที่เลือกในความคิดเห็นที่ 4 อดัมอธิบายว่าทำไม git ถึงทำสิ่งนี้
Patrick

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

คำตอบ:


509

อย่าทำตามคำตอบอื่น ๆ

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

น้ำยาทำความสะอาด

วิธีแก้ปัญหาต่อไปนี้ดูจะสะอาดกว่าสำหรับฉันมากและก็แนะนำโดย Git ด้วย - ลองใช้งานgit statusในพื้นที่เก็บข้อมูลที่มีข้อขัดแย้ง:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

ดังนั้นให้ทำในสิ่งที่ Git แนะนำ (โดยไม่ทำสิ่งใดที่ไร้ประโยชน์):

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

แปลเป็นบรรทัดคำสั่ง:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

คำอธิบายของพฤติกรรมเริ่มต้น

มีสองวิธีการทำเครื่องหมายความขัดแย้งการแก้ไขคือและgit add git resetในขณะที่git resetทำเครื่องหมายข้อขัดแย้งตามที่ได้รับการแก้ไขและลบไฟล์ออกจากดัชนีgit addยังทำเครื่องหมายข้อขัดแย้งตามที่ได้รับการแก้ไข แต่เก็บไฟล์ไว้ในดัชนี

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

ผสานเครื่องมือ

ฉันขอแนะนำให้ใช้เครื่องมือผสานแบบ 3 ทางใด ๆเพื่อแก้ไขข้อขัดแย้งเช่นKDiff3 , Meldฯลฯ แทนที่จะทำด้วยตนเอง มันมักจะแก้ปัญหาความขัดแย้งทั้งหมดหรือส่วนใหญ่โดยอัตโนมัติเอง มันประหยัดเวลามาก !


32
@kamalpal ดูเหมือนว่าจะจำเป็นเมื่อgit stash popล้มเหลวด้วยความขัดแย้ง
Emile Bergeron

21
@kamalpal ใช่ Git ยังแจ้งให้คุณทราบว่าที่เก็บของไม่ได้ถูกทิ้งไว้ในกรณีที่มีข้อขัดแย้ง และคำถามก็เกี่ยวกับกรณีเช่นนี้ดังนั้นคุณต้องดำเนินการจริงๆgit stash dropเว้นแต่คุณต้องการเก็บซ่อนไว้
David Ferenczy Rogožan

@ DavidFerenczyRogožan Git ไม่ได้แจ้งให้ฉันทราบเลยว่ามันไม่ได้ทำให้รายการที่เก็บซ่อน เวอร์ชั่น 2.17.1 ที่นี่
Robert Siemer

298

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

git status พูดว่า:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

ตกลง. ฉันตัดสินใจไปกับสิ่งที่ Git แนะนำ: ฉันแก้ไขข้อขัดแย้งและมุ่งมั่น:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

ตอนนี้สำเนาการทำงานของฉันอยู่ในสถานะที่ฉันต้องการ แต่ฉันได้สร้างความมุ่งมั่นที่ฉันไม่ต้องการ ฉันจะกำจัดสิ่งที่ส่งมอบโดยไม่แก้ไขสำเนาการทำงานของฉันได้อย่างไร เดี๋ยวก่อนมีคำสั่งยอดนิยมสำหรับสิ่งนั้น!

git reset HEAD^

สำเนาการทำงานของฉันไม่มีการเปลี่ยนแปลง แต่การกระทำ WIP หายไป นั่นคือสิ่งที่ฉันต้องการ! (โปรดทราบว่าฉันไม่ได้ใช้--softที่นี่เพราะหากมีไฟล์ที่ผสานอัตโนมัติในที่เก็บของคุณไฟล์เหล่านั้นจะถูกจัดฉากอัตโนมัติดังนั้นคุณจะต้องจบด้วยไฟล์เหล่านี้ที่ถูกจัดฉากอีกครั้งหลังจากresetนั้น)

แต่ยังมีอีกสิ่งหนึ่งที่เหลืออยู่: man page สำหรับgit stash popเตือนเราว่า"การใช้สถานะอาจล้มเหลวเนื่องจากความขัดแย้งในกรณีนี้มันไม่ได้ถูกลบออกจากรายการสะสมคุณต้องแก้ไขข้อขัดแย้งgit stash dropด้วยตนเองและโทรด้วยตนเองภายหลัง" นั่นคือสิ่งที่เราทำตอนนี้:

git stash drop

และเสร็จแล้ว


34
มีความอัปลักษณ์ที่สืบทอดมามากมายโดยเจตนาที่จะต้องทำการรีเซ็ต HEAD ^ ... สำหรับสิ่งที่ควรมีผลกับต้นไม้ทำงาน

6
ทำไมไม่เพียงแค่แก้ไขข้อขัดแย้งแล้วgit add <resolved conflict files>ตามด้วยgit reset HEAD?
BoltzmannBrain

ขอขอบคุณสำหรับข้อเสนอแนะ แต่สิ่งนี้ไม่ได้แก้ไขปัญหาเบื้องต้นว่านี่ไม่ใช่พฤติกรรมเดียวกันเช่นgit stash popไม่มีความขัดแย้ง เพียงเพิ่มไฟล์อื่นลงใน HEAD ก่อนที่จะทำสิ่งที่ขัดแย้งกันgit stash popและมากกว่าที่คุณgit commit -a -m WIPจะเพิ่มไฟล์ใหม่ลงในการคอมมิท แต่ไม่มีข้อขัดแย้งไฟล์ใหม่จะอยู่ใน HEAD แต่ไม่ใช่git stash popไฟล์
Sven

7
ฉันไม่คิดว่าจำเป็นต้องทำอะไรก่อนแล้วจึงเลิกทำ เพียงรีเซ็ตจากคำตอบของ Dawid Ferenczyจะทำเช่นเดียวกัน
vladkras

3
สำหรับผู้ใช้ windows นั้น^จะใช้เป็นสายต่อเนื่องพิเศษและจะทำให้คุณนั่งอยู่ที่ More หรือไม่? พรอมต์แทนการดำเนินการคำสั่ง ใช้แทน: git reset --soft HEAD~1. ดูวิธีทำ i-delete-unpushed-git-commits ไหม?
mrfelis

87

แทนที่จะเพิ่มการเปลี่ยนแปลงที่คุณทำเพื่อแก้ไขข้อขัดแย้งคุณสามารถใช้git reset HEAD fileเพื่อแก้ไขข้อขัดแย้งโดยไม่แสดงการเปลี่ยนแปลงของคุณ

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

เป็นไปได้ว่าควรมีโหมดการรีเซ็ตที่ทำทั้งสองอย่างพร้อมกันแม้ว่าจะยังไม่ได้ทำตอนนี้


2
โหมดการรีเซ็ตเป็นโหมดที่ฉันค้นหา - วิธีแก้ไขอื่น ๆ นั้นเหมือนกับโหมดที่ฉันอธิบายและไม่เหมาะสำหรับไฟล์มากกว่า 5 ไฟล์
Sven

25
และใช้ "git stash drop" ในภายหลังเพื่อเสร็จสิ้น "git stash pop"
David Liu

2
แม้ว่าคำถามจะไม่ถามคำถามนี้อย่างชัดเจน แต่ก็อาจเป็นประโยชน์ในการอัปเดตคำตอบเพื่อรวม "git stash drop" เนื่องจาก stash ไม่ได้ถูกทิ้งโดยอัตโนมัติในกรณีที่มีข้อขัดแย้ง
Abhishek Pathak

29
git checkout stash -- .

ทำงานให้ฉัน

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


สิ่งนี้จะช่วยได้เมื่อ "git pull - autostash" แนะนำการรวมที่ไม่ต้องการและการชำระเงิน git - เขียนทับข้อขัดแย้งจากที่ซ่อน
Alec Istomin

11
git add .
git reset

git add . จะแสดงไฟล์ทั้งหมดที่บอก git ว่าคุณได้แก้ไขข้อขัดแย้งแล้ว

git reset จะ unstage ไฟล์ staged ทั้งหมดโดยไม่สร้างการคอมมิต


จริงๆแล้วนี่ไม่ใช่คำตอบที่ไม่ดีมันก็เป็นอย่างgit add -uนั้นgit reset
ebob

4

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

git stash apply --index

นี่คือคำอธิบายแบบเต็ม:

http://git-scm.com/book/en/Git-Tools-Stashing


ขอบคุณสำหรับคำแนะนำนี้ แต่สิ่งนี้จะไม่ช่วยเมื่อฉันทำไปแล้วgit stash pop- หรือมีวิธีที่จะคืนค่าสิ่งนี้และทำอย่างไรgit stash apply --indexเมื่อฉันพบว่าgit stash popจะมีข้อขัดแย้งหรือไม่?
Sven

ฉันได้เพิ่มตัวอย่างเกี่ยวกับวิธีสร้างสิ่งนี้ - ลองจินตนาการว่าคุณกำลังแก้ไขมากกว่า 10 ไฟล์ดังนั้นคุณจึงไม่ทราบว่าคุณแก้ไขไฟล์ใดอยู่นอกคลัง
Sven

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

ลองใช้เพียงแค่นี้และมันจะไม่ทำงานหลังจากที่คุณมีไฟล์ที่อยู่ในสถานะขัดแย้ง แม้ว่าคุณจะแก้ไขข้อขัดแย้งด้วยตนเอง
Sam3k

2

git stash branchจะทำงานซึ่งจะสร้างสาขาใหม่ให้คุณตรวจสอบการกระทำที่คุณทำเมื่อคุณ stashed งานของคุณนำงานของคุณไปที่นั่นอีกครั้งและจากนั้นปล่อย stash หากใช้สำเร็จ ตรวจสอบนี้


2

วิธีที่เร็วที่สุดที่ฉันพบคือการแก้ไขข้อขัดแย้งจากนั้นทำgit add -uแล้วทำสิ่งgit reset HEADนั้นไม่ได้เกี่ยวข้องกับการกระทำ


1

ตามคำถามที่รวบรวมได้หลังจากแก้ไขความขัดแย้งแล้วgit add <file>เป็นแนวทางที่ถูกต้อง

หลังจากอ่านความคิดเห็นนี้แล้วฉันเข้าใจว่าการเปลี่ยนแปลงจะถูกเพิ่มลงในดัชนีโดยอัตโนมัติ (ตามการออกแบบ) นั่นเป็นเหตุผลที่git add <file>ทำให้กระบวนการแก้ไขข้อขัดแย้งเสร็จสมบูรณ์


-1

ไม่ใช่วิธีที่ดีที่สุดที่จะทำ แต่ใช้งานได้:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file

คำตอบนี้ดูเหมือนผิดปกติกับฉันเพราะมันจะยกเลิกการเปลี่ยนแปลงทั้งหมดfile/path/to/your/fileซึ่งไม่ใช่สิ่งที่ OP ถาม AFAIU
oromoiluig
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.