"git pull" สามารถซ่อนและป๊อปการเปลี่ยนแปลงที่รอดำเนินการโดยอัตโนมัติได้หรือไม่


122

ฉันรู้วิธีแก้ปัญหานี้:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

แต่ไม่ได้มีวิธีการที่จะให้git pullทำstashและpopการเต้นรำสำหรับฉันหรือไม่

หากคำสั่งนี้มีชื่ออื่นก็ใช้ได้

การสร้างนามแฝงเชลล์git stash; git pull; git stash popเป็นวิธีแก้ปัญหา แต่ฉันค้นหาโซลูชันที่ดีกว่า


แล้วนามแฝงของgitล่ะ?
Яois

20
การใช้งานโดยใช้git stash; git pull; git stash popโปรแกรมเป็นสิ่งที่อันตรายเพราะหากไม่มีอะไรให้ซ่อนgit stashจะเป็นการไม่ดำเนินการ แต่git stash popจะปรากฏที่ซ่อนสุดท้าย (ถ้ามี) ซึ่งแทบจะไม่ใช่สิ่งที่คุณต้องการ ผู้ใช้ torek มีโพสต์ดีๆเกี่ยวกับเรื่องนี้ใน Stack Overflow แต่หาไม่เจอ ...
jub0bs

2
@Jubobs อันนี้เหรอ stackoverflow.com/a/20412685/6309หรืออันนี้ stackoverflow.com/a/20480591/6309
VonC

1
@guettli ฉันไม่ได้หมายความว่าคำถามของคุณซ้ำกันฉันแค่ตอบความคิดเห็นของ Jubobs
VonC

2
ในขั้นตอนต่อไปการดำเนินการจะประสบความสำเร็จก็ต่อเมื่อสามารถใช้ที่ซ่อนได้อย่างหมดจดหลังจากดึง หากมีข้อขัดแย้งการดำเนินการทั้งหมดจะล้มเหลวในเชิงอะตอมเพื่อไม่ให้ต้นไม้เปลี่ยนแปลง นี่คือสิ่งที่ฉันต้องการจะทำ: ดึงการเปลี่ยนแปลงที่มีในเครื่องของฉันรวมเข้าด้วยกันมิฉะนั้นจะล้มเหลวด้วยข้อผิดพลาดและให้ฉันตัดสินใจด้วยตนเองว่าจะทำอย่างไรต่อไป `` ธุรกรรม '' ประเภทนี้เป็นไปได้หรือไม่?
Ed Avis

คำตอบ:


185

สำหรับ Git 2.6+ (เผยแพร่ 28 กันยายน 2015)

เท่านั้น git config การตั้งค่าที่น่าสนใจคือ:

rebase.autoStash

(ด้วย Git 2.27, Q2 2020 ตอนนี้คุณมีmerge.autostashแล้วดูด้านล่าง)

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

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

รวมกับ:

pull.rebase

เมื่อเป็นจริงจะแตกแขนงใหม่ที่ด้านบนของสาขาที่ดึงข้อมูลแทนที่จะรวมสาขาเริ่มต้นจากรีโมตเริ่มต้นเมื่อเรียกใช้ "git pull"

git config pull.rebase true
git config rebase.autoStash true

นั่นจะเพียงพอสำหรับการgit pullทำงานง่ายๆแม้ในต้นไม้ที่สกปรก
ไม่จำเป็นต้องใช้นามแฝงในกรณีนั้น


ดูกระทำ 53c76dc (4 กรกฎาคม 2015) โดยเควิน Daudt (Ikke )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ e69b408 , 17 สิงหาคม 2015)

pull: อนุญาตให้ต้นไม้สกปรกเมื่อrebase.autostashเปิดใช้งาน

rebase เรียนรู้ที่จะซ่อนการเปลี่ยนแปลงเมื่อพบผังงานสกปรก แต่git pull --rebaseไม่ทำ

ตรวจสอบว่าทรีการทำงานสกปรกเมื่อrebase.autostashไม่ได้เปิดใช้งานเท่านั้น


หมายเหตุ: หากคุณต้องการดึงโดยไม่มีการrebase.autoStash trueตั้งค่าอัตโนมัติ (แม้ว่าจะตั้งค่าไว้) คุณมีตั้งแต่ git 2.9 (มิถุนายน 2016):

 pull --rebase --no-autostash

ดูกระทำ 450dd1d , กระทำ 1662297 , กระทำ 44a59ff , กระทำ 5c82bcd , กระทำ 6ddc97c , กระทำ eff960b , กระทำ efa195d (2 เมษายน 2016) และกระทำ f66398e , กระทำ c48d73b (21 มีนาคม 2016) โดยMehul เชน (mehul2029 )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 7c137bb , 13 เมษายน 2016)

ยอมรับ f66398eโดยเฉพาะ ได้แก่ :

pull --rebase: เพิ่ม--[no-]autostashธง

หากrebase.autoStashตั้งค่าตัวแปรคอนฟิกูเรชันจะไม่มีวิธีใดที่จะลบล้างตัวแปรสำหรับ " git pull --rebase" จากบรรทัดคำสั่งได้

สอน " git pull --rebase" --[no-]autostashแฟล็กบรรทัดคำสั่งซึ่งจะแทนที่ค่าปัจจุบันของrebase.autoStashif set เนื่องจาก " git rebase" เข้าใจ--[no-]autostashตัวเลือกนี้จึงเป็นเพียงเรื่องของการส่งผ่านตัวเลือกเพื่อเรียก " git rebase" เมื่อ " git pull --rebase" ที่อ้างอิง


คำเตือน: ก่อน Git 2.14 (Q3 2017) " git pull --rebase --autostash" จะไม่ซ่อนอัตโนมัติเมื่อประวัติท้องถิ่นส่งต่อไปยังต้นน้ำอย่างรวดเร็ว

ดูกระทำ f15e7cf (1 มิถุนายน 2017) โดยไทเลอร์เตาอั้งโล่ (tylerbrazier )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 35898ea , 5 มิถุนายน 2017)

pull: ff --rebase --autostashทำงานใน repo ที่สกปรก

เมื่อgit pull --rebase --autostashอยู่ในที่เก็บที่สกปรกส่งผลให้มีการกรอไปข้างหน้าไม่มีสิ่งใดที่ถูกบันทึกอัตโนมัติและการดึงล้มเหลว
นี่เป็นเพราะทางลัดเพื่อหลีกเลี่ยงการเรียกใช้ rebase เมื่อเราสามารถกรอไปข้างหน้าได้ แต่การตั้งค่าอัตโนมัติจะถูกละเว้นใน codepath นั้น


อัปเดต: Mariusz Pawelskiถามคำถามที่น่าสนใจในความคิดเห็น :

ดังนั้นทุกคนกำลังเขียนเกี่ยวกับautostashเวลาที่คุณทำ rebase (หรือpull --rebase)

แต่ไม่มีใครคือการเกี่ยวกับ autostashing เมื่อคุณทำดึงปกติที่มีการผสาน
จึงไม่มีสวิตช์อัตโนมัติสำหรับสิ่งนั้น? หรือฉันขาดอะไรไป? ฉันชอบทำgit pull --rebaseแต่ OP ถามเกี่ยวกับการดึงคอมไพล์ " มาตรฐาน "

ตอบ:

หัวข้อเดิมถกคุณลักษณะ autostash นี้ก็ถูกนำมาใช้อย่างชาญฉลาดทั้งgit pull(ผสาน) git pull --rebaseและ

แต่ ... Junio ​​C Hamano (ผู้ดูแลระบบ Git) ตั้งข้อสังเกตว่า:

หากpull-mergeสิ่งเหล่านี้เป็นสิ่งที่ก่อให้เกิด "ความรำคาญ" ที่ทำให้เกิดหัวข้อนี้ตามคำจำกัดความการเปลี่ยนแปลงในเครื่องจะทับซ้อนกับการผสานและ "stash pop" ภายในนี้จะสัมผัสเส้นทางที่การผสานสัมผัสและไม่น่าจะส่งผลให้ "หลุด "แต่ปล่อยให้ความขัดแย้งต่อไปได้รับการแก้ไข

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

สมการนี้ค่อนข้างแตกต่างกันไปสำหรับ "pull-rebase" เนื่องจาก "rebase" ยืนยันว่าให้คุณเริ่มต้นจากโครงสร้างการทำงานที่สะอาดดังนั้นการ "ดาวน์โหลดแล้วหยุด" จะรู้สึกว่าใหญ่กว่า ฉันมีความสงสัยว่าการคลายปัญหานั้นอาจเป็นการแก้ไขปัญหาที่แท้จริงได้มากกว่า

ดังนั้นสำหรับการดึงผสานแบบคลาสสิกจะเป็นการดีกว่าที่จะ:

ขอแนะนำให้ผู้ใช้ที่จะคิดเกี่ยวกับธรรมชาติของ WIP เขาได้ในโครงสร้างการทำงานก่อนที่จะใช้ว่า "git pull "
มันเป็นสัตว์ร้ายที่ซับซ้อนเกินไปที่อาจรบกวนสิ่งที่คนอื่นกำลังทำอยู่หรือเป็นการเปลี่ยนแปลงเล็กน้อยที่เขาสามารถซ่อนตัวและโผล่กลับมาได้?

หากเป็นแบบเดิมเขาจะทำได้ดีกว่าทำ " checkout -b" ทำงานต่อไปจนกว่าการเปลี่ยนแปลงในท้องถิ่นจะมีรูปร่างที่ดีขึ้นและ "กระทำ" ก่อนที่จะดึงเข้าสู่สาขาเดิม

ถ้าเป็นอย่างหลังเขาควรทำ:

  • " git pull",
  • หลังจากพบว่าขัดแย้งกันให้เรียกใช้
    • git stash,
    • git merge FETCH_HEAD และ
    • git stash pop

ที่ถูกกล่าวว่ามี Git 2.27 (Q2 2020), " git pull" เรียนรู้ที่จะเตือนเมื่อไม่มีpull.rebaseการกำหนดค่าที่มีอยู่และไม่--[no-]rebaseหรือ--ff-onlyจะได้รับ (ซึ่งจะส่งผลให้เกิดการผสาน)

ดูกระทำ d18c950 (10 มีนาคม 2020) โดยอเล็กซ์ Henrie (alexhenrie )
(ผสานโดยJunio ​​C Hamano - gitster-ในการกระทำ 1c56d6f , 27 มี.ค. 2020)

pull: เตือนหากผู้ใช้ไม่ได้บอกว่าจะสร้างฐานข้อมูลใหม่หรือจะรวม

ลงนามโดย: Alex Henrie

บ่อยครั้งที่ผู้ใช้ Git มือใหม่มักลืมพูดว่า " pull --rebase" และจบลงด้วยการรวมที่ไม่จำเป็นจากต้นน้ำ

สิ่งที่พวกเขามักต้องการคือ " pull --rebase" ในกรณีที่ง่ายกว่าหรือ " pull --ff-only" เพื่ออัปเดตสำเนาของสาขาการรวมหลักและสร้างฐานงานใหม่แยกกัน ตัวแปรการกำหนดค่าที่มีอยู่เพื่อช่วยให้พวกเขาในกรณีที่เรียบง่าย แต่มีกลไกที่จะทำให้ผู้ใช้เหล่านี้ตระหนักถึงมันไม่มี
pull.rebase

ออกข้อความเตือนเมื่อไม่มี--[no-]rebaseตัวเลือกจากบรรทัดคำสั่งและไม่มีpull.rebaseการกำหนดค่าตัวแปร
สิ่งนี้จะทำให้ผู้ที่ไม่เคยต้องการ " pull --rebase" ไม่สะดวกซึ่งไม่ต้องทำอะไรเป็นพิเศษ แต่ผู้ใช้จะต้องจ่ายค่าใช้จ่ายของความไม่สะดวกเพียงครั้งเดียวซึ่งควรเป็นค่าใช้จ่ายที่สมเหตุสมผลเพื่อช่วยเหลือผู้ใช้ใหม่จำนวนหนึ่ง


ด้วย Git 2.27 (Q2 2020) ตัวเลือก" git merge" จะเรียนรู้ " --autostash" และการmerge.autostashตั้งค่าใหม่

ดูกระทำ d9f15d3 , กระทำ f8a1785 , กระทำ a03b555 , กระทำ 804fe31 , กระทำ 12b6e13 , กระทำ 0dd562e , กระทำ 0816f1d , กระทำ 9bb3dea , กระทำ 4d4bc15 , กระทำ b309a97 , กระทำ f213f06 , กระทำ 86ed00a , กระทำ facca7f , กระทำ be1bb60 , กระทำ efcf6cf , กระทำ c20de8b , กระทำ bfa50c2 , กระทำ 3442c3d , กระทำ 5b2f6d9 (7 เมษายน 2020) กระทำ 65c425a(4 เมษายน 2020) และกระทำ fd6852c , กระทำ 805d9ea (21 มีนาคม 2020) โดยDenton หลิว (Denton-L )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ bf10200 , 29 เมษายน 2020)

pull: pass --autostash เพื่อรวม

ลงนามโดย: Denton Liu

ก่อนหน้านี้--autostashทำงานกับgit pull --rebase.

อย่างไรก็ตามในแพตช์ที่แล้วการผสานได้เรียนรู้--autostashเช่นกันดังนั้นจึงไม่มีเหตุผลที่เราควรมีข้อ จำกัด นี้อีกต่อไป
สอน pull to pass --autostashเพื่อผสานเช่นเดียวกับ rebase

และ:

rebase: ใช้apply_autostash()จาก sequencer.c

ลงนามโดย: Denton Liu

apply_autostash()ฟังก์ชั่นในbuiltin/rebase.cก็เพียงพอที่คล้ายกับapply_autostash()ฟังก์ชั่นในการsequencer.cที่พวกเขาสามารถใช้แทนกันเกือบยกเว้นสำหรับประเภทของหาเรื่องพวกเขายอมรับ สร้างsequencer.cเวอร์ชันภายนอกและใช้ในฐานข้อมูลใหม่

เวอร์ชัน rebase ถูกนำมาใช้ใน6defce2b02 ("builtin rebase: support --autostashoption", 2018-09-04, Git v2.20.0-rc0 - รวมอยู่ในbatch # 8 ) โดยเป็นส่วนหนึ่งของการแปลงเชลล์เป็น C
เลือกที่จะทำซ้ำฟังก์ชันนี้เนื่องจากในขณะนั้นมีโครงการที่อยู่ระหว่างดำเนินการอีกโครงการหนึ่งที่แปลง rebase แบบโต้ตอบจากเชลล์เป็น C เช่นกันและพวกเขาไม่ต้องการปะทะกับพวกเขาโดยการปรับโครงสร้างsequencer.cเวอร์ชันของapply_autostash().
เนื่องจากทั้งสองพยายามทำมานานเราจึงสามารถรวมเข้าด้วยกันได้อย่างอิสระในตอนนี้


ณ วันที่ 2.4.2 ยังไม่มีการนำไปใช้ บางทีบางวัน rebase.autoStashใช้เฉพาะเมื่อใช้ rebase pull.rebaseใช้ได้เฉพาะเมื่อใช้การดึงเท่านั้น
Randal Schwartz

"นั่นก็เพียงพอแล้วสำหรับการดึงคอมไพล์ง่ายๆให้ทำงานได้แม้อยู่ในต้นไม้ที่สกปรก" ดังที่ Randal แสดงความคิดเห็นนี่ยังไม่เป็นความจริง ต้นแบบปัจจุบันpull.cdie_on_unclean_work_treeยังคงเลือกที่จะ
ประธาน

1
@ ประทานเห็นด้วย การใช้งานเพิ่งเริ่มต้นเมื่อเช้านี้และควรจะเป็น git 2.6 ฉันได้แก้ไขคำตอบเพื่อให้ชัดเจนแล้ว
VonC

ฉันได้รับการยืนยันว่า autostash 2.5.5จะทำงานร่วมกับคอมไพล์
Joshua Hoblitt

1
ดังนั้นทุกคนกำลังเขียนเกี่ยวกับการตั้งค่าอัตโนมัติเมื่อคุณทำrebase(หรือpull --rebase) แต่ไม่มีใครใช้เวลาเกี่ยวกับการตั้งค่าอัตโนมัติเมื่อคุณทำตามปกติpullกับการผสาน จึงไม่มีสวิตช์อัตโนมัติสำหรับสิ่งนั้น? หรือฉันขาดอะไรไป? ฉันชอบทำมากกว่าgit pull --rebaseแต่ OP ถามเกี่ยวกับ "มาตรฐาน"git pull
Mariusz Pawelski

41

เพื่อประหยัดเวลาไม่กี่วินาทีสำหรับนักสำรวจที่กำลังจะมาถึงนี่คือบทสรุป (ขอบคุณ @VonC):

git pull --rebase --autostash

6
ประเด็นก็คือ: หลังจากที่git config pull.rebase trueและ สิ่งที่คุณจะต้องเคยเป็นgit config rebase.autoStash true git pullเพียงgit pull. ไม่จำเป็นต้องมีตัวเลือกอื่น ๆ
VonC

3
ปรากฏว่าคุณต้องมี Git 2.9 เป็นอย่างน้อยสำหรับ--autostashตัวเลือก ใช้-c rebase.autoStash=trueงานได้ใน Git 2.6 เป็นต้นไป
ntc2

15

ตามที่ความคิดเห็นด้านบนระบุไว้การตั้งค่าการกำหนดค่าสองค่าใช้ไม่ได้ในขณะนี้git pullเนื่องจากการกำหนดค่าอัตโนมัติใช้กับ rebases จริงเท่านั้น คำสั่ง git เหล่านี้ทำสิ่งที่คุณต้องการ:

git fetch
git rebase --autostash FETCH_HEAD

หรือตั้งเป็นนามแฝง:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

จากนั้นทำ:

git pullr

แน่นอนนามแฝงนี้สามารถเปลี่ยนชื่อได้ตามต้องการ


7

ด้วย Git 2.6+ คุณสามารถใช้สิ่งต่อไปนี้:

alias gup='git -c rebase.autoStash=true pull --rebase'

สิ่งนี้--rebaseทำให้ใช้ git-pull rebaseแทนmergeดังนั้นการตั้งค่า / ตัวเลือกเช่น--ff-onlyนี้จะไม่มีผล

ฉันใช้นามแฝงเพื่อดึง--ff-onlyโดยค่าเริ่มต้น ( git pull --ff-only) จากนั้นสามารถใช้gup(จากด้านบน) ในกรณีที่ไม่สามารถทำการผสานไปข้างหน้าอย่างรวดเร็วหรือมีการเปลี่ยนแปลงที่ซ่อนอยู่


เป็นความแตกต่างที่สำคัญระหว่างอะไรgit pull --ff-onlyและgit pull pull --rebase --autostash
Alper

0

ดังที่คุณได้กล่าวไปแล้วนี่คือวิธีการทำ คุณสามารถใช้ในนามแฝงเพื่อบันทึกการพิมพ์และใช้ทางลัดหรือใช้ในบรรทัดเดียวก็ได้ (สามารถใช้เป็นนามแฝงได้เช่นกัน)

git stash && git pull --rebase && git stash pop

มันจะทำสิ่งเดียวกับที่คุณทำ แต่เป็นบรรทัดเดียว (&&) และคุณตั้งเป็นนามแฝงหรือไม่มันจะยิ่งสั้นลง

บรรทัดต่อไปนี้จะแสดงการเปลี่ยนแปลงขาเข้า / ขาออกก่อนที่คุณจะดึง / ดัน

git log ^master origin/master
git log master ^origin/master

8
วิธีนี้ไม่ปลอดภัย: หากไม่มีสิ่งใดให้ซ่อนคำสั่งแรกจะไม่ทำอะไรเลยจากนั้นstash popจะปลดสิ่งที่สุ่มออกมาก่อน
John Zwinck

เพียงเพื่อจะเพิ่มความชัดเจนแม้ว่าgit stashจะไม่ได้อะไรซ่อนมันยังคงเป็น "ผลตอบแทน" ERRORCODE ไม่มีดังนั้น && จะยังคงดำเนินการต่อด้วยgit pullและgit stash popและป๊อปซ่อนก่อนหน้านี้ ดังนั้นอย่าใช้สิ่งนี้ดีกว่าเว้นแต่คุณจะมั่นใจมากว่ามันจะซ่อนบางสิ่งไว้!
MoonLite
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.