* โดยทั่วไปแล้ว * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


212

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

สมมติว่าฉันต้องการระบุการเปลี่ยนแปลงนี้โดยไม่ซ้ำกัน: https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920

ฉันสามารถใช้อักขระสี่ตัวแรกได้น้อย: https://github.com/wycats/handlebars.js/commit/e629

แต่ฉันรู้สึกว่าจะมีความเสี่ยง แต่ ssuming codebase ที่อาจใช้เวลาสองสามปี - กล่าวว่า - การเปลี่ยนแปลง 30k มีโอกาสที่จะเกิดการชนกันอย่างไรถ้าฉันใช้ตัวอักษร 8 ตัว? 12? มีจำนวนที่ถือว่าโดยทั่วไปยอมรับได้สำหรับสิ่งนี้หรือไม่?


ที่เกี่ยวข้อง: stackoverflow.com/questions/32405922/…
jub0bs

คำตอบ:


230

คำถามนี้ได้รับคำตอบจริงในบทที่ 7 ของหนังสือ Pro Git :

โดยทั่วไปแล้วตัวละครแปดถึงสิบตัวนั้นมีความพิเศษมากกว่าที่จะไม่ซ้ำใครในโครงการ หนึ่งในโครงการ Git ที่ใหญ่ที่สุดคือเคอร์เนล Linux เริ่มที่จะต้องมี 12 ตัวอักษรจาก 40 ตัวที่เป็นไปได้เพื่อคงความเป็นเอกลักษณ์

7 หลักคือค่าเริ่มต้นของ Git สำหรับ SHA สั้น ๆ ดังนั้นจึงเหมาะสำหรับโครงการส่วนใหญ่ ทีมเคอร์เนลได้เพิ่มจำนวนของพวกเขาหลายครั้งดังที่กล่าวไว้เนื่องจากมีความมุ่งมั่นหลายแสน ดังนั้นสำหรับความมุ่งมั่น ~ 30k ของคุณ 8 หรือ 10 หลักควรจะดีอย่างสมบูรณ์


38
โปรดทราบด้วยว่าgitมันค่อนข้างฉลาดเมื่อพูดถึงเรื่องนี้ คุณสามารถตั้งค่าตัวย่อสั้น ๆ พูดถึง 4 และgitจะใช้ 4 หลักสำหรับแฮ็ชได้มากเท่าที่จะทำได้ แต่เปลี่ยนเป็น 5 หรือมากกว่าเมื่อรู้ว่าตัวย่อไม่ซ้ำกัน ...
twalberg

31
อย่างไรก็ตามโปรดทราบว่าแน่นอนว่านี่ใช้ได้เฉพาะกับช่วงเวลาที่ Git พิมพ์ SHA เท่านั้น หากคุณ "บันทึก" ตัวย่อ SHA (พูดในบันทึกอีเมล IM และอื่น ๆ ) และใช้พวกเขาในภายหลังเพื่ออ้างอิงถึงการกระทำพวกเขาอาจไม่ซ้ำกันอีกต่อไป! ในขณะที่ไม่น่าจะมีความยาวปกติเช่น 7-12 ตัวอักษรหากคุณลงไปที่ 4 หรือ 5 และคุณได้รับวัตถุใหม่สองสามหมื่น (หรือกระทำตามบริบท) สิ่งนี้อาจกลับมากัดคุณได้
Nevik Rehnel

140

หมายเหตุ: คุณสามารถขอgit rev-parse --shortSHA1 ที่สั้นที่สุดและมีเอกลักษณ์ได้
ดูที่ " git รับแฮชแบบสั้นจากแฮชปกติ "

git rev-parse --short=4 921103db8259eb9de72f42db8b939895f5651489
92110

อย่างที่คุณเห็นในตัวอย่างของฉัน SHA1 มีความยาว 5 แม้ว่าฉันจะระบุความยาวเป็น 4


สำหรับ repos ขนาดใหญ่ 7 รายการไม่เพียงพอตั้งแต่ปี 2010 และมอบ dce9648โดย Linus Torvalds (git 1.7.4.4, Oct 2010):

ค่าเริ่มต้นของ 7 มาจากการพัฒนาระบบคอมไพล์ค่อนข้างเร็วเมื่อเลขฐานสิบหกเจ็ดจำนวนมาก (ซึ่งครอบคลุมค่าแฮชประมาณ 250+ ล้านค่า)
ย้อนกลับไปตอนนั้นฉันคิดว่าการปรับปรุง 65k เป็นจำนวนมาก (มันเป็นสิ่งที่เรากำลังจะตีใน BK) และการแก้ไขแต่ละครั้งมีแนวโน้มที่จะมีวัตถุใหม่ประมาณ 5-10 ชิ้นดังนั้นวัตถุหนึ่งล้านจึงเป็นจำนวนมาก

(BK = BitKeeper)

วันนี้เคอร์เนลไม่ได้แม้โครงการคอมไพล์ที่ใหญ่ที่สุดและแม้กระทั่งเมล็ดมีประมาณ 220K แก้ไข ( มากใหญ่กว่าต้นไม้ BK เคยเป็น) และเรากำลังเข้าใกล้สองล้านวัตถุ
ณ จุดนี้เลขฐานสิบหกเจ็ดหลักยังคงไม่ซ้ำกันสำหรับพวกเขาจำนวนมาก แต่เมื่อเราพูดถึงเพียงสองคำสั่งของความแตกต่างขนาดระหว่างจำนวนวัตถุและขนาดแฮชจะมีการชนกันในค่าแฮชที่ถูกตัดทอน
มันไม่ได้ใกล้เคียงกับความไม่สมจริงอีกต่อไป - มันเกิดขึ้นตลอดเวลา

เราทั้งสองควรจะเพิ่มขึ้น abbrev เริ่มต้นที่มีขนาดเล็กบวก, และเพิ่มวิธีสำหรับคนที่การตั้งค่าเริ่มต้นของตัวเองต่อโครงการในไฟล์ config คอมไพล์

core.abbrev

ตั้งชื่อวัตถุความยาวเป็นตัวย่อ
หากไม่ได้ระบุคำสั่งจำนวนมากจะย่อไปยัง 7 hexdigits ซึ่งอาจไม่เพียงพอสำหรับชื่อวัตถุที่สั้นที่จะคงความเป็นเอกลักษณ์ในระยะเวลาที่เพียงพอ

environment.c:

int minimum_abbrev = 4, default_abbrev = 7;

หมายเหตุ: เป็นความเห็นด้านล่างโดยmarco.m , core.abbrevLengthถูกเปลี่ยนชื่อcore.abbrevใน Git เดียวกันกับที่ 1.7.4.4 ในการกระทำ a71f09f

เปลี่ยนชื่อcore.abbrevlengthกลับเป็นcore.abbrev

มันสอดคล้องกับ--abbrev=$nตัวเลือกบรรทัดคำสั่งหลังจากทั้งหมด


อีกไม่นาน Linus ได้เพิ่มe6c587c (สำหรับ Git 2.11, Q4 2016):
(ดังที่ได้กล่าวไว้ในคำตอบของMatthieu Moy )

ในวันแรก ๆ เราค่อนข้างจะตัดสินใจย่อชื่อออบเจ็กต์ลงไปที่ 7-hexdigits แต่เมื่อโครงการเติบโตขึ้นเรื่อย ๆ มันก็ยิ่งมีแนวโน้มที่จะเห็นชื่อออบเจ็กต์สั้น ๆ ที่เกิดขึ้นในวันก่อนหน้านี้

ปัจจุบันโครงการเคอร์เนล Linux ต้องการ 11 ถึง 12 hexdigits ในขณะที่ Git เองต้องการ 10 hexdigits เพื่อระบุวัตถุที่พวกเขามีในขณะที่โครงการขนาดเล็กจำนวนมากอาจยังคงดีกับค่าเริ่มต้น 7-hexdigit เดิม ขนาดเดียวไม่เหมาะกับทุกโครงการ

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

ดูกระทำ e6c587c (1 ตุลาคม 2016) โดยLinus Torvalds (torvalds )
ดูกระทำ 7b5b772 , กระทำ 65acfea (1 ตุลาคม 2016) โดยJunio C Hamano (gitster )
(ผสานโดยJunio ​​C Hamano - gitster- in bb188d0 , 03 ต.ค. 2559)

คุณสมบัติใหม่นั้น (การคาดเดาค่าเริ่มต้นที่สมเหตุสมผลสำหรับค่าตัวย่อ SHA1) มีผลโดยตรงกับวิธีที่Git คำนวณหมายเลขรุ่นของตัวเองเพื่อนำออกใช้


3
คำตอบนี้ให้วิธีการตรวจสอบแฮชที่ "สั้นลง" ที่ยาวที่สุดในที่เก็บเดียวคือ: stackoverflow.com/a/32406103/1858225
Kyle Strand

1
ทราบว่าได้รับการเปลี่ยนชื่อเป็นcore.abbrevLength core.abbrev
marco.m

@ marco.m ขอบคุณ ฉันได้แก้ไขคำตอบแล้ว และฉันได้เชื่อมโยงกับ Git ที่บันทึกชื่อใหม่core.abbrevนั้น
VonC

ฉันจะเพิ่มสิ่งนี้เพื่อให้คุณสามารถเรียกใช้git rev-parse --short=10 --verify HEADเพื่อสร้างตัวละคร 10 ตัว เราใช้อยู่git log -1 --format=%hแต่สร้างได้แค่ 7 ตัวเท่านั้นและเราได้รับการชนกัน
grayaii

ขอขอบคุณสำหรับคำอธิบายเอกสาร ( git-scm.com/docs/git-rev-parse ) นั้นเก่า
André Werlang

36

สิ่งนี้เรียกว่าปัญหาวันเกิด

สำหรับความน่าจะเป็นที่น้อยกว่า 1/2 ความน่าจะเป็นของการชนนั้นสามารถประมาณได้เช่น

p ~ = (n 2 ) / (2m)

โดยที่ n คือจำนวนรายการและ m คือจำนวนความเป็นไปได้ของแต่ละรายการ

จำนวนความเป็นไปได้สำหรับสตริงฐานสิบหกคือ 16 cโดยที่ c คือจำนวนอักขระ

ดังนั้นสำหรับ 8 ตัวอักษรและ 30K มุ่งมั่น

30K ~ = 2 15

P ~ = (n 2 ) / (2 เมตร) ~ = ((2 15 ) 2 ) / (2 * 16 8 ) = 2 วันที่ 30 /2 33 = ⅛

เพิ่มขึ้นเป็น 12 อักขระ

P ~ = (n 2 ) / (2 เมตร) ~ = ((2 15 ) 2 ) / (2 * 16 12 ) = 2 วันที่ 30 /2 49 = 2 -19


คำถามที่ฉันพยายามแก้ไขขอขอบคุณ! ตารางความน่าจะเป็นที่เชื่อมโยงกับคำตอบของ @ Messa ก็มีประโยชน์เช่นกัน
Kyle Chadha

ยอดเยี่ยมเราไม่ต้องการอะไรอย่างอื่นนอกจากนี้อธิบายมันไม่เพียง แต่มันคืออะไร แต่ยังมาได้อย่างไร ...
workplaylifecycle

13

คำถามนี้ได้รับคำตอบแล้ว แต่สำหรับใครก็ตามที่มองหาคณิตศาสตร์ที่อยู่เบื้องหลัง - เรียกว่าปัญหาวันเกิด ( Wikipedia )

มันเกี่ยวกับความน่าจะเป็นที่จะมีคน 2 คนขึ้นไปจากกลุ่ม N คนที่จะมีวันคล้ายวันเกิดในปีเดียวกัน ซึ่งคล้ายกับ probabily ของคอมไพล์ 2 (หรือมากกว่า) คอมมิทจากการเก็บข้อมูลที่มี N กระทำทั้งหมดที่มีคำนำหน้าแฮชเดียวกันของความยาว X

ดูที่ตารางความน่าจะเป็น ตัวอย่างเช่นสำหรับสตริง hash hex ที่มีความยาว 8 ความน่าจะเป็นที่จะเกิดการชนสูงถึง 1% เมื่อที่เก็บมีเพียง 9300 ไอเท็ม (คอมไพล์คอมมิท) สำหรับ 110,000 คอมมิชชันความน่าจะเป็นคือ 75% แต่ถ้าคุณมีแฮ็กฐานสิบหกที่มีความยาว 12 ความน่าจะเป็นของการชนใน 100,000 การคอมมิตต่ำกว่า 0.1%


2

Git เวอร์ชั่น 2.11 (หรืออาจ 2.12?) จะมีคุณสมบัติที่ปรับจำนวนอักขระที่ใช้ในตัวระบุสั้น ๆ (เช่นgit log --oneline) ตามขนาดของโครงการ เมื่อคุณใช้ Git เวอร์ชันดังกล่าวคำตอบสำหรับคำถามของคุณคือ "เลือกความยาวใดก็ได้ที่ Git ให้คุณgit log --onelineมันปลอดภัยพอ"

สำหรับรายละเอียดเพิ่มเติมดูการเปลี่ยนค่าเริ่มต้นสำหรับ“ core.abbrev” หรือไม่ การอภิปรายใน Git Rev ข่าวฉบับที่ 20และกระทำbb188d00f7

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