เหตุใดฉันจึงต้อง“ git push --set-upstream origin <branch>”


147

ฉันสร้างสาขาท้องถิ่นสำหรับทดสอบ Solaris และ Sun Studio ฉันจึงผลักดันสาขาต้นน้ำ หลังจากทำการเปลี่ยนแปลงและพยายามพุชการเปลี่ยนแปลง:

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

ทำไมฉันต้องทำอะไรเป็นพิเศษสำหรับสิ่งนี้?

มีกรณีการใช้งานที่สมเหตุสมผลหรือไม่ที่ใครบางคนจะสร้าง<branch>กด<branch>ไปที่รีโมตแล้วอ้างว่าการกระทำ<branch>นั้นไม่ควรมีไว้เพื่อ<branch>?


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


นี่คือมุมมองของเครื่องอื่น สาขามีอยู่อย่างชัดเจนดังนั้นจึงถูกสร้างและผลักดัน:

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris


2
ขอบคุณ @Alexi น่าเสียดายที่สิ่งที่อ้างถึงนี้ไม่ได้อธิบายถึงกรณีการใช้งานที่ไร้สาระซึ่งจะแสดงโดยค่าเริ่มต้น (คำถามเหล่านี้ไม่ใช่คำถามเชิงโวหารฉันสนใจอย่างแท้จริงในเหตุผลของการออกแบบ UX)
jww

1
โปรดทราบว่าสามารถกำหนดค่าได้ ถ้าคุณทำเช่นgit config --add push.default currentนั้น git push จะสร้าง branch โดยอัตโนมัติใน repo ระยะไกลหากจำเป็น
Gogowitsch

คำตอบ:


271

TL; DR: git branch --set-upstream-to origin/solaris


คำตอบสำหรับคำถามที่คุณถาม - ซึ่งฉันจะเขียนใหม่เล็กน้อยว่า "ฉันต้องตั้งค่าต้นน้ำ" คือ: ไม่คุณไม่ต้องตั้งค่าต้นน้ำเลย

อย่างไรก็ตามหากคุณไม่มีต้นน้ำสำหรับสาขาปัจจุบัน Git จะเปลี่ยนพฤติกรรมของมันgit pushและคำสั่งอื่น ๆ ด้วย

เรื่องราวการผลักดันที่สมบูรณ์ที่นี่ยาวและน่าเบื่อและย้อนกลับไปในประวัติศาสตร์ก่อน Git เวอร์ชัน 1.5 เพื่อให้สั้นลงมากgit pushมีการนำไปใช้งานไม่ดี 1 ในฐานะของ Git รุ่น 2.0 Git ตอนนี้มีการกำหนดค่าลูกบิดสะกดซึ่งขณะนี้เริ่มต้นที่push.default simpleสำหรับ Git หลายเวอร์ชันก่อนและหลัง 2.0 ทุกครั้งที่คุณวิ่งgit pushGit จะส่งเสียงดังออกมามากมายเพื่อพยายามโน้มน้าวให้คุณตั้งค่าpush.defaultเพื่อที่git pushจะปิดเครื่อง

คุณไม่ได้ระบุว่าคุณกำลังใช้งาน Git เวอร์ชันใดหรือไม่ว่าคุณได้กำหนดค่าไว้push.defaultหรือไม่ดังนั้นเราจึงต้องเดา ฉันเดาว่าคุณกำลังใช้รุ่น Git 2 จุดบางสิ่งบางอย่างและที่คุณได้ตั้งค่าpush.defaultที่จะsimpleได้รับมันจะปิดขึ้น อย่างแม่นยำซึ่งเป็นรุ่นของ Git ที่คุณมีและสิ่งที่ถ้าสิ่งที่คุณได้push.defaultตั้งค่าให้, ไม่ว่าเนื่องจากว่าประวัติศาสตร์อันยาวนานและน่าเบื่อ แต่ในท้ายที่สุดแล้วความจริงที่ว่าคุณจะได้รับการร้องเรียนจากยัง Git อื่นแสดงให้เห็นว่า Git ของคุณคือกำหนดค่าเพื่อหลีกเลี่ยงข้อผิดพลาดจากอดีต

ต้นน้ำคืออะไร?

ต้นน้ำเป็นเพียงอีกชื่อสาขามักจะเป็นสาขาที่ห่างไกลการติดตามที่เกี่ยวข้องกับ (ปกติท้องถิ่น) สาขา

ทุกสาขามีตัวเลือกในการตั้งค่าต้นน้ำหนึ่ง (1) ชุด นั่นคือทุกสาขามีต้นน้ำหรือไม่มีต้นน้ำ ไม่มีสาขาใดสามารถมีต้นน้ำได้มากกว่าหนึ่งแห่ง

ต้นน้ำควรแต่ไม่จำเป็นต้องเป็นสาขาที่ถูกต้อง (ไม่ว่าจะเป็นการติดตามระยะไกลเช่นหรือในพื้นที่) นั่นคือถ้าสาขาปัจจุบันBมีต้นน้ำU , ควรทำงาน ถ้ามันใช้ไม่ได้ - ถ้ามันบ่นว่าไม่มีU - Git ส่วนใหญ่จะทำราวกับว่าไม่ได้ตั้งค่าต้นน้ำเลย คำสั่งบางคำเช่นจะแสดงการตั้งค่าอัปสตรีม แต่ทำเครื่องหมายว่า "ไปแล้ว"origin/Bmastergit rev-parse U git branch -vv

ต้นน้ำคืออะไร?

หากคุณpush.defaultตั้งค่าเป็นsimpleหรือupstreamการตั้งค่าอัปสตรีมจะgit pushใช้โดยไม่มีข้อโต้แย้งเพิ่มเติมก็ใช้ได้

git pushนั่นคือมันนั่นคือทั้งหมดที่มันไม่สำหรับ แต่นั่นค่อนข้างสำคัญเนื่องจากgit pushเป็นหนึ่งในสถานที่ที่การพิมพ์ผิดง่ายๆทำให้เกิดอาการปวดหัว

หากคุณpush.defaultมีการตั้งค่าnothing, matchingหรือการตั้งค่าต้นน้ำไม่ทำอะไรเลยสำหรับcurrentgit push

(ทั้งหมดนี้ถือว่าเวอร์ชัน Git ของคุณเป็นอย่างน้อย 2.0)

ต้นน้ำส่งผลกระทบ git fetch

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

ต้นน้ำส่งผลกระทบgit mergeและgit rebaseด้วย

หากคุณเรียกใช้git mergeหรือgit rebaseไม่มีอาร์กิวเมนต์เพิ่มเติม Git จะใช้ต้นน้ำของสาขาปัจจุบัน ดังนั้นจึงทำให้การใช้สองคำสั่งนี้สั้นลง

ต้นน้ำส่งผลกระทบ git pull

คุณไม่ควรใช้2 อย่างgit pullต่อไป แต่ถ้าคุณทำให้git pullใช้การตั้งค่าต้นน้ำเพื่อดูว่าจะดึงข้อมูลจากรีโมตใดจากนั้นสาขาใดที่จะรวมหรือสร้างฐานใหม่ด้วย นั่นคือgit pullจะเป็นสิ่งเดียวกันเป็นgit fetch-because มันจริงทำงาน git fetchและอื่นแล้วจะเป็นสิ่งเดียวกันเป็นgit mergeหรือgit rebaseเพราะมันจริงทำงาน หรือgit mergegit rebase

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

ต้นน้ำส่งผลกระทบ git status

สิ่งนี้อาจสำคัญที่สุด เมื่อคุณตั้งค่าอัปสตรีมแล้วgit statusคุณสามารถรายงานความแตกต่างระหว่างสาขาปัจจุบันของคุณกับสาขาต้นน้ำในแง่ของการคอมมิต

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

เนื่องจากการgit statusรัน:

  • git rev-list --count @{u}..HEAD: คุณมีข้อผูกมัดกี่ข้อกับBสิ่งที่ไม่ได้ทำ?origin/B
  • git rev-list --count HEAD..@{u}: คุณมีข้อผูกมัดกี่ข้อกับสิ่งที่ไม่ได้ทำ?origin/BB

การตั้งค่าต้นน้ำทำให้คุณได้รับสิ่งเหล่านี้ทั้งหมด

วิธีมาmasterแล้วมีชุดต้นน้ำ?

เมื่อคุณโคลนจากระยะไกลเป็นครั้งแรกโดยใช้:

$ git clone git://some.host/path/to/repo.git

หรือคล้ายกันขั้นตอนสุดท้าย Git git checkout masterไม่สามารถเป็นหลัก การตรวจสอบจากสาขาในประเทศนี้masterเท่านั้นคุณไม่ได้มีmasterสาขาในท้องถิ่น

บนมืออื่น ๆ คุณจะมีสาขาที่ห่างไกลติดตามชื่อorigin/masterเพราะคุณเพียงแค่โคลนมัน

Git เดาว่าคุณต้องหมายถึง: "ทำให้ฉันเป็นคนท้องถิ่นใหม่masterที่ชี้ไปที่การกระทำเดียวกันกับการติดตามระยะไกลorigin/masterและในขณะที่คุณอยู่ให้ตั้งค่าต้นน้ำสำหรับmasterเป็นorigin/master"

สิ่งนี้เกิดขึ้นกับทุกสาขาgit checkoutที่คุณยังไม่มี Git สร้างสาขาและทำให้ "ติดตาม" (มีเป็นต้นน้ำ) สาขาการติดตามระยะไกลที่เกี่ยวข้อง

แต่ตอนนี้ไม่ได้ทำงานใหม่สาขาคือสาขาที่ไม่มีสาขาที่ห่างไกลการติดตามเลย

หากคุณสร้างสาขาใหม่ :

$ git checkout -b solaris

origin/solarisมีเป็นยังไม่มี ในพื้นที่ของคุณsolaris ไม่สามารถติดตามสาขาการติดตามระยะไกลorigin/solarisเนื่องจากไม่มีอยู่

เมื่อคุณผลักดันสาขาใหม่ครั้งแรก:

$ git push origin solaris

ที่สร้าง solarisขึ้นoriginและด้วยเหตุนี้ยังสร้างorigin/solarisในที่เก็บ Git ของคุณเอง แต่มันสายเกินไปคุณมีท้องถิ่นsolarisที่ไม่มีต้นน้ำแล้ว 3

ไม่ควรตั้ง Git ตอนนี้เป็นอัปสตรีมโดยอัตโนมัติใช่หรือไม่

อาจ. ดู "ใช้งานได้ไม่ดี" และเชิงอรรถ 1 ตอนนี้เปลี่ยนยาก: มีสคริปต์4ล้านรายการที่ใช้ Git และบางสคริปต์อาจขึ้นอยู่กับพฤติกรรมในปัจจุบัน การเปลี่ยนแปลงลักษณะการทำงานจำเป็นต้องมีรีลีสหลักใหม่ nag-ware เพื่อบังคับให้คุณตั้งค่าฟิลด์คอนฟิกูเรชันและอื่น ๆ กล่าวโดยย่อ Git เป็นเหยื่อของความสำเร็จของตัวเองไม่ว่าจะมีข้อผิดพลาดใด ๆ ในวันนี้สามารถแก้ไขได้ก็ต่อเมื่อการเปลี่ยนแปลงนั้นส่วนใหญ่มองไม่เห็นชัดเจนดีขึ้นมากหรือทำได้ช้าลงเมื่อเวลาผ่านไป

ความจริงก็คือไม่มีวันนี้เว้นแต่คุณจะใช้--set-upstreamหรือ-uในช่วงgit push. นั่นคือสิ่งที่ข้อความกำลังบอกคุณ

คุณไม่จำเป็นต้องทำแบบนั้น ดังที่เราได้กล่าวไว้ข้างต้นคุณไม่จำเป็นต้องทำเลย แต่สมมติว่าคุณต้องการต้นน้ำ คุณได้สร้างสาขาsolarisไว้originแล้วผ่านการพุชก่อนหน้านี้และเมื่อgit branchผลลัพธ์ของคุณแสดงแสดงว่าคุณมีที่ origin/solarisเก็บในเครื่องของคุณแล้ว

solarisคุณเพียงแค่ไม่ได้ตั้งเป็นต้นน้ำสำหรับ

git branch --set-upstream-toในการตั้งค่าได้ในขณะนี้มากกว่าในระหว่างการผลักดันครั้งแรกที่ใช้ --set-upstream-toคำสั่งย่อยใช้ชื่อของสาขาที่มีอยู่เช่นorigin/solarisและชุดต้นน้ำสาขาปัจจุบันที่สาขาอื่น ๆ

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


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

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

3ถ้าคุณรันครั้งแรก git pushในชื่อgit push -u origin solaris- นี่ถ้าคุณเพิ่ม-uแฟล็ก - Git จะตั้งค่าorigin/solarisเป็นอัพสตรีมสำหรับสาขาปัจจุบันของคุณถ้าการพุชสำเร็จ (และต่อเมื่อ) ดังนั้นคุณควรจัดหา-uในการผลักดันครั้งแรก ในความเป็นจริงคุณสามารถจัดหาได้ในการผลักดันใด ๆ ในภายหลังและจะตั้งค่าหรือเปลี่ยนแปลงต้นน้ำ ณ จุดนั้น แต่ฉันคิดว่าgit branch --set-upstream-toง่ายกว่าถ้าคุณลืม

4วัดโดยวิธี Austin Powers / Dr Evil เพียงแค่พูดว่า "one MILLLL-YUN" เท่านั้น


2
หากกรณีทั่วไปคือการ {create branch / push branch / use branch} ผลลัพธ์ของการพุชสาขาภายในเครื่องใหม่ไปยังที่เก็บ Git ระยะไกลและการติดตามนั้นไม่ควรเป็นสิ่งที่ใช้งานได้จริงหรือไม่ และถ้ามีคนต้องการ {create branch / push branch / don't use branch} ก็ไม่ควรต้องทำอะไรเป็นพิเศษเช่น--set-upstream /dev/nullไหม เหตุใดจึงผลักภาระไปสู่กรณีทั่วไป ฉันไม่เข้าใจการตัดสินใจด้านวิศวกรรมและการใช้งานเหล่านี้จริงๆ
jww

1
@VonC: ขวาที่จุดของgit push -uแต่จริงๆดูเหมือนว่าgit push -uควรจะเริ่มต้นหรืออย่างน้อยเริ่มต้นถ้าไม่มีต้นน้ำและควรจะมีgit push --no-set-upstreamเมื่อไม่มีในปัจจุบันต้นน้ำและคุณต้องการเก็บไว้ เป็นอย่างนั้น (ด้วยเหตุผลที่เข้าใจยาก :-))
torek

2
"คุณถามคำถามแบบนี้เรื่อย ๆ เพราะฉันคิดว่าคุณได้เขียน Git ว่า" น่ารังเกียจจริงๆ " โปรดเก็บการคาดเดาประเภทนี้ไว้กับตัวเอง ฉันเจอคำถามนี้เพราะฉันมักจะถามตัวเองด้วยคำถามประเภทนี้ ฉันไม่ใช่นักออกแบบ UX ที่ดีที่สุดในโลก แต่ถึงแม้ฉันจะรู้ว่าพฤติกรรมเริ่มต้นในสถานการณ์เฉพาะนี้อาจดีกว่านี้
Steven Byks

4
@torek - ขอบคุณครับ คำตอบของคุณยอดเยี่ยมมาก มีความคิดที่ดีมีโครงสร้างที่ดีและให้ข้อมูลอย่างมาก :-)
Steven Byks

6
โปรดทราบว่าสามารถกำหนดค่าได้ ถ้าคุณทำเช่นgit config --add push.default currentนั้น git push จะสร้าง branch โดยอัตโนมัติใน repo ระยะไกลหากจำเป็น
Gogowitsch

31

ความแตกต่างระหว่าง
git push origin <branch>
และ
git push --set-upstream origin <branch>
ก็คือทั้งสองดันได้ดีไปยังที่เก็บระยะไกล แต่เมื่อคุณดึงคุณจะสังเกตเห็นความแตกต่าง

ถ้าคุณทำ:
git push origin <branch>
เมื่อดึงคุณต้องทำ:
git pull origin <branch>

แต่ถ้าคุณทำ:
git push --set-upstream origin <branch>
เมื่อดึงคุณจะต้องทำ:
git pull

ดังนั้นการเพิ่มในช่วยให้ไม่ต้องระบุสาขาที่คุณต้องการที่จะดึงจากทุกครั้งที่คุณทำ--set-upstreamgit pull


ความแตกต่างระหว่าง "git push" สองเวอร์ชันซึ่งฉันไม่รู้ว่าทำไมฉันถึงต้องการ / จำเป็นต้องใช้ ไม่มีจุดหมาย!
Frank Puck

17

คำสั่งเต็มโดยทั่วไปเป็นเช่นgit push <remote> <local_ref>:<remote_ref>. หากคุณใช้งานเพียงแค่git pushคอมไพล์จะไม่รู้ว่าจะทำอย่างไรเว้นแต่คุณจะกำหนดค่าบางอย่างที่ช่วยในการตัดสินใจ ใน git repo เราสามารถตั้งค่ารีโมทได้หลายตัว นอกจากนี้เราสามารถส่งการอ้างอิงในพื้นที่ไปยังการอ้างอิงระยะไกล คำสั่งเต็มเป็นวิธีที่ตรงไปตรงมาที่สุดในการผลักดัน หากคุณต้องการพิมพ์คำน้อยลงคุณต้องกำหนดค่าก่อนเช่น --set-upstream

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