| GITFORMAT-PACK(5) | Git Manual | GITFORMAT-PACK(5) |
نام (NAME)
gitformat-pack - قالب بستهها (pack) در گیت
خلاصه دستور (SYNOPSIS)
$GIT_DIR/objects/pack/pack-.{pack,idx}
$GIT_DIR/objects/pack/pack-.rev
$GIT_DIR/objects/pack/pack-*.mtimes
$GIT_DIR/objects/pack/multi-pack-index
توضیحات (DESCRIPTION)
قالب بسته در گیت (pack format) روشی است که گیت بخش عمده دادههای اصلی مخزن خود را در آن ذخیره میکند. در طول چرخه عمر یک مخزن، اشیاء مجزا (loose objects - در صورت وجود) و بستههای کوچکتر در بسته(های) بزرگتر تجمیع میشوند. نگاه کنید به git-gc(1) و git-pack-objects(1).
قالب بسته همچنین برای انتقال روی شبکه (over-the-wire) نیز استفاده میشود؛ مثلاً نگاه کنید به gitprotocol-v2(5)، و همچنین بخشی از سایر قالبهای کانتینری مانند gitformat-bundle(5) است.
چکسامها و شناسههای اشیاء (CHECKSUMS AND OBJECT IDS)
در مخزنی که از SHA-1 سنتی استفاده میکند، چکسامهای بسته، چکسامهای ایندکس و شناسههای اشیاء (نامهای اشیاء) که در ادامه ذکر شدهاند همگی با استفاده از SHA-1 محاسبه میشوند. به همین ترتیب، در مخازن مبتنی بر SHA-256، این مقادیر با استفاده از SHA-256 محاسبه میگردند.
چکسامهای CRC32 همواره بر روی کل شیء بستهبندیشده محاسبه میشوند، شامل هدر (نوع و طول n-بایتی)؛ نام یا آفست شیء پایه در صورت وجود؛ و کل شیء فشردهشده. الگوریتم CRC32 مورد استفاده، همان الگوریتم zlib است.
فایلهای PACK-*.PACK دارای قالب زیر هستند:
امضای ۴ بایتی:
امضا عبارت است از: {'P', 'A', 'C', 'K'}
شماره نسخه ۴ بایتی (با ترتیب بایت شبکه - network byte order):
گیت در حال حاضر نسخه ۲ یا ۳ را میپذیرد اما
فقط نسخه ۲ را تولید میکند.
تعداد ۴ بایتی اشیاء موجود در بسته (ترتیب بایت شبکه)
ملاحظه: نمیتوان بیش از ۴ گیگابایت نسخه داشت ;) و بیش از ۴ گیگابایت شیء در یک بسته وجود ندارد.
(نمایش غیردلتا - undeltified) نوع و طول n-بایتی (نوع ۳ بیتی، طول (n-1)*7+4 بیتی) دادههای فشردهشده
(نمایش دلتا - deltified)
نوع و طول n-بایتی (نوع ۳ بیتی، طول (n-1)*7+4 بیتی)
نام شیء پایه در صورت OBJ_REF_DELTA یا آفست نسبی منفی
از موقعیت شیء دلتا در بسته در صورتی که این شیء
یک شیء OBJ_OFS_DELTA باشد
دادههای دلتای فشردهشده
ملاحظه: طول هر شیء در یک قالب با طول متغیر کدگذاری میشود و به ۳۲ بیتی یا موارد مشابه محدود نیست.
انواع اشیاء (Object types)
انواع معتبر اشیاء عبارتند از:
نوع ۵ برای توسعه در آینده رزرو شده است. نوع ۰ نامعتبر است.
کدگذاری اشیاء (Object encoding)
برخلاف اشیاء مجزا (loose objects)، اشیاء بستهبندیشده فاقد پیشوندی حاوی نوع، اندازه و یک بایت NUL هستند. این موارد ضروری نیستند زیرا میتوان آنها را از روی نوع و طول n-بایتی که پیشوند دادههاست تشخیص داد و بنابراین از دادههای فشردهشده و دلتا حذف شدهاند.
محاسبه شناسه شیء (object ID) همچنان از این پیشوند با بازسازی آن بر اساس نوع و طول در صورت نیاز استفاده میکند.
کدگذاری اندازه (Size encoding)
این سند از "کدگذاری اندازه" زیر برای اعداد صحیح غیرمنفی استفاده میکند: از هر بایت، هفت بیت کمارزشتر برای تشکیل عدد صحیح نهایی استفاده میشود. تا زمانی که باارزشترین بیت (MSB) برابر با ۱ باشد، این فرآیند ادامه مییابد؛ بایتی که MSB آن ۰ باشد هفت بیت آخر را فراهم میکند. تکههای هفتبیتی به یکدیگر متصل میشوند. مقادیر بعدی دارای ارزش مکانی بالاتری هستند.
این کدگذاری اندازه نباید با "کدگذاری آفست"، که آن نیز در این سند استفاده شده است، اشتباه گرفته شود.
هنگام کدگذاری اندازه یک شیء غیردلتا در یک بسته، اندازه برابر با اندازه شیء خام فشردهنشده است. برای اشیاء دلتا، اندازه برابر با اندازه دلتای فشردهنشده است. نام یا آفست شیء پایه در محاسبه اندازه گنجانده نمیشود.
نمایش دلتا (Deltified representation)
از نظر مفهومی تنها چهار نوع شیء وجود دارد: commit، tree، tag و blob. با این حال برای صرفهجویی در فضا، یک شیء میتواند به صورت یک "دلتا" از یک شیء "پایه" دیگر ذخیره شود. به این نمایشها انواع جدید ofs-delta و ref-delta اختصاص داده شده است که فقط در یک فایل بسته معتبر هستند.
هر دو نوع ofs-delta و ref-delta مقدار "دلتا" را برای اعمال روی شیء دیگر (که شیء پایه نامیده میشود) ذخیره میکنند تا شیء بازسازی شود. تفاوت میان آنها این است که ref-delta مستقیماً نام شیء پایه را کدگذاری میکند. اگر شیء پایه در همان بسته باشد، ofs-delta در عوض آفست شیء پایه در بسته را کدگذاری میکند.
شیء پایه نیز در صورتی که در همان بسته باشد میتواند به صورت دلتا باشد. نوع Ref-delta همچنین میتواند به شیئی خارج از بسته ارجاع دهد (یعنی اصطلاحاً "بسته نازک" یا thin pack). با این حال هنگام ذخیرهسازی روی دیسک، بسته باید مستقل و خودبسنده (self contained) باشد تا از وابستگیهای چرخهای جلوگیری شود.
دادههای دلتا با اندازه شیء پایه و اندازه شیئی که باید بازسازی شود آغاز میشوند. این اندازهها با استفاده از کدگذاری اندازه از بخش بالا کدگذاری میشوند. باقیمانده دادههای دلتا دنبالهای از دستورالعملها برای بازسازی شیء از روی شیء پایه است. اگر شیء پایه به صورت دلتا باشد، ابتدا باید به فرم استاندارد تبدیل شود. هر دستورالعمل دادههای بیشتری را به شیء مقصد اضافه میکند تا کامل شود. تا کنون دو دستورالعمل پشتیبانی میشود: یکی برای کپی کردن یک بازه بایتی از شیء مبدا و دیگری برای درج دادههای جدید تعبیهشده در خود دستورالعمل.
هر دستورالعمل دارای طول متغیر است. نوع دستورالعمل توسط بیت هفتم از اولین بایت تعیین میشود. نمودارهای زیر از قرارداد RFC 1951 (قالب دادههای فشرده Deflate) پیروی میکنند.
دستورالعمل
کپی از شیء
پایه
+----------+---------+---------+---------+---------+-------+-------+-------+ | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 | +----------+---------+---------+---------+---------+-------+-------+-------+
این قالب دستورالعمل برای کپی کردن یک بازه بایتی از شیء مبدا است. این دستور آفست مبدا برای کپی و تعداد بایتها برای کپی را کدگذاری میکند. آفست و اندازه با ترتیب اندیان کوچک (little-endian) هستند.
تمام بایتهای آفست و اندازه اختیاری هستند. این امر برای کاهش اندازه دستورالعمل هنگام کدگذاری آفستها یا اندازههای کوچک است. هفت بیت اول در بایت اول مشخص میکنند کدامیک از هفت بایت بعدی وجود دارند. اگر بیت صفر تنظیم شده باشد، offset1 وجود دارد. اگر بیت یک تنظیم شده باشد offset2 وجود دارد و به همین ترتیب.
توجه داشته باشید که یک دستورالعمل فشردهتر، کدگذاری آفست و اندازه را تغییر نمیدهد. برای مثال، اگر فقط offset2 مانند زیر حذف شود، offset3 همچنان شامل بیتهای ۱۶ تا ۲۳ خواهد بود. این بایت به offset2 تبدیل نمیشود و حتی اگر درست در کنار offset1 قرار گیرد شامل بیتهای ۸ تا ۱۵ نخواهد شد.
+----------+---------+---------+ | 10000101 | offset1 | offset3 | +----------+---------+---------+
در فشردهترین حالت خود، این دستورالعمل تنها یک بایت (0x80) فضا اشغال میکند که در آن هر دو مقدار آفست و اندازه حذف شدهاند و مقادیر پیشفرض آنها صفر خواهد بود. یک استثنای دیگر نیز وجود دارد: اندازه صفر به طور خودکار به 0x10000 تبدیل میشود.
دستورالعمل
افزودن
داده جدید
+----------+============+ | 0xxxxxxx | data | +----------+============+
این دستورالعمل برای ساخت شیء مقصد بدون شیء پایه است. دادههای زیر به شیء مقصد ضمیمه میشوند. هفت بیت اول از اولین بایت اندازه دادهها را به بایت مشخص میکنند. اندازه باید غیرصفر باشد.
دستورالعمل
رزروشده
+----------+============ | 00000000 | +----------+============
این دستورالعمل برای توسعه در آینده رزرو شده است.
فایلهای اصلی PACK-*.IDX (نسخه ۱) دارای قالب زیر هستند:
عدد صحیح ۴ بایتی با ترتیب بایت شبکه، که محل ذخیره شیء در فایل بسته را به صورت آفست از ابتدای فایل ثبت میکند.
یک نام شیء با اندازه مناسب.
یک کپی از چکسام بسته در انتهای فایل بسته متناظر.
چکسام ایندکس از تمام موارد بالا.
Pack Idx file:
-- +--------------------------------+
fanout | fanout[0] = 2 (for example) |-.
table +--------------------------------+ |
| fanout[1] | |
+--------------------------------+ |
| fanout[2] | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| fanout[255] = total objects |---.
-- +--------------------------------+ | |
main | offset | | |
index | object name 00XXXXXXXXXXXXXXXX | | |
table +--------------------------------+ | |
| offset | | |
| object name 00XXXXXXXXXXXXXXXX | | |
+--------------------------------+<+ |
.-| offset | |
| | object name 01XXXXXXXXXXXXXXXX | |
| +--------------------------------+ |
| | offset | |
| | object name 01XXXXXXXXXXXXXXXX | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | offset | |
| | object name FFXXXXXXXXXXXXXXXX | |
--| +--------------------------------+<--+
trailer | | packfile checksum |
| +--------------------------------+
| | idxfile checksum |
| +--------------------------------+
.-------.
|
Pack file entry: <+
packed object header:
1-byte size extension bit (MSB)
type (next 3 bit)
size0 (lower 4-bit)
n-byte sizeN (as long as MSB is set, each 7-bit)
size0..sizeN form 4+7+7+..+7 bit integer, size0
is the least significant part, and sizeN is the
most significant part.
packed object data:
If it is not DELTA, then deflated bytes (the size above
is the size before compression).
If it is REF_DELTA, then
base object name (the size above is the
size of the delta data that follows).
delta data, deflated.
If it is OFS_DELTA, then
n-byte offset (see below) interpreted as a negative
offset from the type-byte of the header of the
ofs-delta entry (the size above is the size of
the delta data that follows).
delta data, deflated.
offset encoding:
n bytes with MSB set in all but the last one.
The offset is then the number constructed by
concatenating the lower 7 bit of each byte, and
for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1))
to the result.
فایلهای PACK-*.IDX نسخه ۲ از بستههای بزرگتر از ۴ گیبیبایت پشتیبانی میکنند و
دارای سازماندهیهای دیگری نیز هستند. آنها دارای قالب زیر میباشند:
یک کپی از چکسام بسته در انتهای فایل بسته متناظر.
چکسام ایندکس از تمام موارد بالا.
فایلهای PACK-*.REV دارای قالب زیر هستند:
چکسام فایل بسته متناظر، و
یک چکسام از تمام موارد بالا.
تمام اعداد ۴ بایتی با ترتیب شبکه هستند.
فایلهای PACK-*.MTIMES دارای قالب زیر هستند:
تمام اعداد ۴ بایتی با ترتیب بایت شبکه هستند.
فایلهای MULTI-PACK-INDEX (MIDX) دارای قالب زیر هستند:
فایلهای multi-pack-index به چندین فایل بسته و شیء مجزا ارجاع میدهند.
به منظور امکانپذیر ساختن افزونههایی که دادههای اضافی را به MIDX اضافه میکنند، بدنه را به "تکهها" (chunks) سازماندهی میکنیم و یک جدول جستجو در ابتدای بدنه ارائه میدهیم. هدر شامل مقادیر طولی معینی است، مانند تعداد بستهها، تعداد فایلهای MIDX پایه، طول و انواع هش.
تمام اعداد ۴ بایتی با ترتیب شبکه هستند.
هدر (HEADER):
امضای ۴ بایتی:
امضا عبارت است از: {'M', 'I', 'D', 'X'}
شماره نسخه ۱ بایتی:
گیت نسخهای را مینویسد که با گزینه پیکربندی "midx.version"
مشخص شده است، که به طور پیشفرض برابر با ۲ است. این سیستم
هر دو نسخه ۱ و ۲ را تشخیص میدهد.
نسخه شناسه شیء ۱ بایتی (Object Id Version):
ما طول شناسههای اشیاء (OIDs) را از روی این مقدار استنتاج میکنیم:
1 => SHA-1
2 => SHA-256
اگر نوع هش با الگوریتم هش مخزن مطابقت نداشته باشد،
فایل multi-pack-index باید نادیده گرفته شده و هشداری
به کاربر نمایش داده شود.
تعداد "تکهها" به صورت ۱ بایتی
تعداد فایلهای چندبستهای پایه به صورت ۱ بایتی:
این مقدار در حال حاضر همواره صفر است.
تعداد فایلهای بسته به صورت ۴ بایتی
جدول جستجوی تکه (CHUNK LOOKUP):
مقدار (C + 1) * 12 بایت فراهمکننده آفستهای تکهها:
اولین ۴ بایت شناسه تکه را توصیف میکند. مقدار ۰ یک برچسب پایاندهنده است.
۸ بایت دیگر، آفست در فایل جاری را برای شروع تکه ارائه میدهند.
(تکهها با ترتیب ترتیبی در فایل ارائه میشوند، بنابراین در صورت نیاز
میتوانید طول را با استفاده از موقعیت تکه بعدی استنتاج کنید.)
جدول CHUNK LOOKUP با جدول فهرست مطالب در قالب فایلی مبتنی بر تکه مطابقت دارد؛ نگاه کنید به linkgit:gitformat-chunk[5].
دادههای باقیمانده در بدنه هر بار به صورت یک تکه توصیف میشوند و این تکهها ممکن است به هر ترتیبی ارائه گردند. تکهها اجباری هستند مگر خلاف آن مشخص شده باشد.
دادههای تکه (CHUNK DATA):
نامهای فایلهای بسته (شناسه: {'P', 'N', 'A', 'M'})
نامهای فایلهای بسته را به عنوان دنبالهای از رشتههای پایانیافته
با NUL ذخیره میکند. هیچ فاصله پرکننده اضافی میان نامهای فایل
وجود ندارد و آنها به ترتیب الفبایی فهرست شدهاند. خود تکه
در انتها با بین ۰ تا ۳ بایت NUL پر میشود تا اندازه
تکه مضربی از ۴ بایت شود. نسخههای ۱ MIDX ملزم هستند
بستههای خود را به ترتیب الفبایی فهرست کنند، اما نسخههای ۲ MIDX میتوانند
بستههای خود را به هر ترتیب دلخواهی فهرست نمایند.
فایلهای بسته نقشهبیتی (شناسه: {'B', 'T', 'M', 'P'})
جدولی از دو عدد صحیح بدون علامت ۴ بایتی با ترتیب شبکه ذخیره میکند.
هر مدخل جدول متناظر با یک بسته واحد است (به ترتیبی که
در بالا در تکه `PNAM` ظاهر شدهاند). مقادیر برای هر مدخل جدول
به شرح زیر است:
- اولین موقعیت بیتی (در ترتیب شبهبسته، در ادامه را ببینید) که
حاوی شیئی از آن بسته باشد.
- تعداد بیتهایی که اشیاء آنها از آن بسته انتخاب شدهاند.
توزیع OID (شناسه: {'O', 'I', 'D', 'F'})
مدخل i-ام، F[i]، تعداد OIDهایی را که بایت اول آنها
حداکثر i است ذخیره میکند. بنابراین F[255] تعداد کل
اشیاء را ذخیره میکند.
جستجوی OID (شناسه: {'O', 'I', 'D', 'L'})
شناسههای OID برای تمام اشیاء در MIDX به ترتیب
الفبایی در این تکه ذخیره میشوند.
آفستهای اشیاء (شناسه: {'O', 'O', 'F', 'F'})
دو مقدار ۴ بایتی را برای هر شیء ذخیره میکند.
۱: شناسه pack-int-id برای بستهای که این شیء را ذخیره میکند.
۲: آفست در داخل بسته.
اگر تمام آفستها کمتر از 2^32 باشند، تکه آفست بزرگ
وجود نخواهد داشت و آفستها همانند IDX v1 ذخیره میشوند.
اگر حداقل یک مقدار آفست بزرگتر از 2^32-1 وجود داشته باشد،
تکه آفست بزرگ باید وجود داشته باشد و آفستهای بزرگتر از
2^31-1 باید در عوض در آن ذخیره شوند. اگر تکه آفست بزرگ
وجود داشته باشد و بیت ۳۱ام فعال باشد، حذف آن بیت ردیفی
را در آفستهای بزرگ آشکار میکند که حاوی آفست ۸ بایتی
این شیء است.
[اختیاری] آفستهای بزرگ اشیاء (شناسه: {'L', 'O', 'F', 'F'})
آفستهای ۸ بایتی در فایلهای بسته بزرگ.
[اختیاری] ترتیب بسته نقشهبیت (شناسه: {'R', 'I', 'D', 'X'})
فهرستی از موقعیتهای MIDX (یک موقعیت به ازای هر شیء در MIDX، در مجموع num_objects،
هر کدام یک عدد صحیح بدون علامت ۴ بایتی با ترتیب بایت شبکه)، مرتبشده
بر اساس موقعیتهای نسبی نقشهبیت/شبهبسته آنها.
تریلر (TRAILER):
چکسام ایندکس از محتویات بالا.
ایندکسهای معکوس چندبستهای (MULTI-PACK-INDEX REVERSE INDEXES)
مشابه ایندکس معکوس مبتنی بر بسته، از ایندکس چندبستهای (multi-pack index) نیز میتوان برای تولید یک ایندکس معکوس استفاده کرد.
به جای نگاشت میان آفست، موقعیت بسته و موقعیت ایندکس، این ایندکس معکوس میان موقعیت یک شیء در MIDX و موقعیت آن شیء در یک شبهبسته (pseudo-pack) که MIDX توصیف میکند نگاشت انجام میدهد (یعنی مدخل i-ام از ایندکس معکوس چندبستهای، موقعیت MIDX مربوط به شیء i-ام را با ترتیب شبهبسته نگهداری میکند).
برای روشن شدن تفاوت میان این ترتیبها، یک نقشهبیت دسترسیپذیری چندبستهای را در نظر بگیرید (که هنوز وجود ندارد، اما چیزی است که ما در اینجا در جهت آن حرکت میکنیم). هر بیت باید متناظر با یک شیء در MIDX باشد، و بنابراین به یک نگاشت کارآمد از موقعیت بیت به موقعیت MIDX نیاز داریم.
یک راهحل این است که اجازه دهیم بیتها همان موقعیت را در ایندکس مرتبشده بر اساس oid ذخیرهشده توسط MIDX اشغال کنند. اما چون شناسههای oid عملاً تصادفی هستند، نقشهبیتهای دسترسیپذیری حاصل فاقد محلی بودن داده (locality) خواهند بود و بنابراین فشردهسازی بسیار ضعیفی خواهند داشت. (به همین دلیل است که نقشهبیتهای تکبستهای برای همین منظور از ترتیب بسته استفاده میکنند، نه از ترتیب .idx).
بنابراین مایل هستیم ترتیبی برای کل MIDX بر پایه ترتیب بسته تعریف کنیم که محلی بودن بسیار بهتری دارد (و در نتیجه کارآمدتر فشرده میشود). میتوانیم یک شبهبسته را متصور شویم که از اتصال تمام بستههای موجود در MIDX به وجود آمده است. به عنوان مثال، اگر یک MIDX با سه بسته (a، b، c) داشته باشیم که به ترتیب دارای ۱۰، ۱۵ و ۲۰ شیء باشند، میتوانیم ترتیبی از اشیاء را به این صورت تصور کنیم:
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
که در آن ترتیب بستهها توسط فهرست بستههای MIDX تعریف میشود، و سپس ترتیب اشیاء در هر بسته با ترتیب موجود در فایل بسته واقعی یکسان است.
با داشتن فهرست بستهها و تعداد اشیاء آنها، میتوانید این ترتیب شبهبسته را به سادگی بازسازی کنید (برای نمونه، شیء در موقعیت ۲۷ باید (c,1) باشد زیرا بستههای "a" و "b" ۲۵ جایگاه را اشغال کردهاند). اما نکتهای وجود دارد: اشیاء ممکن است میان بستهها تکراری باشند، که در این صورت MIDX فقط یک اشارهگر به شیء را ذخیره میکند (و بنابراین ما فقط یک جایگاه در نقشهبیت میخواهیم).
فراخوانها میتوانند با خواندن اشیاء به ترتیب موقعیت بیتی، موارد تکراری را خودشان مدیریت کنند، اما این کار با تعداد اشیاء نسبت خطی دارد و برای جستجوهای معمول در نقشهبیت بیش از حد پرهزینه است. ساخت یک ایندکس معکوس این مشکل را حل میکند، چرا که ایندکس معکوس وارون منطقی ایندکس است و آن ایندکس از قبل موارد تکراری را حذف کرده است. اما ساخت ایندکس معکوس به صورت بلادرنگ و پویا میتواند پرهزینه باشد. از آنجا که ما از قبل یک قالب روی دیسک برای ایندکسهای معکوس مبتنی بر بسته داریم، اجازه دهید از آن برای شبهبسته MIDX نیز مجدداً استفاده کنیم.
اشیاء موجود در MIDX به منظور اتصال در شبهبسته به صورت زیر مرتب میشوند. فرض کنید pack(o) بستهای را برمیگرداند که o توسط MIDX از آن انتخاب شده است، و ترتیبی از بستهها را بر اساس شناسه عددی آنها (به شکلی که توسط MIDX ذخیره شده است) تعریف کنید. فرض کنید offset(o) آفست شیء o را درون pack(o) برمیگرداند. سپس o1 و o2 را به صورت زیر مقایسه کنید:
(این جزئیاتی است که به نقشهبیت MIDX اجازه میدهد مشخص کند کدام بسته باید توسط مکانیزم بازاستفاده بسته استفاده شود، زیرا میتواند از MIDX بستهای را که شامل شیء در موقعیت بیت ۰ است درخواست کند).
به طور خلاصه، شبهبسته یک MIDX اتصال بدون تکرار اشیاء در بستههای ذخیرهشده توسط MIDX است که با ترتیب بسته چیده شدهاند، و بستهها با ترتیب MIDX مرتب شدهاند (به طوری که بسته ترجیحدادهشده در ابتدا میآید).
ایندکس معکوس MIDX در تکه اختیاری RIDX درون خود MIDX ذخیره میشود.
تکه BTMP (BTMP chunk)
تکه فایلهای بسته نقشهبیتی (BTMP) اطلاعات اضافی را درباره اشیاء در نقشهبیت دسترسیپذیری ایندکس چندبستهای کدگذاری میکند. به یاد داشته باشید که اشیاء موجود در MIDX با ترتیب "شبهبسته" (بالا را ببینید) برای نقشهبیتهای دسترسیپذیری چیده شدهاند.
بر اساس مثال بالا، فرض کنید بستههای "a"، "b" و "c" را به ترتیب با ۱۰، ۱۵ و ۲۰ شیء داریم. در ترتیب شبهبسته، این اشیاء به صورت زیر چیده میشوند:
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
هنگام کار با نقشهبیتهای تکبستهای (یا به طور معادل، نقشهبیتهای دسترسیپذیری چندبستهای با یک بسته ترجیحدادهشده)، دستور git-pack-objects(1) بازاستفاده «عینبهعین» (verbatim) را انجام میدهد و تلاش میکند تکههایی از فایل بسته نقشهبیتی یا ترجیحدادهشده را به جای افزودن اشیاء به فهرست بستهبندی، مجدداً استفاده کند.
هنگامی که تکهای از بایتها از یک بسته موجود مجدداً استفاده میشود، نیازی نیست اشیاء موجود در آن به فهرست بستهبندی اضافه شوند، که این امر در حافظه و زمان پردازنده صرفهجویی میکند. اما یک تکه از یک فایل بسته موجود تنها زمانی میتواند مجدداً استفاده شود که شرایط زیر برقرار باشد:
تکه BTMP اطلاعات لازم را برای پیادهسازی بازاستفاده چندبستهای بر روی مجموعهای از فایلهای بسته همانطور که در بالا شرح داده شد کدگذاری میکند. به طور خاص، تکه BTMP سه بخش اطلاعاتی (همگی اعداد صحیح بدون علامت ۳۲ بیتی با ترتیب بایت شبکه) را برای هر فایل بسته p که در MIDX ذخیره شده است به شرح زیر کدگذاری میکند:
bitmap_pos
bitmap_nr
برای مثال، تکه BTMP متناظر با مثال بالا (با بستههای «a»، «b» و «c») به این صورت خواهد بود:
| bitmap_pos | bitmap_nr | |
| packfile “a” | 0 | 10 |
| packfile “b” | 10 | 15 |
| packfile “c” | 25 | 20 |
با وجود این اطلاعات، میتوانیم با هر فایل بسته به عنوان بستهای با قابلیت بازاستفاده جداگانه به همان شیوهای رفتار کنیم که پیش از پیادهسازی تکه BTMP برای بازاستفاده عینبهعین بسته روی بستههای جداگانه انجام میشد.
بستههای باطله (CRUFT PACKS)
قابلیت بستههای باطله (cruft packs) جایگزینی برای مکانیزم سنتی گیت در حذف اشیاء غیرقابلدسترس ارائه میدهد. این سند مروری بر مکانیزم هرس (pruning) گیت ارائه کرده و توضیح میدهد که چگونه میتوان از یک بسته باطله به جای آن برای انجام همین کار استفاده کرد.
پیشزمینه (Background)
برای حذف اشیاء غیرقابلدسترس از مخزن، گیت دستور git repack -Ad را ارائه میدهد (نگاه کنید به git-repack(1)). به نقل از مستندات:
[...] اشیاء غیرقابلدسترس در یک بسته قبلی، به جای باقی ماندن در بسته قدیمی، به اشیاء مجزا و بازشده تبدیل میشوند. [...] اشیاء مجزای غیرقابلدسترس بر اساس قواعد انقضای معمول در اجرای بعدی 'git gc' هرس خواهند شد.
اشیاء غیرقابلدسترس بلافاصله حذف نمیشوند، زیرا این کار ممکن است با یک ارسال داده (push) ورودی که ممکن است به شیئی در حال حذف ارجاع دهد، تداخل زمانی (race) پیدا کند. در عوض، آن اشیاء غیرقابلدسترس به عنوان اشیاء مجزا ذخیره میشوند و تا زمانی که سن آنها از پنجره انقضا بگذرد به همان صورت باقی میمانند؛ در آن زمان توسط git-prune(1) حذف میشوند.
گیت باید این اشیاء غیرقابلدسترس را به صورت مجزا ذخیره کند تا بتواند زمانهای mtime اختصاصی هر شیء را ردیابی نماید. اگر این اشیاء غیرقابلدسترس در یک بسته بزرگ نوشته میشدند، آنگاه چه با تازهسازی آن بسته (به دلیل بازنویسی یک شیء درون آن) و چه با ایجاد یک بسته جدید از اشیاء غیرقابلدسترس، مقدار mtime بسته بهروزرسانی میشد و اشیاء درون آن هرگز از پنجره انقضا خارج نمیشدند. در عوض، اشیاء به صورت مجزا نگهداری میشوند تا زمان mtime تکتک اشیاء ردیابی شود و از وضعیتی که در آن همه اشیاء باطله به طور همزمان تازهسازی میشوند جلوگیری گردد.
این امر میتواند به شرایط نامطلوبی منجر شود؛ به ویژه زمانی که یک مخزن شامل تعداد زیادی شیء غیرقابلدسترس است که هنوز دوره مهلت آنها به پایان نرسیده است. داشتن دایرکتوریهای بزرگ در بخشهای مختلف .git/objects میتواند موجب افت کارایی در مخزن شود. علاوه بر این، در صورت وجود اشیاء غیرقابلدسترس به تعداد کافی، این وضعیت میتواند به اتمام inodeها (inode starvation) منجر شده و عملکرد کل سیستم را تضعیف کند. از آنجا که هرگز نمیتوانیم آن اشیاء را بستهبندی کنیم، این مخازن اغلب حجم زیادی از فضای دیسک را اشغال میکنند، زیرا ما فقط میتوانیم آنها را با zlib فشرده سازیم اما امکان ذخیره آنها در زنجیرههای دلتا وجود ندارد.
بستههای باطله (Cruft packs)
یک بسته باطله با گنجاندن مقادیر mtime به ازای هر شیء در یک فایل جداگانه در کنار یک بسته واحد حاوی همه اشیاء مجزا، نیاز به ذخیره اشیاء غیرقابلدسترس در حالت مجزا را از بین میبرد.
یک بسته باطله توسط دستور git repack --cruft هنگام تولید یک بسته جدید نوشته میشود (گزینه --cruft در git-pack-objects(1)). توجه داشته باشید که git repack --cruft یک بستهبندی مجدد کلاسیک همهدریکی (all-into-one) است، به این معنی که همهچیز در بسته حاصل قابلدسترس است و هر چیز دیگری غیرقابلدسترس تلقی میشود. پس از نوشتن، گزینه --cruft به دستور git repack اعلام میکند که بسته دیگری تولید کند که فقط شامل اشیائی باشد که در مرحله قبل بستهبندی نشدهاند (که معادل بستهبندی همه اشیاء غیرقابلدسترس در کنار یکدیگر است). این فرآیند به صورت زیر پیش میرود:
این حالت هنگامی که به git-repack(1) دستور نوشتن یک بسته باطله داده شود، به صورت داخلی فراخوانی میشود. نکته اساسی این است که مجموعه بستههای نگهداریشده در حافظه (in-core kept packs) دقیقاً همان مجموعهای از بستهها هستند که توسط repack حذف نخواهند شد؛ به عبارت دیگر، آنها حاوی تمام اشیاء قابلدسترس مخزن هستند.
هنگامی که یک مخزن از قبل دارای یک بسته باطله باشد، دستور git repack --cruft معمولاً فقط اشیاء را به آن اضافه میکند. یک استثنا بر این قاعده زمانی است که به git repack گزینه --cruft-expiration داده شود، که به بسته باطله تولیدشده امکان میدهد به جای انتظار برای انقضای بعدی اشیاء توسط git-gc(1)، اشیاء منقضیشده را نادیده بگیرد و حذف کند.
به طور معمول این git-gc(1) است که مسئول حذف اشیاء غیرقابلدسترس منقضیشده میباشد.
روشهای جایگزین (Alternatives)
جایگزینهای قابلتوجه برای این طرح عبارتند از:
درباره مکان دادههای mtime، یک فایل کمکی جدید متصل به بسته انتخاب شد تا از پیچیده شدن قالب .idx جلوگیری شود. اگر قالب .idx روزی پشتیبانی از تکههای اختیاری داده را به دست آورد، ادغام قالب .mtimes در خود فایل .idx ممکن است منطقی باشد.
گیت (GIT)
بخشی از مجموعه git(1)
| 2026-06-29 | Git 2.55.0 |