ความแตกต่างระหว่าง git pull และ git pull --rebase


311

ฉันเริ่มใช้คอมไพล์ในบางครั้งและไม่เข้าใจความซับซ้อนอย่างสมบูรณ์ คำถามพื้นฐานของฉันที่นี่คือการหาความแตกต่างระหว่าง a git pullและgit pull --rebaseเนื่องจากการเพิ่ม--rebaseตัวเลือกดูเหมือนจะไม่ทำสิ่งที่แตกต่างกันมาก: เพียงแค่ดึง

โปรดช่วยฉันด้วยการทำความเข้าใจความแตกต่าง



3
สำเนาซ้ำที่เป็นไปได้ของgit pull VS git เรียก git rebase
TJ

ลิงค์ที่มีประโยชน์: atlassian.com/git/tutorials/rewriting-history/git-rebase
Taras Melnyk

คำตอบ:


326

git pull= git fetch+ git mergeเทียบกับการติดตามสาขาต้นน้ำ

git pull --rebase= git fetch+ git rebaseเทียบกับการติดตามสาขาต้นน้ำ

หากคุณต้องการที่จะทราบวิธีgit mergeและgit rebaseแตกต่างกันอ่าน


12
มันเป็นมูลค่า noting บอกว่าgit pull --rebaseเป็นเช่นเดียวกับgit fetchและgit rebaseเป็นพื้นมันเป็นอย่างไร แต่ก็ไม่ได้ว่าเทียบเท่าความหมาย มีความแตกต่างบางอย่างซึ่งอธิบายไว้ที่นี่ gitolite.com/git-pull--rebase
w0rp

8
มันเป็นสิ่งที่ฉันจะเรียกว่า "โกหกง่าย" เพื่อขอยืมวลีจาก Scott Meyers มันเป็นวิธีที่ดีในการอธิบายโดยไม่คำนึงถึง
w0rp

สั้นมาก ฉันไม่เข้าใจความแตกต่าง สิ่งที่สำคัญเกี่ยวกับfetch?
Green

240

บางครั้งเรามีอัพสตรีมที่รีบาวด์ / ย้อนกลับสาขาที่เราพึ่งพา นี่อาจเป็นปัญหาใหญ่ - ก่อให้เกิดความขัดแย้งกับเราหากเราล่อง

ความมหัศจรรย์คือ git pull --rebase

การดึง git ปกติคือพูดอย่างหลวม ๆ บางอย่างเช่นนี้ (เราจะใช้ต้นกำเนิดที่เรียกว่าระยะไกลและสาขาที่เรียกว่า foo ในตัวอย่างเหล่านี้ทั้งหมด):

# assume current checked out branch is "foo"
git fetch origin
git merge origin/foo

เมื่อเห็นอย่างรวดเร็วคุณอาจคิดว่า git pull --rebase ทำสิ่งนี้:

git fetch origin
git rebase origin/foo

แต่นั่นจะไม่ช่วยถ้าการรีสตรีม rebase เกี่ยวข้องกับ "การบีบ" (หมายความว่าแพทช์ - รหัสของการกระทำนั้นเปลี่ยนไปไม่ใช่แค่การสั่งซื้อ)

ซึ่งหมายถึง git pull --rebase ต้องทำมากกว่านั้นอีกเล็กน้อย นี่คือคำอธิบายของสิ่งที่มันทำและอย่างไร

สมมติว่าจุดเริ่มต้นของคุณคือ:

a---b---c---d---e  (origin/foo) (also your local "foo")

เวลาผ่านไปและคุณได้ทำข้อตกลงไว้กับ "foo" ของคุณเอง:

a---b---c---d---e---p---q---r (foo)

ในขณะเดียวกันด้วยความโกรธแค้นต่อต้านสังคมผู้ดูแลต้นน้ำไม่เพียง แต่ลด "foo" ของเขาเขายังใช้สควอชหรือสองตัว ห่วงโซ่การกระทำของเขาตอนนี้มีลักษณะเช่นนี้:

a---b+c---d+e---f  (origin/foo)

การดึง git ณ จุดนี้จะส่งผลให้เกิดความสับสน แม้แต่การเรียก git; คอมไพล์ rebase ต้นกำเนิด / foo จะไม่ตัดเพราะคอมมิต "b" และ "c" ด้านหนึ่งและคอมมิชชัน "b + c" ในอีกด้านหนึ่งจะขัดแย้งกัน (และคล้ายกับ d, e และ d + e)

สิ่งที่git pull --rebaseไม่ในกรณีนี้คือ

git fetch origin
git rebase --onto origin/foo e foo

สิ่งนี้จะช่วยให้คุณ:

 a---b+c---d+e---f---p'---q'---r' (foo)

คุณยังอาจได้รับความขัดแย้ง แต่จะเป็นความขัดแย้งที่แท้จริง (ระหว่าง p / q / r และ a / b + c / d + e / f) และไม่ใช่ความขัดแย้งที่เกิดจาก b / c ที่ขัดแย้งกับ b + c เป็นต้น

คำตอบที่นำมาจาก (และแก้ไขเล็กน้อย):
http://gitolite.com/git-pull--rebase


9
นี่คือคำตอบที่ดีที่สุด คุณอาจต้องการเปลี่ยนผลลัพธ์สุดท้ายเป็นa---b+c---d+e---f---p'---q'---r' (foo)ตั้งแต่แฮชการเปลี่ยนแปลง rebase
Bastien

22
คำตอบนี้ถูกคัดลอกและวางทุกคำต่อคำจากgitolite.com/git-pull--rebaseและควรมีการระบุแหล่งที่มาต่อใบอนุญาตในหน้านั้น
สัญลักษณ์ตัวแทน

นี่คือคำอธิบายที่ดี แต่ฉันมีสถานการณ์ที่ฉันได้กระทำAและฉันส่ง PR ไปยัง repo ต้นน้ำที่ได้รับการยอมรับ จากนั้นเมื่อฉันทำgit pull --rebaseกับ repo ต้นน้ำฉันไม่ได้รับความA'มุ่งมั่นใหม่บน repo ดึงต้นน้ำ ในความเป็นจริงไม่มีA'อยู่เลย เป็นเพราะAมีการรวมเข้ากับระบบหรือไม่ หรือเป็นเพราะไม่มีความแตกต่างระหว่างอัปสตรีมและรีบาวด์ของฉันไปยังเวอร์ชัน?
CMCDragonkai

ฉันกำลังจะผ่าน Git git pull --rebaseกวดวิชาและได้รับการตอบสนองนี้ใช้เพื่อเข้าใจ แต่สิ่งหนึ่งที่ทำให้ฉันสับสนในสถานการณ์สมมุตินี้คือผู้ดูแลระบบต้นน้ำเปลี่ยนประวัติโครงการที่ถูกดึงเข้าไปในที่เก็บของนักพัฒนาท้องถิ่นแล้ว นี่ไม่ใช่การปฏิบัติที่ไม่ดีโดยทั่วไปใช่ไหม หากเขาต้องการที่จะสควอชกระทำ / เขียนประวัติศาสตร์มันควรจะทำก่อนที่จะรวมไว้ในที่เก็บส่วนกลางเพื่อหลีกเลี่ยงความขัดแย้งประเภทนี้
bmcentee148

44

สมมติว่าคุณมีข้อผูกพันสองอย่างในสาขาท้องถิ่น:

      D---E master
     /
A---B---C---F origin/master

หลังจาก "git pull" จะเป็น:

      D--------E  
     /          \
A---B---C---F----G   master, origin/master

หลังจาก "git pull --rebase" จะไม่มีการรวมจุด G โปรดทราบว่า D และ E มีความมุ่งมั่นที่แตกต่างกัน:

A---B---C---F---D'---E'   master, origin/master

1
ไม่ใช่ A --- B --- C --- D '--- E' - F?
prgmrDev

5
@prgmrDev ทำไมต้องแทรก D และ E ก่อนหน้า F
Jon

1
มันไม่ได้เป็นอย่างgit rebaseนั้นเหรอ? git pull --rebaseแต่เรากำลังพูดถึง และพวกมันต่างกัน
Green

10

ในกรณีที่ง่ายที่สุดที่ไม่มีการชน

  • ด้วย rebase: rebases ท้องถิ่นของคุณยอมรับ ontop ของ HEAD ระยะไกลและไม่ได้สร้างการผสาน / ผสานกระทำ
  • ไม่มี / ปกติ: ผสานและสร้างการคอมมิชชัน

ดูสิ่งนี้ด้วย:

man git-pull

แม่นยำยิ่งขึ้น git pull รัน git fetch ด้วยพารามิเตอร์ที่กำหนดและเรียก git merge เพื่อผสานส่วนหัวสาขาที่ดึงมาไว้ในสาขาปัจจุบัน ด้วย --rebase มันจะทำการรีบูต git แทน git merge

ดูเพิ่มเติม:
เมื่อใดที่ฉันควรใช้ git pull --rebase
http://git-scm.com/book/en/Git-Branching-Rebasing


3
และในกรณีที่มีการชนกัน?
Rndm

1
คุณจะได้รับการขอให้แก้ไขปัญหาด้วยตนเองและจากนั้น - ยังคงมีการ rebase: git sdd modified-file; git rebase --continueหรือการผสาน: git add modified-file; git commit;ที่modified-fileไฟล์ในท้องถิ่นของคุณคุณปรับเปลี่ยนตนเอง / mergetool
drahnr

มีอะไรพิเศษเกี่ยวกับfetch? เหตุใดพวกเขาจึงสร้างrebaseกระแสสองแห่ง 1) git rebaseและ 2) git pull --rebase?
Green

7

สำหรับสิ่งนี้เป็นสิ่งสำคัญที่จะเข้าใจความแตกต่างระหว่างการรวมและการลด

การคืนเงินเป็นวิธีการเปลี่ยนแปลงที่ควรส่งผ่านจากด้านบนของลำดับชั้นลงและการรวมเป็นวิธีที่พวกเขาไหลกลับขึ้นไป

สำหรับรายละเอียดอ้างอิง - http://www.derekgourlay.com/archives/428


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