گیت ۲.۵۵ منتشر شد
پروژهٔ متنباز گیت بهتازگی نسخهٔ ۲.۵۵ را با ویژگیهای جدید و رفع اشکالاتی از بیش از ۱۰۰ مشارکتکننده، که ۳۳ نفر از آنها تازهوارد هستند، منتشر کرده است. در این مقاله، مهمترین تغییرات و قابلیتهای این نسخه را بررسی میکنیم.

بازبستهبندی با نمایههای چندبستهای افزایشی
گیت محتویات مخزن شما را بهصورت شیءهای جداگانه ذخیره میکند: کامیتها، درختها و بلاپها. آن اشیاء معمولاً در بستهفایلها زندگی میکنند، که مجموعههای فشردهای از اشیاء هستند. هر بستهفایل یک نمایهٔ بسته متناظر دارد که به گیت امکان میدهد هر شیء را بهسرعت درون بسته پیدا کند. اما مخازن بزرگ معمولاً فقط یک بستهفایل ندارند: با گذشت زمان، دریافتها (Fetches)، ارسالها (Pushes)، وظایف نگهداری و بازبستهبندیها میتوانند بستههای متعددی بر جای بگذارند.
یک نمایهٔ چندبستهای (یا MIDX) یک نمایهٔ واحد روی چندین بسته در اختیار گیت قرار میدهد. به جای باز کردن و جستجوی نمایه هر بسته بهطور جداگانه، گیت میتواند از MIDX بپرسد که یک شیء مشخص در کدام بسته و در چه افستی قرار دارد. این امر بهویژه برای مخازن بزرگ مفید است و یکی از بلوکهای سازندهٔ استراتژی نگهداری مخازن گیتهاب محسوب میشود.
گیت ۲.۵۵ به git repack میآموزد که چگونه آن زنجیرههای MIDX افزایشی را مستقیماً بنویسد:
$ git repack --write-midx=incremental
بدون هیچ گزینهٔ دیگری، این حالت فقط-افزودنی (Append-only) است: گیت یک لایهٔ جدید برای بستههای ایجادشده توسط بازبستهبندی مینویسد و لایههای موجود را دستنخورده باقی میگذارد. این زمانی مفید است که بخواهید میزان بازنویسی فراداده در طول یک اجرای نگهداری را به حداقل برسانید.
اما یک زنجیرهٔ فقط-افزودنی نمیتواند برای همیشه رشد کند. اگر هر بار اجرای نگهداری یک لایهٔ جدید اضافه کند، در نهایت خود زنجیره به چیزی تبدیل میشود که باید نگهداری شود. گیت ۲.۵۵ همچنین از ترکیب --write-midx=incremental با بازبستهبندی هندسی پشتیبانی میکند:
$ git repack --write-midx=incremental --geometric=2 -d
وقتی این حالتها با هم استفاده میشوند، هر بازبستهبندی یک لایهٔ انتهایی جدید ایجاد میکند و سپس تصمیم میگیرد که آیا لایههای مجاور باید با هم فشرده شوند یا خیر. قانون پیشفرض توسط repack.midxSplitFactor کنترل میشود: اگر تعداد اشیاء انباشتهشده در لایههای جدیدتر به اندازهٔ کافی نسبت به لایهٔ قدیمیتر بعدی بزرگ شود، گیت آن لایهها را در یک لایهٔ جایگزین واحد ادغام میکند. در غیر این صورت، لایههای قدیمیتر دستنخورده باقی میمانند.
اصلاح کامیتهای قبلی با git history
هر کسی که تا به حال مجموعهای از کامیتها را قبل از ارسال برای بازبینی صیقل داده است، احتمالاً این تجربه را داشته است: متوجه میشوید که یک تغییر در درخت کاری شما واقعاً به یک کامیت قبلی تعلق دارد، نه به انتهای شاخه.
امروزه، یکی از روشهای رایج برای رسیدگی به این موضوع، ایجاد یک کامیت اصلاحی (Fixup) و سپس ادغام خودکار آن است:
$ git commit --fixup=<commit>
$ git rebase --autosquash <commit>^
این روش کار میکند، اما از شما میخواهد که سازوکار را به جای قصد خود بیان کنید. گیت ۲.۵۵ بر روی دستور تجربی git history که در گیت ۲.۵۴ معرفی شد، با افزودن زیردستور جدید fixup بنا شده است. این زیردستور تغییراتی را که در حال حاضر در نمایه (Index) مرحلهبندی شدهاند، به یک کامیت قبلی اعمال میکند:
$ git history fixup <commit>
در اینجا یک مثال کوچک آورده شده است. کامیت اول یک دستور پخت پنکیک را معرفی کرد و سپس چند کامیت دیگر روی آن اضافه شد. بعداً متوجه میشویم که دستور پخت فاقد شربت افرا بود. پس از مرحلهبندی آن تغییر یکخطی، git history fixup <commit> آن را در کامیت اصلی دستور پخت ادغام کرده و کامیتهای بعدی را روی آن بازپخش میکند.

در اینجا تغییر مرحلهبندیشده بخشی از خود کامیت هدف میشود. کامیت هدف بهطور پیشفرض پیام و نویسندگی خود را حفظ میکند، مگر اینکه --reedit-message را پاس دهید، و گیت کامیتهای بعدی را بازنویسی میکند تا شاخه به تاریخی معادل با اصلاح در جای مناسب ختم شود.
مانند بقیهٔ git history، این دستور هنوز تجربی است. همچنین عمداً محافظهکارانه است. از آنجا که fixup از نمایه میخواند، به یک درخت کاری نیاز دارد و نمیتواند در یک مخزن خالی (Bare) عمل کند؛ اگر اعمال تغییر مرحلهبندیشده باعث ایجاد تعارض شود، دستور به جای اینکه شما را در میانهٔ یک بازنویسی وضعیتی رها کند، متوقف میشود.
قالب بندی بهتر بازبینیها
گیت یک دستور تجربی جدید به نام git format-rev یاد گرفته است، برای قالببندی زیبای بازبینیها از ورودی استاندارد. برخلاف git log که یک بازه از تاریخچه را پیمایش میکند، git format-rev برای مواردی طراحی شده است که با کامیتها یکییکی یا جاسازیشده در متن دیگر مواجه میشوید.
برای مثال، فرض کنید از git last-modified برای چاپ کامیتی که هر مسیر را در برخی دایرکتوریها آخرین بار تغییر داده، استفاده میکنید. اگر میخواستید بدانید چه کسی آخرین بار هر مسیر را تغییر داده، نه فقط کدام کامیت این کار را کرده، چه میکردید؟ میتوانستید آن کامیتها را با نام نویسنده جایگزین کنید و خروجی را از طریق چیزی شبیه به این لوله کنید:
$ git last-modified | perl -F'\t' -lane '
chomp($F[0] = qx(git show -s --format=%an $F[0]));
print join "\t", @F
'
Junio C Hamano builtin/commit.c
[...]
این روش کار میکند، اما برای هر سطر باید یک فرایند گیت جدید راهاندازی کند تا فقط کامیت را قالببندی کند. در گیت ۲.۵۵، git format-rev میتواند آن بخش را بهعنوان یک لولهٔ معمولی مدیریت کند:
$ git last-modified |
git format-rev --stdin-mode=text --format=%an
Junio C Hamano builtin/commit.c
[...]
حالت متنی این دستور همچنین میتواند نامهای کامل شیء کامیت موجود در متن آزاد را بازنویسی کند، که آن را برای هوکهای commit-message یا سایر گردشهای کاری اسکریپتنویسی مفید میکند.
این فقط نمونهای از تغییرات نسخهٔ اخیر بود. برای اطلاعات بیشتر، یادداشتهای انتشار برای ۲.۵۵ یا هر نسخهٔ قبلی را در مخزن گیت بررسی کنید.