Origin / HEAD ได้รับการตั้งค่าอย่างไร


144

ฉันมีสาขาตั้งขึ้นเพื่อติดตามการอ้างอิงในแหล่งกำเนิด git checkout <branchname>สลับไปที่สาขานั้นและ a git statusจะแสดงให้ฉันเห็นว่าสาขาของฉันอยู่ข้างหน้าหรือข้างหลังไกลแค่ไหนจากจุดเริ่มต้น แต่ฉันประหลาดใจที่origin/HEADยังคงชี้ไปที่origin/masterและไม่ใช่origin/<branchname>

ดังนั้นคำถามของฉันคือภายใต้สถานการณ์ใดที่กำเนิด / หัวถูกย้าย

แก้ไข:

ฉันขอขอบคุณคำตอบเกี่ยวกับวิธีการย้ายต้นกำเนิด / หัว แต่ฉันสนใจในสิ่งที่ "อินทรีย์" ย้ายมันนอกฉันอย่างชัดเจนบอกให้ทำเช่นนั้น

ตัวอย่างเช่นเมื่อฉันเปลี่ยนสาขา git ทำให้ HEAD ชี้ไปที่สาขาที่ฉันเช็คเอาท์ดังนั้นฉันจึงประหลาดใจที่ต้นกำเนิด / HEAD ไม่เคลื่อนไหวในลักษณะเดียวกัน


refs/origin/HEADโปรดทราบว่าคำถามนี้เป็นเรื่องเกี่ยวกับการอ้างอิงสัญลักษณ์ท้องถิ่นบนรีโมทเช่น มันไม่ได้เกี่ยวกับวิธีการHEADตั้งค่าการอ้างอิงสัญลักษณ์ของที่เก็บ
clacke

คำตอบ:


173

โปรดทราบก่อนว่าคำถามของคุณแสดงความเข้าใจผิดเล็กน้อย Origin / HEAD แสดงถึงสาขาเริ่มต้นบนรีโมตนั่นคือ HEAD ที่อยู่ในที่เก็บข้อมูลรีโมตนั้นที่คุณเรียกใช้ Origin เมื่อคุณสลับสาขาใน repo ของคุณคุณจะไม่ส่งผลกระทบต่อสิ่งนั้น เช่นเดียวกับสาขาระยะไกล คุณอาจมีmasterและorigin/masterใน repo ของคุณซึ่งorigin/masterเป็นตัวแทนของmasterสาขาในพื้นที่เก็บข้อมูลระยะไกล

HEAD ของ Origin จะเปลี่ยนเฉพาะเมื่อคุณหรือคนอื่นเปลี่ยนในที่เก็บระยะไกลซึ่งโดยทั่วไปไม่ควรเกิดขึ้น - คุณต้องการให้ repo สาธารณะสาขาเริ่มต้นคงที่ในสาขาที่มั่นคง (อาจเป็น Master) origin / HEAD คือการอ้างอิงแบบโลคัลที่แสดงสำเนาโลคัลของ HEAD ในที่เก็บแบบรีโมต (ชื่อเต็มของมันคือการอ้างอิง / รีโมท / กำเนิด / หัว)

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


แก้ไข : ปัญหาที่กล่าวถึงด้านล่างได้รับการแก้ไขในGit 1.8.4.3 ; ดูอัปเดตนี้


มีข้อแม้เล็ก ๆ อยู่ HEAD คือการอ้างอิงเชิงสัญลักษณ์ชี้ไปที่สาขาแทนที่จะส่งไปยังการคอมมิตโดยตรง แต่โปรโตคอลการถ่ายโอนระยะไกล git เท่านั้นที่รายงานการกระทำเพื่อการอ้างอิง ดังนั้น Git จึงรู้ SHA1 ของการกระทำที่ชี้ไปที่ HEAD และผู้อ้างอิงอื่น ๆ ทั้งหมด จากนั้นจะต้องอนุมานค่าของ HEAD โดยการค้นหาสาขาที่ชี้ไปที่การกระทำเดียวกัน นี่หมายความว่าหากมีสองสาขาเกิดขึ้นที่จุดนั้นมันจะคลุมเครือ (ฉันเชื่อว่ามันเลือกอาจารย์ถ้าเป็นไปได้จากนั้นกลับไปที่ตัวอักษรแรก) คุณจะเห็นรายงานนี้ในผลลัพธ์ของgit remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

ผิดปกติแม้ว่าความคิดของหัวพิมพ์ด้วยวิธีนี้จะเปลี่ยนถ้าสิ่งที่เปลี่ยนแปลงในระยะไกล (เช่นถ้า foo จะถูกลบออก) refs/remotes/origin/HEADก็ไม่ได้ปรับปรุงจริง สิ่งนี้สามารถนำไปสู่สถานการณ์ที่แปลกจริง ๆ บอกว่าในตัวอย่างข้างต้นกำเนิด / HEAD จริงชี้ไปที่ foo และสาขา foo ของต้นกำเนิดถูกลบออกแล้ว จากนั้นเราสามารถทำสิ่งนี้:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

ดังนั้นแม้ว่าการแสดงจากระยะไกลจะรู้ว่า HEAD นั้นเป็นผู้เชี่ยวชาญ แต่ก็ไม่ได้อัพเดทอะไรเลย สาขา fale เก่าถูกตัดอย่างถูกต้องและ HEAD จะกลายเป็นห้อย (ชี้ไปที่สาขาที่ไม่มีอยู่) และก็ยังไม่อัปเดตให้ชี้ไปที่ต้นแบบ หากคุณต้องการแก้ไขปัญหานี้ให้ใช้git remote set-head origin -aซึ่งกำหนดหัว HEAD ของต้นกำเนิดโดยอัตโนมัติจากนั้นตั้งค่า Origin / HEAD ให้ชี้ไปที่สาขาระยะไกลที่เหมาะสม


@jefromi คำตอบที่น่ากลัว! เป็นเพียงข้อสังเกต: คุณเขียนว่าHEAD เป็นผู้อ้างอิงเชิงสัญลักษณ์ชี้ไปที่สาขาแทนที่จะตรงไปยังคำสั่ง [... ]แต่อาจคุ้มค่าที่จะกล่าวถึง "HEAD HEAD state" เพื่อความสมบูรณ์
jub0bs

2
@Jubobs ขอบคุณ! หากคำตอบของฉันต้องการการอัปเดตโปรดอย่าลังเลที่จะแก้ไขมัน - แน่นอนว่ามันจะช่วยให้ผู้คนประหยัดเวลาในการอ่านบทสรุปสั้น ๆ เกี่ยวกับการทำงานของสิ่งต่าง ๆ จริง ๆ แทนที่จะต้องจำแนกสิ่งที่เป็นจริงเมื่อสองปีก่อน .
Cascabel

ได้อ่านสิ่งนี้อย่างน้อย 5 ครั้งและยังไม่เข้าใจนิดหน่อย
krb686

7
git remote set-head origin -aทำงานให้ฉัน
Shujito

75

มันคือการตั้งค่าของคุณในฐานะเจ้าของ repo ท้องถิ่นของคุณ เปลี่ยนเป็นดังนี้

git remote set-head origin some_branch

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

รายการคู่มือสำหรับชุดหัวระยะไกลให้ข้อมูลที่ดีเกี่ยวกับเรื่องนี้

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


1
การเน้นการแก้ไขไม่ถูกต้องที่นี่ นอกจากนี้ยังสามารถเปลี่ยนแปลงได้หากคุณโคลนจากสำเนาในเครื่องที่ไม่ได้อยู่ในสาขาหลัก
mphair

ฉันไม่ถือว่าโคลน "เคลื่อนไหว" แต่ฉันคิดว่าเราไม่เห็นด้วยกับเรื่องนี้ :)
EIS

24

อะไรคือต้นกำเนิด / หัว "ออร์แกนิก"?

  • git clone ตั้งค่าหนึ่งครั้งไปยังจุดที่ HEAD เริ่มต้น
    • มันทำหน้าที่เป็นสาขาเริ่มต้นในการชำระเงินหลังจากโคลนด้วย git clone

HEAD บนจุดเริ่มต้นแสดงถึงอะไร?

  • บนที่เก็บเปลือย (มักจะเป็นที่เก็บข้อมูล“ บนเซิร์ฟเวอร์”) ทำหน้าที่เป็นเครื่องหมายสำหรับสาขาเริ่มต้นเพราะgit cloneใช้ในลักษณะดังกล่าว
  • บนที่เก็บแบบไม่ใช้เปลือย (โลคัลหรือรีโมต) จะสะท้อนการเช็กเอาต์ปัจจุบันของที่เก็บ

ชุดต้นกำเนิด / หัวคืออะไร?

  • git clone ดึงข้อมูลและตั้งค่า
  • มันจะสมเหตุสมผลถ้า git fetchการปรับปรุงมันเหมือนกับการอ้างอิงอื่น ๆ แต่มันก็ไม่ได้
  • git remote set-head origin -a ดึงข้อมูลและตั้งค่า
    • มีประโยชน์ในการอัปเดตความรู้ในท้องถิ่นเกี่ยวกับสิ่งที่ห่างไกลพิจารณาว่าเป็น "สาขาเริ่มต้น"

เรื่องไม่สำคัญ

  • origin/HEAD ยังสามารถตั้งค่าอื่น ๆ ได้โดยไม่ต้องติดต่อรีโมต: git remote set-head origin <branch>
    • ฉันไม่เห็นกรณีใช้งานยกเว้นเรื่องการทดสอบ
  • น่าเสียดายที่ไม่มีสิ่งใดสามารถตั้งค่า HEAD บนรีโมทได้
  • รุ่นเก่าของคอมไพล์ไม่ทราบว่า HEAD ของสาขาใดชี้ไปที่รีโมตเพียงอย่างเดียวที่กระทำการแฮชในที่สุดจึงมี: ดังนั้นหวังว่าจะเลือกชื่อสาขาที่ชี้ไปที่แฮชเดียวกัน

ฉันสูญเสียการอ้างอิงถึงorigin/HEADและโซลูชันของคุณช่วย ขอบคุณ!
java_dude

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

@MichaWiedenmann เหตุใดจึงเป็นทางลัดที่กำหนดค่าไว้ในเครื่อง สำหรับทางลัดที่กำหนดไว้ในorigin/HEADเครื่องเป็นชื่อที่ไม่ดี และที่git cloneใช้ชื่อระยะไกลเป็นค่าเริ่มต้นสำหรับ "สาขากำหนดค่าในท้องถิ่น" ขัดแย้งกับที่ HEADเมื่อวันที่เก็บไม่ใช่เปลือยก็ไม่ได้ทำให้รู้สึกถึงปัจจุบันการใช้งานระยะไกล
Robert Siemer

10

คำเตือน : นี่คือการอัปเดตคำตอบของ Jefromiซึ่งฉันกำลังเขียนเพื่อบันทึกความอยากรู้อยากเห็นบางครั้ง

ฉันพยายามอย่างไร้ประโยชน์ที่จะทำซ้ำ (ใน Git 2.0.1) remote HEAD is ambiguousข้อความที่ Jefromi กล่าวถึงในคำตอบของเขา; ดังนั้นฉันจึงขุดเล็กน้อย (โดยการโคลนhttps://github.com/git/gitและค้นหาบันทึก) มันเคยเป็นอย่างนั้น

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Commit 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771ลงวันที่ 27 กุมภาพันธ์ 2009 พบกับgit log --reverse --grep="HEAD is ambiguous")

อย่างไรก็ตามความคลุมเครือในคำถามได้ถูกยกขึ้น :

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(กระทำ9196a2f8bd46d36a285bdfa03b4540ed3f01f671, ลงวันที่ 8 พฤศจิกายน 2013, พบกับgit log --grep="ambiguous" --grep="HEAD" --all-match)

แก้ไข (ขอบคุณtorek ):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

ซึ่งหมายความว่าหากคุณใช้Git v1.8.4.3 หรือใหม่กว่าคุณไม่ควรพบปัญหาที่คลุมเครือ - ระยะไกล - HEAD


1
ขึ้นอยู่กับแท็กในแหล่ง git การแก้ไขนี้ใช้กับ git เวอร์ชัน 1.8.4.3 และใหม่กว่า
torek

@ RobertSiemer ฉันไม่แน่ใจ แต่ฉันคิดว่าใช่
jub0bs

8

จำได้ว่ามีrepos คอมไพล์สองตัวที่เรากำลังพูดถึง repo ท้องถิ่นของคุณด้วยรหัสของคุณและระยะไกลทำงานที่อื่น

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

คอมพิวเตอร์ของคุณ (repo ในพื้นที่) ไม่มีธุรกิจที่เปลี่ยนตัวชี้ HEAD บน repo git ระยะไกล มันอาจเป็นเจ้าของโดยนักพัฒนาที่แตกต่างกันเช่น

อีกอย่างหนึ่งสิ่งที่คอมพิวเตอร์ของคุณเรียกกำเนิด / XXX คือความเข้าใจในคอมพิวเตอร์ของคุณเกี่ยวกับสถานะของรีโมต ณ เวลาที่ดึงข้อมูลครั้งล่าสุด

ดังนั้นต้นกำเนิด / การอัพเดทแบบ "เป็นอินทรีย์" จะเป็นอย่างไร มันจะเป็นกิจกรรมใน repo คอมไพล์ระยะไกล ไม่ใช่ repo ในพื้นที่ของคุณ

คนได้กล่าวถึง

git อ้างอิงสัญลักษณ์หัวอ้างอิง / หัว / my_other_branch

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


1
ขออภัยถ้าฉันทำซ้ำเล็กน้อย ฉันแค่ต้องการชี้ให้เห็นความจริงที่ว่า git นั้นเป็นระบบควบคุมเวอร์ชันแบบกระจายและดังนั้น repos ทั้งสองจึงเป็นอิสระ
Pablo Maurin

3

เรียกใช้คำสั่งต่อไปนี้จาก git CLI:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name> 

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