ดึงการคอมมิทเฉพาะจากที่เก็บ Git ระยะไกล


189

มีวิธีใดที่จะเรียกคืนการคอมมิตเฉพาะจากรีโมต Git ระยะไกลโดยไม่ทำการโคลนบนพีซีของฉันได้หรือไม่? โครงสร้างของ repo ระยะไกลนั้นเหมือนกับโครงสร้างของฉันและดังนั้นจะไม่มีความขัดแย้งใด ๆ แต่ฉันไม่รู้ว่าจะทำอย่างไรและฉันไม่ต้องการที่จะโคลนพื้นที่เก็บข้อมูลขนาดใหญ่นั้น

ฉันใหม่สำหรับ git มีวิธีใด?


1
repo ที่มีอยู่ของคุณเป็นโคลนของรีโมตอยู่แล้วหรือมันแตกต่างอย่างสิ้นเชิง?
CharlesB

repo คือเคอร์เนล Linux และมันก็เหมือนกันมาก
Varun Chitre

เป็นโคลนหรือไม่
CharlesB

1
ไม่แน่นอน พิจารณาสิ่งนี้ให้ repo ระยะไกลอยู่ที่หัว D และของฉันอยู่ที่หัว A และอยู่ข้างหลังโดย B, C, D ฉันต้องการรวมคอมมิชชัน B จาก repo หนึ่งและ C จากอีกอันหนึ่งและ D จากอีกอันหนึ่งเป็น B, C, D ที่ทำใน repos เหล่านี้แตกต่างกับความเชี่ยวชาญของพวกเขาเอง
Varun Chitre

1
@VarunChitre คุณสามารถยอมรับคำตอบอื่น ๆ จาก VonC ได้หรือไม่?
CharlesB

คำตอบ:


109

เริ่มต้นด้วย Git เวอร์ชั่น 2.5+ (Q2 2558) การดึงการคอมมิทครั้งเดียว (โดยไม่ต้องโคลน repo เต็ม) เป็นไปได้จริง

ดูคอมมิชชัน 687668โดยFredrik Medley ( moroten) , 21 พฤษภาคม 2558
(ผสานโดยJunio ​​C Hamano - gitster-ในการกระทำ a9d3493 , 01 Jun 2015)

ตอนนี้คุณมีการกำหนดค่าใหม่ (ด้านเซิร์ฟเวอร์)

uploadpack.allowReachableSHA1InWant

อนุญาตให้upload-packยอมรับคำขอดึงข้อมูลที่ขอให้วัตถุที่สามารถเข้าถึงได้จากเคล็ดลับอ้างอิงใด ๆ อย่างไรก็ตามโปรดทราบว่าการคำนวณการเข้าถึงวัตถุมีราคาแพง
เริ่มfalseต้นที่

หากคุณรวมการกำหนดค่าฝั่งเซิร์ฟเวอร์นั้นเข้ากับตื้นตื้น ( git fetch --depth=1) คุณสามารถขอคำสั่งเดียว (ดูt/t5516-fetch-push.sh:

git fetch --depth=1 ../testrepo/.git $SHA1

คุณสามารถใช้git cat-fileคำสั่งเพื่อดูว่าการกระทำได้รับการดึง:

git cat-file commit $SHA1

" git upload-pack" ที่ทำหน้าที่ " git fetch" สามารถบอกได้ว่าให้บริการการกระทำที่ไม่ได้อยู่ที่ปลายอ้างอิงใด ๆ ตราบใดที่สามารถเข้าถึงได้จากการอ้างอิงด้วยuploadpack.allowReachableSHA1InWant ตัวแปรการกำหนดค่า


เอกสารฉบับเต็มคือ:

upload-pack: อนุญาตให้เรียก sha1 ที่เข้าถึงได้

ด้วยuploadpack.allowReachableSHA1InWantการตั้งค่าตัวเลือกการกำหนดค่าที่ฝั่งเซิร์ฟเวอร์ " git fetch" สามารถสร้างคำขอด้วยบรรทัด "ต้องการ" ที่ตั้งชื่อวัตถุที่ไม่ได้โฆษณา (น่าจะได้รับมาจากแบนด์หรือจากตัวชี้ submodule)
เฉพาะวัตถุที่สามารถเข้าถึงได้จากเคล็ดลับสาขาเช่นสหภาพของสาขาที่โฆษณาและสาขาที่ถูกซ่อนtransfer.hideRefsจะถูกประมวลผล
โปรดทราบว่ามีค่าใช้จ่ายที่เกี่ยวข้องในการเดินย้อนประวัติเพื่อตรวจสอบความสามารถในการเข้าถึง

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

กรณีที่มีประโยชน์เช่น

  • ที่เก็บที่มีไฟล์ขนาดใหญ่ในประวัติศาสตร์
  • การดึงข้อมูลที่จำเป็นสำหรับการชำระเงินแบบ submodule เท่านั้น
  • เมื่อแชร์ sha1 โดยไม่บอกสาขาที่แน่นอนว่ามันเป็นของและใน Gerrit ถ้าคุณคิดในแง่ของการกระทำแทนที่จะเปลี่ยนหมายเลข
    (กรณี Gerrit ได้รับการแก้ไขแล้วallowTipSHA1InWantเนื่องจากการเปลี่ยนแปลงของ Gerrit ทุกครั้งมีการอ้างอิง)

Git 2.6 (ไตรมาสที่ 3 ปี 2558) จะปรับปรุงรูปแบบดังกล่าว
ดูกระทำ 2bc31d1 , กระทำ cc118a6 (28 กรกฎาคม 2015) โดยเจฟฟ์คิง (peff )
(รวมโดยJunio C Hamano - gitster-ในการกระทำ 824a0be , 19 สิงหาคม 2015)

refs: สนับสนุนลบ transfer.hideRefs

หากคุณซ่อนลำดับชั้นของการอ้างอิงโดยใช้การตั้งค่าtransfer.hideRefsจะไม่มีวิธีใดที่จะแทนที่การกำหนดค่าในภายหลังเพื่อ "เลิกซ่อน"
แพทช์นี้ใช้การซ่อน "เชิงลบ" ซึ่งทำให้การจับคู่ถูกทำเครื่องหมายว่าไม่ถูกซ่อนทันทีแม้ว่าแมทช์อื่นจะซ่อน
เราดูแลเพื่อนำไปใช้ในการแข่งขันย้อนกลับการสั่งซื้อจากวิธีที่พวกเขาถูกเลี้ยงให้เราโดยการกำหนดค่าเครื่องจักรที่เป็นปกติที่ช่วยให้ "หนึ่งในชัยชนะที่ผ่านมา" การทำงานของเราตั้งค่าลำดับความสำคัญ (และรายการใน.git/configตัวอย่างเช่นจะแทนที่/etc/gitconfig)

ดังนั้นคุณสามารถทำได้:

git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'

เพื่อซ่อนrefs/secretใน repos ทั้งหมดยกเว้นบิตสาธารณะหนึ่งรายการใน repo หนึ่งรายการ


Git 2.7 (พ.ย. / ธ.ค. 2015) จะปรับปรุงอีกครั้ง:

ดูกระทำ 948bfa2 , กระทำ 00b293e (5 พฤศจิกายน 2015) กระทำ 78a766a , กระทำ 92cab49 , กระทำ 92cab49 , กระทำ 92cab49 (3 พฤศจิกายน 2015) กระทำ 00b293e , กระทำ 00b293e (5 พฤศจิกายน 2015) และกระทำ 92cab49 , กระทำ 92cab49 , กระทำ 92cab49 , กระทำ 92cab49 (3 พฤศจิกายน 2015) โดยLukas Fleischer (lfos )
ช่วยโดย: เอริคซันไชน์ (sunshineco )
(ผสานโดยJeff King - peff- in dbba85e , 20 พ.ย. 2558)

config.txt: จัดทำเอกสารความหมายของhideRefsด้วย namespaces

ตอนนี้ไม่มีคำจำกัดความที่ชัดเจนว่าtransfer.hideRefsควรทำอย่างไรเมื่อตั้งค่าเนมสเปซ
อธิบายว่าhideRefsคำนำหน้าตรงกับชื่อที่ลอกในกรณีนั้น นี่คือวิธีที่hideRefsรูปแบบการจัดการในปัจจุบันได้รับแพ็ค

hideRefs: เพิ่มการสนับสนุนสำหรับการอ้างอิงแบบเต็ม

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

ดังนั้นเอกสารใหม่ :

transfer.hideRefs:

หากมีการใช้เนมสเปซคำนำหน้าเนมสเปซจะถูกแยกออกจากการอ้างอิงแต่ละรายการก่อนที่จะจับคู่กับtransfer.hiderefsรูปแบบ
ตัวอย่างเช่นถ้าrefs/heads/masterมีการระบุในtransfer.hideRefsและ namespace ปัจจุบันถูกfooแล้วrefs/namespaces/foo/refs/heads/master ถูกตัดออกจากการโฆษณา แต่refs/heads/masterและ refs/namespaces/bar/refs/heads/masterยังคงมีการโฆษณาเป็นที่เรียกว่า "มี" เส้น
เพื่อให้ตรงกับการอ้างอิงก่อนที่จะปอกเพิ่ม^ด้านหน้าชื่ออ้างอิง ถ้าคุณรวม!และ^, !จะต้องระบุเป็นครั้งแรก


เราได้กล่าวถึงความคิดเห็นในการตั้งค่าuploadpack.allowAnySHA1InWantซึ่งช่วยให้upload-packสามารถยอมรับfetchคำขอที่ถามถึงวัตถุใด ๆ ได้เลย (ค่าเริ่มต้นเป็นfalse)

ดูคอมมิท f8edeaa (พ.ย. 2016, Git v2.11.1) โดยDavid "novalis" Turner ( novalis) :

upload-pack: อนุญาตให้เรียก sha1 ใดก็ได้

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

นอกจากนี้ยังเป็นที่นิยมในระบบแบบกระจาย - บางทีอาจมีเซิร์ฟเวอร์หนึ่งที่อ้างถึงการอ้างอิง แต่มีอีกอันที่มีแรงผลักดันไปยังการอ้างอิงนั้นและบางทีคำขอ HTTP ทั้งสองนั้นจะถูกนำไปยังเซิร์ฟเวอร์ที่แตกต่างกันเหล่านี้


4
คุณช่วยยกตัวอย่างที่สมบูรณ์มากขึ้นเกี่ยวกับวิธีสร้าง repo clone ด้วยการคอมมิชชันเดียวนี้ได้หรือไม่? ฉันพยายามแล้ว แต่ล้มเหลว .. ขอบคุณ!
Lars Bilke

1
ฉันต้องการผลักดันให้ GitHub บางทีพวกเขาอาจไม่อนุญาตสิ่งนี้
Lars Bilke

2
@ LarsBilke เรากำลังพูดถึงโคลนหรือดึงที่นี่ไม่ได้ผลัก และฉันค่อนข้างมั่นใจว่า GitHub ยังไม่มี Git 2.5 ที่ฝั่งเซิร์ฟเวอร์
VonC

2
ยิ่งไปกว่านั้นตอนนี้uploadpack.allowAnySHA1InWantไม่มีบทลงโทษการคำนวณการเข้าถึง (และเวกเตอร์ DoS)
.. GitHub หยุดช่วยเหลือน้ำแข็ง

1
ขอบคุณ! ฉันคิดว่ามันตลกที่พวกเขาอธิบายว่า "เชื่อใจผู้ใช้ในการเข้าถึง" มากกว่า "เชื่อใจผู้เขียน repo ที่ไม่ผลักอึแบบสุ่มที่พวกเขาไม่ต้องการให้สาธารณะ"
.. GitHub หยุดช่วยเหลือน้ำแข็ง

98

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

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

Git เก็บทุกอย่างไว้ใน.gitโฟลเดอร์ การคอมมิชชันไม่สามารถดึงข้อมูลและเก็บไว้แยกได้มันต้องการบรรพบุรุษทั้งหมดของมัน พวกเขาจะเชื่อมโยงกัน


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

git fetch origin refs/heads/branch:refs/remotes/origin/branch

นี้จะดาวน์โหลดเฉพาะ commits ที่มีอยู่ในสาขาที่ห่างไกลbranch (และคนที่คุณพลาด)origin/branchและเก็บไว้ใน จากนั้นคุณสามารถรวมหรือชำระเงิน

คุณสามารถระบุเฉพาะการมอบหมาย SHA1:

git fetch origin 96de5297df870:refs/remotes/origin/foo-commit

นี้จะดาวน์โหลดเพียงกระทำของที่ระบุ SHA-1 96de5297df870 (และบรรพบุรุษของตนที่คุณพลาด) และเก็บเป็น (ไม่ใช่ที่มีอยู่) origin/foo-commitสาขาที่ห่างไกล


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

1
มันยังคงดาวน์โหลดข้อมูลจำนวนมาก (430mb) ด้วยการเรียก git ความมุ่งมั่นที่ต้องการคือเพียงไม่กี่ kbs ไม่มีคำสั่งพิเศษที่จะทำเช่นนี้จริงเหรอ? และถ้าฉันต้องการลบ repo 'git fetched' เก็บไว้ที่ไหน
Varun Chitre

9
นี่ค่อนข้างล้าสมัยในขณะนี้ เรามีทั้งความสามารถในการดำเนินการโคลนตื้น , เช่นเดียวกับการดึงข้อมูลเดียวกระทำ ตอนนี้โคลนโคลนได้รับอนุญาตให้กดและดึงข้อมูลได้ตามปกติโดยไม่ต้องรู้ประวัติทั้งหมดของโครงการดังนั้นจึงไม่ถูกต้องที่จะบอกว่าการกระทำไม่สามารถอยู่คนเดียวได้หากไม่มีบรรพบุรุษ สิ่งที่คุณพูดเกี่ยวกับการดึงข้อมูลหลังจากการโคลนครั้งแรกนั้นเป็นความจริง แต่เราก็มีตัวเลือกที่ถูกกว่า
Theodore Murdock

6
คำสั่งสุดท้าย (โดยใช้ SHA1 กระทำ) ไม่ทำงานสำหรับฉัน คำสั่งจะทำ "บางสิ่ง" อย่างเงียบ ๆ ชั่วครู่หนึ่งแล้วออกโดยไม่มีข้อความหรือมีผลข้างเคียงที่ชัดเจน
HRJ

1
@HRJ ใช่ฉันพบนี้เกินไปบน Ubuntu 16.04 กับ 2.7.4-0ubuntu1.3Git อย่างไรก็ตามเมื่อใช้2.16.2-0ppa1~ubuntu16.04.1จาก PPA git-core สิ่งนี้จะทำงานได้ตามที่ควร ดูเหมือนข้อผิดพลาดที่ได้รับการแก้ไข ไม่พบการอ้างอิงถึงสิ่งนั้นด้วยการค้นหาอย่างรวดเร็ว หากใครสามารถชี้ให้ฉันได้ฉันก็ชอบที่จะรับการแก้ไขนี้ย้อนกลับ
gertvdijk

62

ฉันดึง repo คอมไพล์ของฉัน:

git pull --rebase <repo> <branch>

การอนุญาตให้คอมไพล์ดึงรหัสทั้งหมดสำหรับสาขาและจากนั้นฉันก็ทำการรีเซ็ตเพื่อความมุ่งมั่นที่สนใจฉัน

git reset --hard <commit-hash>

หวังว่านี่จะช่วยได้


1
แม้ว่าจะไม่มีคำตอบใดที่ช่วยชีวิตฉันได้! ขอบคุณมัด!
michaeltintiuc

การรีเซ็ต - ทำงานได้ดีสำหรับฉันหลังจากการโคลน! ขอบคุณ
Nick-ACNB

3
-1: คำสั่ง "ทำลาย" เช่นgit reset --hardเมื่อใช้ร่วมกันในโซลูชันทั่วไปสามารถนำผู้คนเข้าสู่กับดักที่พวกเขาสูญเสียข้อมูล
yauauie

54

คุณสามารถดึงข้อมูลรีโมตรีโมตได้เพียงครั้งเดียว

git fetch <repo> <commit>

ที่ไหน

  • <repo>สามารถเป็นชื่อ repo ระยะไกล (เช่นorigin) หรือแม้กระทั่ง URL repo ระยะไกล (เช่นhttps://git.foo.com/myrepo.git)
  • <commit> สามารถเป็น SHA1 ที่กระทำได้

ตัวอย่างเช่น

git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545

หลังจากที่คุณเรียกการกระทำ (และบรรพบุรุษที่หายไป) คุณสามารถเช็คเอาต์ด้วย

git checkout FETCH_HEAD

โปรดทราบว่าสิ่งนี้จะทำให้คุณอยู่ในสถานะ "ถอดหัว"


10
เมื่อฉันพยายามfetchrev เฉพาะที่คุณทำ git ล้มเหลวด้วยรหัสข้อผิดพลาด 1 และไม่มีผลลัพธ์ นี่เป็นสิ่งที่เคยทำงานในรุ่นที่ผ่านมาหรือไม่ (ฉัน v2.0.2.)
Jack O'Connor

2
แก้ไข: จะใช้งานได้ถ้าฉันมีความมุ่งมั่นในพื้นที่อยู่แล้วเช่นถ้าฉันได้ทำแบบเต็มfetchแม้ว่าในกรณีนี้ฉันไม่แน่ใจว่าการใช้งานคืออะไร
Jack O'Connor

2
อันที่จริงดูเหมือนว่ามันจะไม่ทำงานสำหรับฉันอีกต่อไปกับ git 2.0.2 เช่นกัน :(
ไหล

2
git checkout FETCH_HEADจะช่วยให้
lzl124631x

1
วิธีนี้ใช้ไม่ได้กับการดึงข้อมูลแบบตื้น (เช่น--depth=1)!
kingmakerking

16

คุณสามารถดึงข้อมูล repo จากระยะไกลได้ด้วย:

git fetch <repo>

ที่ไหน

  • <repo>สามารถเป็นชื่อ repo ระยะไกล (เช่นorigin) หรือแม้กระทั่ง URL repo ระยะไกล (เช่นhttps://git.foo.com/myrepo.git)

ตัวอย่างเช่น:

git fetch https://git.foo.com/myrepo.git 

หลังจากที่คุณเรียกคืน repos คุณอาจรวมการกระทำที่คุณต้องการ (เนื่องจากคำถามเกี่ยวกับการเรียกคืนหนึ่งคอมมิชชันแทนที่จะรวมคุณอาจใช้ cherry-pick เพื่อเลือกการคอมมิทเดียว):

git merge <commit>
  • <commit> สามารถเป็น SHA1 ที่กระทำได้

ตัวอย่างเช่น:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

หรือ

git merge 0a071603d87e0b89738599c160583a19a6d95545

หากเป็นการกระทำล่าสุดที่คุณต้องการผสานคุณอาจใช้ตัวแปร FETCH_HEAD:

git cherry-pick (or merge) FETCH_HEAD

ต้องมีการตั้งค่าบัญชี Git บนเครื่อง มันไม่ทำงานภายใต้บัญชีทดสอบ คุณมีบางอย่างที่ทำงานภายใต้บัญชีทดสอบหรือไม่
jww

คุณหมายความว่าอะไร ? คุณไม่สามารถเรียก git?
Sérgio

Ummm ดังนั้นคำสั่งจะเป็น git config set uploadpack.allowReachableSHA1InWantอย่างไร
Alexander Mills

2

วิธีนี้ใช้ได้ผลดีที่สุด:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

ชื่อ "temp" สิ่งที่คุณต้องการ ... สาขานี้อาจจะกำพร้าแม้ว่า


เห็นได้ชัดว่าไม่ได้กับรุ่นคอมไพล์รุ่นเก่าเช่น 1.8.x
sorin

1

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

1) สร้างที่เก็บว่างใน local และgit init

2) git remote add origin " url-of-repository "

3) ต้นกำเนิดการดึง git [สิ่งนี้จะไม่ย้ายไฟล์ของคุณไปยังพื้นที่ทำงานในพื้นที่ของคุณเว้นแต่คุณจะรวม]

4) git cherry-pick " Enter-long-commit-hash-that-you-need "

เสร็จสิ้นด้วยวิธีนี้คุณจะมีไฟล์จากการกระทำเฉพาะนั้นในเครื่องของคุณ

ใส่ยาวกระทำแฮช:

คุณสามารถรับสิ่งนี้ได้โดยใช้ -> git log --pretty = oneline



0

หากการกระทำที่ร้องขออยู่ในคำขอดึงของ repo ระยะไกลคุณสามารถรับได้โดย ID:

# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git

# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.