เหตุใด Git จึงบอกว่าสาขาหลักของฉัน "ทันสมัยอยู่แล้ว" แม้ว่าจะไม่เป็นเช่นนั้นก็ตาม


118

ปัญหาพื้นฐาน

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

git pull upstream master

เพื่อดึงข้อมูลและรวมจากต้นน้ำ (ดังนั้นในทางทฤษฎีแล้วโค้ดที่ถูกลบควรกลับมา)

Git บอกฉันทุกอย่างเป็นปัจจุบัน

ทุกอย่างไม่ทันสมัยแน่นอน - โค้ดที่ถูกลบทั้งหมดจะยังคงถูกลบ

ข้อมูลที่เกี่ยวข้องอื่น ๆ

ฉันมีเพียงสาขาเดียวที่เรียกว่า "master"

ฉันเพิ่งตั้งค่า "หลัก" เพื่อติดตามอัปสตรีมดังนี้:

ตั้งค่าสาขาหลักเพื่อติดตามสาขาหลักระยะไกลจากต้นน้ำ

คำสั่งgit branch -vvให้ผล:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

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

ปรับปรุง

ฉันคิดว่ามันชัดเจน แต่อย่างไรก็ตามนี่คือเป้าหมายของฉัน:

รับรหัสล่าสุดในระบบของฉัน

ขอโทษทีนะ แต่ทำไมงานง่ายๆแบบนั้นมันต้องยากขนาดนี้


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

คำตอบ:


211

ฉันคิดว่าปัญหาพื้นฐานของคุณที่นี่คือคุณกำลังตีความผิดและ / หรือเข้าใจผิดว่า git ทำอะไรและทำไมถึงทำเช่นนั้น

เมื่อคุณโคลนที่เก็บอื่น git จะสร้างสำเนาของสิ่งที่ "อยู่ตรงนั้น" นอกจากนี้ยังใช้ป้ายกำกับสาขา "ของพวกเขา" เช่นmasterและทำสำเนาของป้ายกำกับนั้นซึ่งมี "ชื่อเต็ม" ในแผนผังคอมไพล์ของคุณ (ปกติ) remotes/origin/master(แต่ในกรณีของคุณremotes/upstream/master) ส่วนใหญ่เวลาที่คุณได้รับการละเว้นส่วนเกินไปดังนั้นคุณจึงสามารถอ้างถึงว่าเป็นสำเนาต้นฉบับremotes/upstream/master

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

git pullคำสั่งส่วนใหญ่จะเป็นเพียงแค่จดชวเลขตามมาด้วยgit fetch git mergeนี่เป็นสิ่งสำคัญเพราะหมายความว่าคุณต้องเข้าใจว่าการดำเนินการทั้งสองนั้นทำอะไรได้จริง

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

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

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

สิ่งที่คุณต้องการคือดูหรืออาจจะ "รีเซ็ต" เป็น "เวอร์ชัน" ของรหัส

หากคุณเพียงต้องการดูคุณสามารถตรวจสอบเวอร์ชันนั้นได้:

git checkout upstream/master

remotes/upstream/masterที่บอกคอมไพล์ที่คุณต้องการที่จะย้ายไดเรกทอรีปัจจุบันไปยังสาขาที่มีชื่อเต็มเป็นจริง คุณจะเห็นรหัสเป็นครั้งสุดท้ายที่คุณเรียกใช้git fetchและได้รับรหัสล่าสุด

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

git checkout master

จากนั้นgit resetคำสั่งจะช่วยให้คุณ "ย้ายป้ายกำกับ" ได้เหมือนเดิม ปัญหาเดียวที่เหลืออยู่ (สมมติว่าคุณพร้อมที่จะละทิ้งทุกสิ่งที่คุณไม่ได้ทำ) คือการค้นหาว่าป้ายกำกับควรชี้ไปที่ใด

git logจะช่วยให้คุณหาชื่อเหล่านั้นเป็นตัวเลขสิ่งเช่น7cfcb29-which ถาวร (ไม่เคยเปลี่ยน) ชื่อและมีจำนวนที่ไร้สาระของวิธีการอื่น ๆ ที่จะตั้งชื่อพวกเขา upstream/masterแต่ในกรณีนี้คุณต้องการเพียงแค่ชื่อ

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

git reset --hard upstream/master

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

มันไม่ได้เป็นซุปเปอร์เรื่องธรรมดาที่จะจริงๆต้องการgit reset --hardและเช็ดออกพวงของการทำงาน วิธีที่ปลอดภัยกว่า (ทำให้การกู้คืนงานนั้นง่ายขึ้นมากหากคุณตัดสินใจว่าบางอย่างคุ้มค่าหลังจากนั้น) คือการเปลี่ยนชื่อสาขาที่มีอยู่:

git branch -m master bunchofhacks

จากนั้นสร้างสาขาท้องถิ่นใหม่ชื่อmaster"แทร็ก" (ฉันไม่ชอบคำนี้มากนักเพราะฉันคิดว่ามันทำให้คนสับสน แต่นั่นคือคำ git :-)) ต้นกำเนิด (หรือต้นน้ำ) ต้นแบบ:

git branch -t master upstream/master

ซึ่งคุณสามารถดำเนินการได้ด้วยตัวเอง:

git checkout master

คำสั่งสามคำสุดท้ายทำอะไร (มีทางลัดที่จะทำให้เป็นเพียงสองคำสั่ง) คือเปลี่ยนชื่อที่วางบนป้ายที่มีอยู่แล้วสร้างป้ายกำกับใหม่จากนั้นเปลี่ยนไปใช้:

ก่อนทำอะไร:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "master"

หลังจากgit branch -m:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

หลังจากgit branch -t master upstream/master:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

นี่C0คือคอมมิตล่าสุด (แผนผังแหล่งที่มาที่สมบูรณ์) ที่คุณได้รับเมื่อคุณทำgit cloneไฟล์. C1 ถึง C9 คือความมุ่งมั่นของคุณ

โปรดทราบว่าหากคุณเป็นเช่นgit checkout bunchofhacksนั้นgit reset --hard HEAD^^สิ่งนี้จะเปลี่ยนภาพสุดท้ายเป็น:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

เหตุผลก็คือHEAD^^ตั้งชื่อการแก้ไขสองขึ้นจากส่วนหัวของสาขาปัจจุบัน (ซึ่งก่อนการรีเซ็ตจะเป็นbunchofhacks) reset --hardจากนั้นจึงย้ายป้ายกำกับ Commits C8 และ C9 ตอนนี้ส่วนใหญ่มองไม่เห็น (คุณสามารถใช้สิ่งต่างๆเช่น reflog และgit fsckค้นหาได้ แต่มันไม่สำคัญอีกต่อไป) ป้ายกำกับของคุณเป็นของคุณที่จะย้ายตามที่คุณต้องการ คำสั่งดูแลคนที่เริ่มต้นด้วยfetch remotes/เป็นเรื่องธรรมดาที่จะจับคู่ "ของคุณ" กับ "ของพวกเขา" (ดังนั้นหากพวกเขามีremotes/origin/mauveคุณก็จะตั้งชื่อของคุณmauveด้วยเช่นกัน) แต่คุณสามารถพิมพ์ "ของพวกเขา" ได้ทุกเมื่อที่คุณต้องการตั้งชื่อ / ดูว่าคุณได้รับ "จากพวกเขา" (โปรดจำไว้ว่า "หนึ่งคอมมิต" คือแผนผังซอร์สทั้งหมดคุณสามารถเลือกไฟล์เฉพาะหนึ่งไฟล์จากคอมมิตหนึ่งไฟล์git showตัวอย่างเช่น


12
ฉันได้เรียนรู้มากมายจากคำตอบที่ยอดเยี่ยมของคุณ แต่ฉันยังคงสับสนว่าทำไมฉันจึงได้รับข้อความสถานะคอมไพล์: "สาขาของคุณอัปเดต" ต้นทาง / ต้นแบบ "" เมื่อ repo ต้นน้ำมีการกระทำหลายรายการก่อน repo ปัจจุบันของฉัน ฉันสามารถรับข้อมูลล่าสุดได้ด้วย git pull แต่ฉันจะรู้ได้อย่างไรว่าฉันต้องดึงหากข้อความแจ้งว่าฉันทันสมัย
Christopher Werby

@ChristopherWerby: ดูเหมือนว่าคุณกำลังทำงานgit mergeเป็นคำสั่งบรรทัดคำสั่ง (ซึ่งเป็นสิ่งที่ฉันทำเองเป็นวิธีการที่สมเหตุสมผล) หมายเหตุแม้ว่าที่git pullเริ่มต้นจากการทำงานครั้งแรกgit fetch, แล้วทำงานgit merge(หรือgit rebaseถ้าคุณบอกว่ามันจะทำอย่างนั้นแทน) เป็นขั้นตอนการดึงข้อมูลที่นำคอมมิตใหม่มารวม (หรือ rebased-only)
torek

@torek มีคำสั่งอื่นนอกเหนือจากgit statusที่ฉันสามารถใช้เพื่อดูว่า repo ต้นน้ำอยู่ข้างหน้า repo ปัจจุบันของฉันหรือไม่ ข้อความที่ได้รับมีgit statusระบุว่า "สาขาของคุณเป็นปัจจุบัน" ที่มา / ต้นแบบ "ทำให้ฉันสับสนว่าฉันมีการเปลี่ยนแปลงล่าสุดเมื่อฉันไม่ทำ บางครั้งฉันได้รับข้อความบางอย่างเช่น "ที่มา / ต้นแบบคือ 5 คอมมิตก่อนสาขาของคุณ" (การถอดความ) แต่มันไม่สอดคล้องกัน
Christopher Werby

1
สิ่งนี้ยังไม่สามารถตอบได้จริงว่าเหตุใดจึงgit statusบอกว่า "สาขาของคุณทันสมัย" ในทันทีที่git fetchดึงวัตถุกว่าร้อยชิ้นลงมาและแก้ไขพื้นที่สามเหลี่ยมปากแม่น้ำได้เกือบร้อยแห่งโดยกล่าวถึงสาขาใหม่หลายรายการและแท็กใหม่สองสามรายการและเปลี่ยนหลัก (รีโมต การติดตาม) หัวหน้าสาขาคอมมิต - จากนั้นอีกสถานะคอมไพล์อย่างร่าเริงและไม่พูดไม่จาก็ยังคงพูดว่า "สาขาของคุณทันสมัยแล้ว" เห็นได้ชัดว่าจำนวนมากมาจากแหล่งกำเนิด แต่สาขานั้น "ทันสมัยกับแหล่งกำเนิด" ทั้งก่อนและหลัง?
NeilG

1
git pullรันgit fetchก่อนแล้วgit merge(หรือคำสั่งที่สองอื่น ๆ ที่คุณเลือก) git fetchขั้นตอนการปรับปรุงของหน่วยความจำ Git ของพวกเขาสถานะของ Git โดยเรียกขึ้นของพวกเขา Git และได้รับอะไรใหม่จากพวกเขา คุณgit statusจะตรวจสอบหน่วยความจำ Git ของคุณเกี่ยวกับ Git เท่านั้น
torek

18

ฉันมีปัญหาเดียวกับคุณ

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

ในที่สุดคำสั่งเหล่านี้จะอัปเดตไฟล์และโฟลเดอร์ทั้งหมดในเครื่องของฉัน:

git fetch --all
git reset --hard origin/master 

หรือหากคุณต้องการสาขา

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

1
ขอบคุณ! สิ่งนี้ใช้งานได้จริง โปรดทราบว่าชื่อสาขาต้องตรงตามตัวพิมพ์เล็กและใหญ่!
André Ramon

4

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

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

ปรับปรุง:

รับรหัสล่าสุดในระบบของฉัน

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

git fetch upstream
git checkout upstream/master

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


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

upstream/masterขออภัยควรจะได้รับ อัปเดตคำตอบของฉัน
Ryan Stewart

3

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

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name

1

คำตอบด้านบนนั้นดีกว่ามากในแง่ของความกว้างและความลึกของข้อมูลที่ให้มา แต่ดูเหมือนว่าหากคุณต้องการให้ปัญหาของคุณได้รับการแก้ไขเกือบจะในทันทีและไม่ต้องกังวลกับหลักการพื้นฐานบางประการของการควบคุมเวอร์ชันคุณสามารถ ...

  1. เปลี่ยนเป็นมาสเตอร์

    $ git checkout upstream master
    
  2. ลบสาขาที่คุณไม่ต้องการ (หมายเหตุ: ต้องมี -D แทนที่จะเป็นแฟล็ก -d ปกติเนื่องจากสาขาของคุณมีการคอมมิตล่วงหน้ามากกว่ามาสเตอร์)

    $ git branch -d <branch_name>
    
  3. สร้างสาขาใหม่

    $ git checkout -b <new_branch_name>
    

1

แม้ว่าคำตอบเหล่านี้จะไม่ได้ผลสำหรับฉัน แต่ฉันก็สามารถแก้ไขปัญหาได้โดยใช้คำสั่งต่อไปนี้

git fetch origin

นี่เป็นเคล็ดลับสำหรับฉัน


0

ขอเตือนอย่างเป็นมิตรหากคุณมีไฟล์ในเครื่องที่ไม่ได้อยู่ใน github และยังมีคำgit statusพูดของคุณ

สาขาของคุณเป็น "ต้นทาง / หลัก" ล่าสุดแล้ว ไม่มีอะไรจะผูกมัดต้นไม้ทำงานสะอาด

อาจเกิดขึ้นได้หากไฟล์อยู่ใน .gitignore

ลองวิ่ง

cat .gitignore 

และดูว่าไฟล์เหล่านี้ปรากฏขึ้นที่นั่นหรือไม่ นั่นจะอธิบายได้ว่าทำไมคอมไพล์ถึงไม่ต้องการย้ายไปที่รีโมต

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