สรุป
ตามค่าเริ่มต้นgit pull
สร้างการรวมการกระทำที่เพิ่มเสียงรบกวนและความซับซ้อนให้กับประวัติรหัส นอกจากนี้pull
ทำให้ง่ายต่อการไม่คิดว่าการเปลี่ยนแปลงของคุณอาจได้รับผลกระทบจากการเปลี่ยนแปลงที่เข้ามา
git pull
คำสั่งมีความปลอดภัยตราบใดที่มันดำเนินการผสานข้างหน้าอย่างรวดเร็ว หากgit pull
มีการกำหนดค่าให้ทำการผสานการกรอไปข้างหน้าเท่านั้นและเมื่อไม่สามารถผสานการกรอไปข้างหน้าได้ Git จะออกจากข้อผิดพลาด วิธีนี้จะให้โอกาสคุณในการศึกษาความมุ่งมั่นที่เข้ามาคิดเกี่ยวกับวิธีที่พวกเขาจะส่งผลกระทบต่อการกระทำในท้องถิ่นของคุณและตัดสินใจแนวทางการดำเนินการที่ดีที่สุด
ด้วย Git 2.0 และใหม่กว่าคุณสามารถเรียกใช้:
git config --global pull.ff only
เพื่อเปลี่ยนพฤติกรรมเริ่มต้นเป็นเพียงการส่งต่ออย่างรวดเร็ว ด้วยเวอร์ชัน Git ระหว่าง 1.6.6 ถึง 1.9.x คุณจะต้องติดนิสัยในการพิมพ์:
git pull --ff-only
อย่างไรก็ตามด้วย Git ทุกรุ่นฉันแนะนำให้ตั้งgit up
ชื่อแทนดังนี้:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
และใช้แทนgit up
git pull
ฉันชอบชื่อแทนนี้มากกว่าgit pull --ff-only
เพราะ:
- ใช้ได้กับ Git ทุกรุ่น (ที่ไม่ใช่โบราณ)
- มันดึงสาขาต้นน้ำทั้งหมด (ไม่ใช่เฉพาะสาขาที่คุณกำลังทำงานอยู่) และ
- มันล้าง
origin/*
สาขาเก่าที่ไม่มีต้นน้ำอีกต่อไป
มีปัญหากับ git pull
git pull
ไม่เลวถ้าใช้อย่างถูกต้อง การเปลี่ยนแปลงล่าสุดของ Git ทำให้การใช้งานgit pull
อย่างถูกต้องง่ายขึ้นแต่น่าเสียดายที่พฤติกรรมเริ่มต้นของธรรมดาgit pull
มีปัญหาหลายประการ:
- มันแนะนำความไม่เชิงเส้นที่ไม่จำเป็นในประวัติศาสตร์
- มันทำให้ง่ายต่อการรื้อฟื้นคอมมิตโดยไม่ตั้งใจซึ่งถูกรีบูทโดยเจตนาโดยไม่ตั้งใจ
- มันปรับเปลี่ยนไดเรกทอรีการทำงานของคุณในรูปแบบที่ไม่แน่นอน
- การหยุดสิ่งที่คุณกำลังทำอยู่ชั่วคราวเพื่อทบทวนงานของคนอื่นนั้นน่ารำคาญ
git pull
- มันทำให้ยากที่จะ rebase อย่างถูกต้องไปยังสาขาระยะไกล
- มันไม่ได้ล้างสาขาที่ถูกลบใน repo ระยะไกล
ปัญหาเหล่านี้อธิบายโดยละเอียดยิ่งขึ้นด้านล่าง
ประวัติความเป็นมาไม่เชิงเส้น
โดยค่าเริ่มต้นgit pull
คำสั่งจะเทียบเท่ากับการทำงานตามgit fetch
git merge @{u}
หากมีการกระทำ unpushed ในพื้นที่เก็บข้อมูลในท้องถิ่นเป็นส่วนหนึ่งของการผสานgit pull
สร้างผสานกระทำ
ไม่มีอะไรเลวร้ายเกี่ยวกับการรวมการกระทำ แต่พวกเขาอาจเป็นอันตรายและควรได้รับการปฏิบัติด้วยความเคารพ:
- การรวมคอมมิชชันนั้นยากที่จะตรวจสอบโดยเนื้อแท้ เพื่อให้เข้าใจว่าการผสานกำลังทำอะไรคุณต้องเข้าใจความแตกต่างของพ่อแม่ทุกคน ความแตกต่างทั่วไปไม่ได้ถ่ายทอดข้อมูลหลายมิตินี้อย่างดี ในทางตรงกันข้ามชุดของการกระทำปกตินั้นง่ายต่อการตรวจสอบ
- การแก้ไขความขัดแย้งผสานเป็นเรื่องยุ่งยากและความผิดพลาดมักจะไม่ถูกตรวจจับเป็นเวลานานเนื่องจากการคอมมิทผสานนั้นยากต่อการตรวจสอบ
- การรวมกันสามารถแทนที่ผลของการกระทำปกติได้อย่างเงียบ ๆ รหัสดังกล่าวไม่ได้เป็นผลรวมของความมุ่งมั่นที่เพิ่มขึ้นอีกต่อไปซึ่งนำไปสู่ความเข้าใจผิดเกี่ยวกับสิ่งที่เปลี่ยนแปลงไปจริง ๆ
- การรวมกระทำอาจขัดขวางแผนการรวมอย่างต่อเนื่องบางอย่าง (เช่นสร้างอัตโนมัติเฉพาะเส้นทางพาเรนต์แรกภายใต้อนุสัญญาที่สันนิษฐานว่าผู้ปกครองคนที่สองชี้ไปที่งานที่ยังไม่เสร็จสมบูรณ์)
แน่นอนว่ามีเวลาและสถานที่สำหรับการผสาน แต่การเข้าใจเมื่อการรวมควรและไม่ควรใช้สามารถปรับปรุงประโยชน์ของที่เก็บของคุณ
โปรดทราบว่าจุดประสงค์ของ Git คือเพื่อให้ง่ายต่อการแบ่งปันและใช้งานการวิวัฒนาการของ codebase ไม่ใช่เพื่อบันทึกประวัติอย่างแม่นยำในขณะที่มันคลี่ออกมา (ถ้าคุณไม่เห็นด้วยให้พิจารณาrebase
คำสั่งและเหตุผลที่สร้างขึ้น) การรวมที่สร้างโดยgit pull
ไม่สื่อความหมายที่เป็นประโยชน์ต่อผู้อื่น - พวกเขาเพียงแค่บอกว่ามีคนอื่นเกิดขึ้นที่จะผลักดันไปยังที่เก็บก่อนที่จะทำการเปลี่ยนแปลงของคุณ เหตุใดการผสานเหล่านี้จึงเกิดขึ้นถ้าพวกเขาไม่ได้มีความหมายต่อผู้อื่นและอาจเป็นอันตรายได้
เป็นไปได้ที่จะกำหนดค่าgit pull
ให้รีบูทแทนที่จะรวม แต่ยังมีปัญหา (อธิบายในภายหลัง) แต่git pull
ควรจะกำหนดค่าที่จะทำเพียงผสานข้างหน้าอย่างรวดเร็ว
การคืนสู่พันธะที่ถูกปฏิเสธ
สมมติว่ามีใครบางคน rebases สาขาและแรงผลักดันมัน โดยทั่วไปไม่ควรเกิดขึ้น แต่บางครั้งก็มีความจำเป็น (เช่นเพื่อลบไฟล์บันทึก 50GiB ที่เข้ามาแล้วผลักโดยไม่ตั้งใจ) การผสานที่ทำโดยgit pull
จะรวมเวอร์ชันใหม่ของสาขาอัปสตรีมลงในเวอร์ชันเก่าที่ยังคงมีอยู่ในที่เก็บในเครื่องของคุณ หากคุณดันผลลัพธ์ออกมา pitch forks and torches จะเริ่มเข้ามา
บางคนอาจแย้งว่าปัญหาที่แท้จริงคือการปรับปรุงกำลัง ใช่โดยทั่วไปจะแนะนำให้หลีกเลี่ยงการกดทับเมื่อทำได้ แต่บางครั้งก็หลีกเลี่ยงไม่ได้ นักพัฒนาจะต้องเตรียมที่จะจัดการกับการอัพเดทแรงเพราะบางครั้งพวกเขาจะเกิดขึ้น git pull
วิธีนี้ไม่สุ่มสี่สุ่มห้าผสานในกระทำเก่าผ่านสามัญ
การปรับเปลี่ยนไดเรกทอรีการทำงานที่น่าประหลาดใจ
ไม่มีวิธีใดที่จะคาดเดาได้ว่าไดเรกทอรีหรือดัชนีการทำงานจะมีหน้าตาเป็นอย่างไรจนกระทั่งgit pull
เสร็จสิ้น อาจมีข้อขัดแย้งที่ผสานที่คุณต้องแก้ไขก่อนที่คุณจะสามารถทำสิ่งอื่นได้มันอาจแนะนำไฟล์บันทึก 50GiB ในไดเรกทอรีทำงานของคุณเพราะมีคนผลักมันโดยไม่ตั้งใจอาจเปลี่ยนชื่อไดเรกทอรีที่คุณกำลังทำงานอยู่เป็นต้น
git remote update -p
(หรือgit fetch --all -p
) อนุญาตให้คุณดูความมุ่งมั่นของผู้อื่นก่อนที่คุณจะตัดสินใจที่จะรวมหรือปฏิเสธการอนุญาตให้คุณจัดทำแผนก่อนดำเนินการ
ความยากลำบากในการตรวจสอบภาระผูกพันของผู้อื่น
สมมติว่าคุณกำลังทำการเปลี่ยนแปลงบางอย่างและมีคนอื่นต้องการให้คุณตรวจทานบางสิ่งที่พวกเขาเพิ่งผลัก git pull
การทำงานของการผสาน (หรือการรีบูต) แก้ไขไดเรกทอรีการทำงานและดัชนีซึ่งหมายความว่าไดเรกทอรีการทำงานและดัชนีของคุณต้องสะอาด
คุณสามารถใช้git stash
แล้วgit pull
แต่คุณจะทำอย่างไรเมื่อคุณตรวจสอบเสร็จแล้ว? ในการกลับไปยังที่ที่คุณอยู่คุณต้องเลิกทำการผสานที่สร้างโดยgit pull
ใช้ที่เก็บของ
git remote update -p
(หรือgit fetch --all -p
) ไม่ได้ปรับเปลี่ยนไดเรกทอรีการทำงานหรือดัชนีดังนั้นจึงปลอดภัยที่จะเรียกใช้เมื่อใดก็ได้ - แม้ว่าคุณจะมีการจัดฉากและ / หรือการเปลี่ยนแปลงที่ไม่มีการจัดฉาก คุณสามารถหยุดสิ่งที่คุณกำลังทำและทบทวนการกระทำของคนอื่นโดยไม่ต้องกังวลกับการหยุดชะงักหรือทำสิ่งที่คุณทำอยู่ git pull
ไม่ได้ให้ความยืดหยุ่นแก่คุณ
การรีบูทเข้าสู่สาขาระยะไกล
รูปแบบการใช้ Git ทั่วไปคือการทำgit pull
เพื่อนำการเปลี่ยนแปลงล่าสุดตามด้วยgit rebase @{u}
เพื่อกำจัดการคอมมิชชันที่git pull
แนะนำ ก็พอที่ทั่วไปที่ Git มีตัวเลือกการกำหนดค่าบางอย่างเพื่อลดขั้นตอนเหล่านี้ไปยังขั้นตอนเดียวโดยบอกgit pull
จะดำเนินการ rebase แทนการผสาน (ดูbranch.<branch>.rebase
, branch.autosetuprebase
และpull.rebase
ตัวเลือก)
น่าเสียดายที่ถ้าคุณมีการรวมที่ไม่ได้กดการกระทำที่คุณต้องการรักษาไว้ (เช่นการรวมการรวมสาขาของฟีเจอร์ที่ถูกผลักเข้าไปmaster
) ไม่ว่าจะเป็นการ rebase-pull ( git pull
พร้อมการbranch.<branch>.rebase
ตั้งค่าเป็นtrue
) หรือการผสานดึง ( git pull
พฤติกรรมเริ่มต้น) ตามด้วย rebase จะทำงานได้ นี่เป็นเพราะgit rebase
กำจัดการรวม (ทำให้เป็นเส้นตรง DAG) โดยไม่มี--preserve-merges
ตัวเลือก การดำเนินการดึง rebase ไม่สามารถกำหนดค่าเพื่อรักษาการผสานและการผสานดึงตามด้วยgit rebase -p @{u}
จะไม่กำจัดการผสานที่เกิดจากการผสานดึง ปรับปรุง: Git v1.8.5 เพิ่มและgit pull --rebase=preserve
git config pull.rebase preserve
สาเหตุเหล่านี้git pull
จะต้องทำgit rebase --preserve-merges
หลังจากดึงความมุ่งมั่นต้นน้ำ (ขอบคุณfunkasterสำหรับเฮดอัพ!)
ล้างสาขาที่ถูกลบ
git pull
ไม่ตัดสาขาการติดตามระยะไกลที่สอดคล้องกับสาขาที่ถูกลบออกจากที่เก็บระยะไกล ตัวอย่างเช่นถ้ามีคนลบสาขาfoo
จาก repo origin/foo
ระยะไกลคุณจะยังคงเห็น
สิ่งนี้นำไปสู่การที่ผู้ใช้ทำการคืนชีพสาขาที่ถูกฆ่าโดยไม่ตั้งใจเพราะพวกเขาคิดว่าพวกเขายังคงทำงานอยู่
ทางเลือกที่ดีกว่า: ใช้git up
แทนgit pull
แทนที่จะgit pull
แนะนำให้สร้างและใช้git up
นามแฝงต่อไปนี้:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
นามแฝงนี้ดาวน์โหลดการกระทำล่าสุดทั้งหมดจากสาขาต้นน้ำทั้งหมด (การตัดกิ่งที่ตายแล้ว) และพยายามที่จะส่งต่อสาขาท้องถิ่นอย่างรวดเร็วไปยังการกระทำล่าสุดในสาขาอัปสตรีม หากประสบความสำเร็จแสดงว่าไม่มีการกระทำในท้องถิ่นดังนั้นจึงไม่มีความเสี่ยงในการรวมความขัดแย้ง กรอไปข้างหน้าจะล้มเหลวหากมีการกระทำในท้องถิ่น (ไม่ได้รับการชำระ) ให้โอกาสคุณในการตรวจสอบข้อผูกพันต้นน้ำก่อนที่จะดำเนินการ
สิ่งนี้ยังคงปรับเปลี่ยนไดเร็กตอรี่การทำงานของคุณในรูปแบบที่ไม่แน่นอน, แต่ถ้าคุณไม่มีการเปลี่ยนแปลงในเครื่อง ไม่เหมือนgit pull
ว่าgit up
จะไม่ส่งคุณไปยังพรอมต์ที่คาดหวังให้คุณแก้ไขข้อขัดแย้งในการผสาน
ตัวเลือกอื่น: git pull --ff-only --all -p
ต่อไปนี้เป็นทางเลือกสำหรับgit up
นามแฝงข้างต้น:
git config --global alias.up 'pull --ff-only --all -p'
เวอร์ชันนี้git up
มีพฤติกรรมเหมือนกับgit up
นามแฝงก่อนหน้ายกเว้น:
- ข้อความแสดงข้อผิดพลาดเป็นความลับอีกเล็กน้อยถ้าสาขาในประเทศของคุณไม่ได้กำหนดค่าด้วยสาขาต้นน้ำ
- มันขึ้นอยู่กับคุณสมบัติที่ไม่มีเอกสาร (
-p
อาร์กิวเมนต์ซึ่งถูกส่งผ่านไปfetch
) ที่อาจเปลี่ยนแปลงใน Git เวอร์ชันในอนาคต
หากคุณใช้ Git 2.0 หรือใหม่กว่า
ด้วย Git 2.0 และใหม่กว่าคุณสามารถกำหนดค่าgit pull
เพื่อทำการผสานการกรอไปข้างหน้าอย่างรวดเร็วโดยค่าเริ่มต้น:
git config --global pull.ff only
สาเหตุนี้git pull
จะทำหน้าที่เหมือนgit pull --ff-only
แต่ก็ยังไม่สามารถดึงข้อมูลกระทำต้นน้ำหรือทำความสะอาดออกเก่าสาขาดังนั้นฉันยังคงต้องการorigin/*
git up