ฉันทำการทดลองเพื่อค้นหาว่า Git จะทำงานอย่างไรในกรณีนี้ นี่คือกับรุ่น 2.7.9 ~ rc0 + next.20151210 (รุ่นเดเบียน) ฉันเพียงแค่ลดขนาดแฮชจาก 160 บิตเป็น 4 บิตโดยใช้ diff และ git ที่สร้างใหม่:
--- git-2.7.0~rc0+next.20151210.orig/block-sha1/sha1.c
+++ git-2.7.0~rc0+next.20151210/block-sha1/sha1.c
@@ -246,6 +246,8 @@ void blk_SHA1_Final(unsigned char hashou
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
- for (i = 0; i < 5; i++)
- put_be32(hashout + i * 4, ctx->H[i]);
+ for (i = 0; i < 1; i++)
+ put_be32(hashout + i * 4, (ctx->H[i] & 0xf000000));
+ for (i = 1; i < 5; i++)
+ put_be32(hashout + i * 4, 0);
}
จากนั้นฉันก็ลงมือทำบางอย่างและสังเกตสิ่งต่อไปนี้
- หากหยดนั้นมีแฮชเดียวกันอยู่แล้วคุณจะไม่ได้รับคำเตือนใด ๆ เลย ทุกอย่างดูเหมือนจะโอเค แต่เมื่อคุณกดโคลนนิ่งบางคนหรือเปลี่ยนกลับคุณจะสูญเสียเวอร์ชันล่าสุด (ตามที่อธิบายไว้ด้านบน)
- หากวัตถุต้นไม้มีอยู่แล้วและคุณสร้างหยดที่มีแฮชเดียวกัน: ทุกอย่างดูเหมือนจะเป็นเรื่องปกติจนกว่าคุณจะพยายามที่จะผลักดันหรือบางคนโคลนที่เก็บของคุณ จากนั้นคุณจะเห็นว่า repo เสียหาย
- หากมีวัตถุกระทำอยู่แล้วและคุณสร้างหยดที่มีแฮชเดียวกันนั่นคือ # 2 - เสียหาย
- หากมี Blob อยู่แล้วและคุณสร้างวัตถุที่มีแฮชเดียวกันมันจะล้มเหลวเมื่อทำการอัพเดท "ref"
- หากมีหยดอยู่แล้วและคุณสร้างวัตถุต้นไม้ด้วยแฮชเดียวกัน มันจะล้มเหลวเมื่อสร้างความมุ่งมั่น
- หากวัตถุต้นไม้มีอยู่แล้วและคุณทำการกระทำวัตถุที่มีแฮชเดียวกันวัตถุนั้นจะล้มเหลวเมื่อทำการอัพเดท "ref"
- หากวัตถุต้นไม้มีอยู่แล้วและคุณสร้างวัตถุต้นไม้ที่มีแฮชเดียวกันทุกอย่างจะดูโอเค แต่เมื่อคุณส่งมอบพื้นที่เก็บข้อมูลทั้งหมดจะอ้างอิงต้นไม้ที่ไม่ถูกต้อง
- หากมีวัตถุกระทำอยู่แล้วและคุณสร้างวัตถุส่งสารที่มีแฮชเดียวกันทุกอย่างจะดูโอเค แต่เมื่อคุณคอมมิชชันคอมมิทจะไม่ถูกสร้างขึ้นและพอยน์เตอร์ HEAD จะถูกย้ายไปที่คอมมิชชันเก่า
- หากมีวัตถุกระทำอยู่แล้วและคุณสร้างวัตถุต้นไม้ที่มีแฮชเดียวกันวัตถุนั้นจะล้มเหลวเมื่อสร้างการกระทำ
สำหรับ # 2 คุณจะได้รับข้อผิดพลาดเช่นนี้เมื่อคุณเรียกใช้ "git push":
error: object 0400000000000000000000000000000000000000 is a tree, not a blob
fatal: bad blob object
error: failed to push some refs to origin
หรือ:
error: unable to read sha1 file of file.txt (0400000000000000000000000000000000000000)
หากคุณลบไฟล์แล้วเรียกใช้ "git checkout file.txt"
สำหรับ # 4 และ # 6 โดยทั่วไปคุณจะได้รับข้อผิดพลาดดังนี้:
error: Trying to write non-commit object
f000000000000000000000000000000000000000 to branch refs/heads/master
fatal: cannot update HEAD ref
เมื่อใช้งาน "git commit" ในกรณีนี้คุณสามารถพิมพ์ "git commit" อีกครั้งเนื่องจากจะสร้างแฮชใหม่ (เนื่องจากการประทับเวลาที่เปลี่ยนแปลง)
สำหรับ # 5 และ # 9 คุณจะได้รับข้อผิดพลาดดังนี้:
fatal: 1000000000000000000000000000000000000000 is not a valid 'tree' object
เมื่อใช้งาน "git commit"
หากมีคนพยายามโคลนที่เก็บข้อมูลที่เสียหายของคุณพวกเขามักจะเห็นสิ่งต่อไปนี้:
git clone (one repo with collided blob,
d000000000000000000000000000000000000000 is commit,
f000000000000000000000000000000000000000 is tree)
Cloning into 'clonedversion'...
done.
error: unable to read sha1 file of s (d000000000000000000000000000000000000000)
error: unable to read sha1 file of tullebukk
(f000000000000000000000000000000000000000)
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry the checkout with 'git checkout -f HEAD'
สิ่งที่ "กังวล" คือในสองกรณี (2,3) พื้นที่เก็บข้อมูลเสียหายโดยไม่มีคำเตือนใด ๆ และใน 3 กรณี (1,7,8) ทุกอย่างดูโอเค แต่เนื้อหาที่เก็บแตกต่างจากที่คุณคาดหวัง เป็น. คนที่โคลนหรือดึงจะมีเนื้อหาที่แตกต่างจากสิ่งที่คุณมี เคส 4,5,6 และ 9 ใช้ได้เนื่องจากจะหยุดโดยมีข้อผิดพลาด ฉันคิดว่ามันจะดีกว่าถ้ามันล้มเหลวด้วยข้อผิดพลาดอย่างน้อยในทุกกรณี