Git ทำอะไรจริง ๆ เมื่อมันบอกว่ามันคือ“ การแก้ไขเดลตา”


187

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



1
ดูเพิ่มเติมที่ Git 2.20 (Q4 2018) และหมู่เกาะเดลต้าเพิ่มเติม: stackoverflow.com/a/52458712/6309
VonC

คำตอบ:


54

Git ใช้การเข้ารหัสเดลต้าเพื่อเก็บวัตถุบางอย่างใน packfiles แต่คุณไม่ต้องการให้มีการเล่นการเปลี่ยนแปลงทุกครั้งเดียวที่เคยในไฟล์ที่กำหนดเพื่อให้ได้รับรุ่นปัจจุบันดังนั้น Git นอกจากนี้ยังมีภาพรวมเป็นครั้งคราวของเนื้อหาของไฟล์ที่เก็บไว้ได้เป็นอย่างดี "การแก้ไขเดลตา" เป็นขั้นตอนที่เกี่ยวข้องกับการทำให้แน่ใจว่าทั้งหมดนั้นยังคงที่

นี่คือบทจากส่วน "Git Internals" ของหนังสือ Pro Git ซึ่งมีให้ทางออนไลน์ซึ่งพูดถึงเรื่องนี้


80
คำตอบนี้ไม่ถูกต้อง ดูเหมือนจะอธิบายว่า Mercurial ทำงานอย่างไรไม่ใช่ Git กำลังจะเกิดขึ้นใน Google เพื่อค้นหาปัญหานี้ดังนั้นฉันรู้สึกว่าจำเป็นต้องตอบกลับ Git ไม่ได้จัดเก็บความแตกต่างระหว่างการกระทำในฐานะเดลต้า Git เป็นร้าน "วัตถุทั้งหมด" ดังนั้น Git จึงไม่จำเป็นต้อง "สแนปชอต" เพื่อแสดงไฟล์ใด ๆ เนื่องจากประวัติไฟล์ไม่จำเป็นต้องถูกสร้างขึ้นใหม่จากเดลตา นั่นคือวิธีที่ Mercurial ทำงาน
nexus บอกว่า

12
ที่เดียวที่มีการเข้ารหัสเดลต้ามาลงเล่นอยู่ในไฟล์แพ็คซึ่งเป็นการบีบอัดและโอนอย่างเคร่งครัด - มันไม่ได้เปลี่ยนแปลงวิธีที่ Git "เห็น" โลก ( kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/ ...... ) โปรดดูคำตอบของ araqnid ด้านล่างเพื่อการตอบสนองที่ถูกต้อง
nexus บอกว่า

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

2
คำตอบของคุณยังไม่ถูกต้อง "Git ยังมีสแนปชอตของเนื้อหาไฟล์เป็นระยะ ๆ เช่นกัน" - ไม่ถูกต้อง "'การแก้ไขเดลตา' เป็นขั้นตอนที่เกี่ยวข้องกับการทำให้แน่ใจว่าทั้งหมดนั้นยังคงเดิม - ที่ไม่ถูกต้องการตอบสนองของ araqnid ด้านล่างนั้นถูกต้อง
nexus บอกว่า

1
ตามที่อธิบายไว้ในบทที่กล่าวถึงข้างต้น Git เก็บเนื้อหาไฟล์แบบเต็มของเวอร์ชั่นล่าสุดเสมอ เวอร์ชันก่อนหน้าจะถูกจัดเก็บเป็นไฟล์ที่มีการเข้ารหัสเดลต้าเมื่อเป็นไฟล์ "หลวม" (โดยการโทรgit gcหรือเมื่อใดก็ตามที่ Git กำหนดว่าจำเป็น) Git จะบีบอัดไฟล์ "หลวม" ทั้งหมดลงใน packfile เพื่อประหยัดพื้นที่และไฟล์ดัชนีลงใน packfile นั้นจะถูกสร้างขึ้น ดังนั้น zlib จะบีบอัดด้วยอัลกอริทึมเดลต้าของตัวเอง แต่ Git ใช้การเข้ารหัสเดลต้าเพื่อเก็บเวอร์ชันก่อนหน้า เนื่องจากการเข้าถึงที่พบบ่อยและบ่อยที่สุดคือเวอร์ชันล่าสุดซึ่งจัดเก็บเป็นสแน็ปช็อต
BrionS

118

ขั้นตอนgit cloneคือ:

  1. รับไฟล์ "แพ็ค" ของวัตถุทั้งหมดในฐานข้อมูล repo
  2. สร้างไฟล์ดัชนีสำหรับแพ็คที่ได้รับ
  3. ตรวจสอบการแก้ไขส่วนหัว (สำหรับ repo ที่ไม่เปลือย)

"Resolving deltas" เป็นข้อความที่แสดงสำหรับขั้นตอนที่สองการสร้างดัชนีไฟล์แพ็ค ("git index-pack")

ไฟล์แพ็คไม่มีรหัสวัตถุจริงในนั้นมีเพียงเนื้อหาของวัตถุ ดังนั้นในการพิจารณาว่า ID วัตถุคืออะไร git ต้องทำการแตก + SHA1 ของแต่ละวัตถุในแพ็คเพื่อสร้าง ID ของวัตถุซึ่งจะถูกเขียนลงในไฟล์ดัชนี

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

โดยสรุปขั้นตอน "การแก้ไขเดลตา" เกี่ยวข้องกับการคลายการบีบอัดและการตรวจสอบฐานข้อมูล repo ทั้งหมดซึ่งไม่น่าแปลกใจใช้เวลาค่อนข้างนาน การคลายและคำนวณ SHA1 นั้นน่าจะใช้เวลามากกว่าการใช้คำสั่ง delta

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


7
สามารถขนานกันได้ไหม
brooksbp

การบีบอัดเดลต้านี้มากกว่าการเก็บวัตถุหลายรายการในสตรีมข้อมูล zlib หนึ่งรายการหรือไม่
fuz

1
@FUZxxl ใช่มันใช้วิธีเช่น diff หรือ xdelta ที่จะเปรียบเทียบสอง blobs และผลิตแก้ไขสคริปต์
araqnid

@ Brooksbp: มีข้อ จำกัด เท่านั้น เนื่องจากวัตถุที่มี id 103fa49 อาจต้องการ df85b51 ที่จะถอดรหัส แต่เมื่อคุณได้รับ 103fa49, df85b51 ก็ยังไม่อยู่ที่นั่น (ไฟล์แพ็คถูกสั่งโดยแฮช sha1 อย่างเคร่งครัด) ดังนั้นสำหรับทุกสิ่งที่อ้างอิงเฉพาะสิ่งที่มีอยู่แล้วสิ่งต่างๆนั้นง่าย แต่สำหรับทุกสิ่งคุณจะต้องรอจนกว่าจะได้รับ และการบีบอัดเดลตานี้สามารถซ้อนกันได้ดังนั้น 103fa49 อาจต้องการ 4e9ba42 ซึ่งในทางกลับกันจำเป็นต้องมี 29ad945 ซึ่งในทางกลับกันต้องการ c9e645a ... คุณจะได้ภาพ [ใช่ฉันสังเกตเห็นว่า> 4 ปี;)]
Bodo Thiesen

2
@ Brooksbp: กลายเป็นว่าฉันผิดไฟล์แพ็คไม่จำเป็นต้องเรียงลำดับโดยแฮช sha1 นอกจากนี้เมื่อเขียน git เขียนวัตถุที่ต้องการก่อนวัตถุที่ต้องการวัตถุนั้น ดังนั้นจริงๆแล้วคุณควรจะสามารถขนานกันได้ ข้อเสียเดียวที่ยังคงอยู่: เนื่องจากคุณไม่ทราบว่าจะต้องใช้วัตถุใดในภายหลังคุณจะต้องสร้างบางครั้งซ้ำแล้วซ้ำอีก ดูที่นี่: kernel.org/pub/software/scm/git/docs/technical/ …
Bodo Thiesen

4

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


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