ทำไม git ไม่สามารถรีเซ็ตฮาร์ด / ซอฟต์ตามเส้นทางได้?


142

$ git reset -- <file_path> สามารถรีเซ็ตตามเส้นทาง

อย่างไรก็ตาม$ git reset (--hard|--soft) <file_path>จะรายงานข้อผิดพลาดดังต่อไปนี้:

Cannot do hard|soft reset with paths.

คำตอบ:


147

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

เพียงแค่ทำการ "ฮาร์ดรีเซ็ต" สำหรับเส้นทางgit checkout HEAD -- <path>(ตรวจสอบเวอร์ชันที่มีอยู่ของไฟล์)

ซอฟต์รีเซ็ตสำหรับพา ธ ไม่สมเหตุสมผล

การรีเซ็ตแบบผสมสำหรับเส้นทางคือสิ่งที่git reset -- <path>ทำ


76
ส่วนตัวผมคิดว่าgit checkout -- <path>ควรจะแทนที่ด้วยgit reset --hard <path>. มันเข้าท่ากว่ามาก ...
vergenzt

25
git checkout -- <path>ไม่ทำการฮาร์ดรีเซ็ต จะแทนที่เนื้อหาแผนผังการทำงานด้วยเนื้อหาที่จัดฉาก git checkout HEAD -- <path>ทำการฮาร์ดรีเซ็ตสำหรับเส้นทางโดยแทนที่ทั้งดัชนีและแผนผังการทำงานด้วยเวอร์ชันจาก HEAD คอมมิต
Dan Fabulich

1
@EdPlunkett Er ประโยคที่สองในคำตอบจะบอกคุณว่าคำสั่งอื่นมีฟังก์ชันอะไรบ้าง
แอมเบอร์

17
-1: การชำระเงินเพื่อแก้ไขดังกล่าวจะไม่ลบไฟล์ออกจากสำเนาที่ใช้งานได้หากการแก้ไขดังกล่าวมีไฟล์ที่ถูกลบ reset --hardด้วยเส้นทางจะให้ชิ้นส่วนที่ขาดหายไปนี้ Git นั้นทรงพลังมากจนข้ออ้าง "เราไม่ปล่อยให้คุณทำเพื่อปกป้องตัวเอง" ถือเป็นศูนย์: มีหลายวิธีที่จะทำสิ่งที่ผิด "โดยบังเอิญ" git reflogไม่มีใครที่มีความสำคัญอยู่แล้วเมื่อคุณมี
void.pointer

1
ตามที่กล่าวไว้โดยการชำระเงิน @ void.pointer จะไม่ลบไฟล์ หากคุณต้องการพฤติกรรมที่แล้วมองไปที่นี้คำตอบ git reset --hard -- <path>แต่ฉันก็ยังหวังว่าสักวันหนึ่งเราจะได้รับ มีกรณีการใช้งานที่ถูกต้องตามกฎหมาย
Mariusz Pawelski

18

git checkout HEAD <path>คุณสามารถประสบความสำเร็จในสิ่งที่คุณกำลังพยายามที่จะทำโดยใช้

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


ใช้ขั้นตอนการชำระเงินการเปลี่ยนแปลงซึ่งไม่เหมือนกับการรีเซ็ต --soft
worc

12

คำถามที่ว่ามีอยู่แล้วตอบผมจะอธิบายว่าทำไมส่วนหนึ่ง

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

  • หากคุณระบุพา ธ จะแทนที่ไฟล์ที่ตรงกันในดัชนีด้วยไฟล์จากคอมมิต (HEAD ตามค่าดีฟอลต์) การดำเนินการนี้ไม่ส่งผลกระทบต่อโครงสร้างการทำงานเลยและโดยปกติจะใช้ตรงกันข้ามกับ git add

  • หากคุณไม่ได้ระบุเส้นทางระบบจะย้ายส่วนหัวสาขาปัจจุบันไปยังการคอมมิตที่ระบุและพร้อมกับเลือกที่จะรีเซ็ตดัชนีและโครงสร้างการทำงานเป็นสถานะของการคอมมิตนั้น นี้เพิ่มเติมพฤติกรรมที่ถูกควบคุมโดยพารามิเตอร์โหมด:
    --soft : ไม่ได้สัมผัสดัชนีและต้นไม้ทำงาน
    --mixed (ค่าเริ่มต้น): รีเซ็ตดัชนี แต่ไม่ใช่โครงสร้างการทำงาน
    - ฮาร์ด : รีเซ็ตดัชนีและโครงสร้างการทำงาน
    นอกจากนี้ยังมีตัวเลือกอื่น ๆ โปรดดูเอกสารสำหรับรายการทั้งหมดและกรณีการใช้งานบางส่วน

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

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


เป็นที่ชัดเจนว่าการรีเซ็ตมีจุดมุ่งหมายเพื่อย้ายส่วนหัวสาขาในตอนแรก แต่เนื่องจากมีฟังก์ชันเพิ่มเติมในการรีเซ็ตโครงสร้างการทำงานและดัชนีสำหรับคอมมิตทั้งหมดและฟังก์ชันการรีเซ็ตดัชนีสำหรับไฟล์เฉพาะเหตุใดจึงไม่ทำ มีฟังก์ชั่นในการรีเซ็ตโครงสร้างการทำงานสำหรับไฟล์เฉพาะหรือไม่? ฉันเชื่อว่านั่นคือสิ่งที่ OP ขอ
Danilo Souza Morães

อาจเป็นเพราะฟังก์ชั่นนั้น (การรีเซ็ตโครงสร้างการทำงานสำหรับไฟล์เฉพาะ) มีอยู่แล้วในgit checkoutคำสั่ง? และการรีเซ็ตเพื่อทำสิ่งเดียวกันนี้จะทำให้ผู้ใช้สับสนต่อไป คำตอบของฉันคือ--hardตัวเลือกนั้นไม่สามารถใช้ได้กับไฟล์บางไฟล์เนื่องจากเป็นโหมดสำหรับการรีเซ็ตสาขาไม่ใช่การรีเซ็ตดัชนี และการรีเซ็ตทรีการทำงานมีชื่อว่าการชำระเงินดังที่คุณสามารถอ่านได้ในคำตอบอื่น ๆ ทั้งหมดนี้เป็นเพียงการออกแบบอินเทอร์เฟซผู้ใช้ IMHO ของ Git ที่ไม่ดี
ผู้ใช้

เปรียบเทียบตัวเลือกแรกกับgit checkout: git reset --กำหนดดัชนีเท่านั้นในขณะที่git checkout --กำหนดโครงสร้างการทำงานเท่านั้น?
seeker_of_bacon

3

มีเหตุผลที่สำคัญมากที่อยู่เบื้องหลังที่: หลักการของcheckoutresetและ

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

ในทางกลับกันการรีเซ็ตคอมไพล์ไม่มีบทบาทนี้ ตามชื่อที่แนะนำมันจะรีเซ็ตการอ้างอิงปัจจุบัน แต่จะมีที่เก็บเป็นแหล่งที่มาเสมอโดยไม่ขึ้นกับ "reach" (--soft, --mixed หรือ --hard)

สรุป:

  • ชำระเงิน : จากที่ใดก็ได้ (ดัชนี / repo กระทำ) -> ต้นไม้ทำงาน
  • รีเซ็ต : Repo กระทำ -> เขียนทับ HEAD (และเลือกดัชนีและโครงสร้างการทำงาน)

ดังนั้นสิ่งที่อาจทำให้สับสนเล็กน้อยคือการมีอยู่ของgit reset COMMIT -- filesตั้งแต่ "การเขียนทับ HEAD" กับไฟล์บางไฟล์เท่านั้นที่ไม่สมเหตุสมผล!

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

ดังนั้นจึงgit reset -- <files>มีความพิเศษอยู่แล้ว: มันจะไม่เขียนทับ HEAD IMHO รูปแบบดังกล่าวทั้งหมดจะเป็นข้อยกเว้น แม้ว่าเราจะสามารถสร้าง--hardเวอร์ชันได้ แต่คนอื่น ๆ (เช่น--soft) ก็ไม่สมเหตุสมผล


ฉันชอบคำตอบนี้ จริงๆแล้วgit reset -- <files>ดูเหมือนว่ามันถูกเพิ่มเข้ามาเพราะนี่เป็นคุณสมบัติที่มีประโยชน์ แต่ไม่มีใครแน่ใจว่าควรใส่คำสั่งใด โชคดีที่ตอนนี้เรามีสติมากขึ้นgit restoreซึ่งมีฟังก์ชันการทำงานgit checkout -- <path> git checkout <commit> -- <path>และgit reset [<commit>] -- <path>มีค่าเริ่มต้นที่ดีกว่าและคุณสมบัติอื่น ๆ ที่คุณไม่สามารถทำได้มาก่อน (ตรงกันข้ามกับคำตอบที่ยอมรับกล่าวในที่สุดคุณก็สามารถกู้คืนโครงสร้างที่ใช้งานได้โดยไม่ต้องสัมผัสดัชนี)
Mariusz Pawelski

3

ตรวจสอบให้แน่ใจว่าคุณใส่เครื่องหมายทับระหว่างต้นทางหรือต้นน้ำ (ต้นทาง) และสาขาจริง:

git reset --hard origin/branch

หรือ

git reset --hard upstream/branch`

0

คำอธิบาย

git resetคู่มือรายการ 3 วิธีในการภาวนา:

  • 2 เป็นไฟล์ที่ชาญฉลาด: สิ่งเหล่านี้ไม่ส่งผลกระทบต่อโครงสร้างการทำงานแต่ทำงานเฉพาะกับไฟล์ในดัชนีที่ระบุโดย<paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 คือการกระทำที่ชาญฉลาด: ทำงานกับไฟล์ทั้งหมดในการอ้างอิง<commit>และอาจส่งผลต่อโครงสร้างการทำงาน:

    • git reset [<mode>] [<commit>]

ไม่มีโหมดการเรียกใช้ที่ทำงานเฉพาะกับไฟล์ที่ระบุและส่งผลต่อโครงสร้างการทำงาน

วิธีแก้ปัญหา

หากคุณต้องการทั้งสอง:

  • รีเซ็ตเวอร์ชันดัชนี / แคชของไฟล์
  • ชำระเงินไฟล์ (กล่าวคือทำให้แผนผังการทำงานตรงกับดัชนีและเวอร์ชันคอมมิต)

คุณสามารถใช้นามแฝงนี้ในไฟล์กำหนดค่า git ของคุณ:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

จากนั้นคุณสามารถเลือกทำอย่างใดอย่างหนึ่ง:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic สำหรับreco: reset && check out)


-2

git reset --soft HEAD ~ 1 ชื่อไฟล์เลิกทำการคอมมิต แต่การเปลี่ยนแปลงยังคงอยู่ในโลคัล ชื่อไฟล์อาจเป็น - สำหรับไฟล์ที่คอมมิตทั้งหมด


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