مسئله فایل بزرگ در یک مخزن واقعی
فرض کنید کد یک بازی یا سامانه آموزشی را در Git نگه میدارید و کنار آن فایلهای صوت، تصویر لایهباز و چند ویدئو قرار دارند. تغییر یک خط برنامه معمولاً تفاوت کوچکی ایجاد میکند، اما ذخیره نسخه تازه یک فایل باینری ممکن است مقدار زیادی داده وارد تاریخچه کند. نتیجه فقط بزرگ شدن پوشه امروز نیست؛ نسخههای قبلی نیز بخشی از تاریخچه پروژه هستند و دریافت مخزن را برای همکار تازه دشوار میکنند. Git LFS برای جدا کردن محتوای چنین فایلهایی از اشیای معمول Git طراحی شده است. برنامهنویس همچنان نام فایل و نسخه آن را همراه کد ثبت میکند، ولی خود داده در محل ذخیره مخصوص LFS قرار میگیرد.
انتخاب این ابزار باید با شناخت نوع داده انجام شود. فایل خروجی ساخت که هر بار از کد قابل تولید است معمولاً نباید صرفاً به دلیل بزرگ بودن وارد LFS شود؛ سامانه نگهداری مصنوعات ساخت میتواند جای مناسبتری باشد. در مقابل، تصویر اصلی طراحی یا نمونه صوتی که ورودی پروژه محسوب میشود به نسخهبندی هماهنگ با کد نیاز دارد. این تفاوت جلوی تبدیل مخزن به انبار همه فایلهای تیم را میگیرد و هزینه نگهداری را قابل توضیح میکند.
اشارهگر چه چیزی را ثبت میکند؟
در مدل رسمی LFS، داخل Git یک فایل متنی کوچک به جای محتوای بزرگ ثبت میشود. این اشارهگر نسخه قالب، شناسه محتوای شیء و اندازه آن را نگه میدارد. شناسه در قالب فعلی بر پایه SHA-256 است و اندازه به بایت بیان میشود. بنابراین اشارهگر خود تصویر یا ویدئو نیست؛ اطلاعات لازم برای پیدا کردن و کنترل محتوای مربوط به آن است. اگر کاربری فایل تصویری را باز کند و چند خط متن درباره version و oid ببیند، احتمالاً داده واقعی هنوز دریافت نشده است.
فیلتر clean هنگام افزودن فایل، محتوای آن را در ذخیره محلی LFS قرار میدهد و اشارهگر را به Git تحویل میدهد. فیلتر smudge در مسیر بیرون آوردن فایل از مخزن میتواند محتوای واقعی را جایگزین اشارهگر کند. طبق مستندات، clean بهتنهایی فایل را روی سرور نمیفرستد؛ قلاب پیش از push مسئول انتقال اشیای لازم است. این جدایی توضیح میدهد چرا موفق شدن commit محلی به معنای موجود بودن فایل روی سرور نیست. باید انتقال و سپس دریافت مستقل هم بررسی شود.
انتخاب الگو و ثبت قانون تیم
تنظیم اولیه را در یک مخزن آزمایشی و با فایل غیرحساس انجام دهید. ابتدا وجود فرمان Git LFS را بررسی کنید، سپس فیلترهای آن را نصب کنید. قانون ردیابی به فایل gitattributes نوشته میشود؛ این فایل بخشی از قرارداد پروژه است و باید همراه تغییرات ثبت شود. اگر فقط تنظیم محلی توسعهدهنده باقی بماند، دستگاه دیگر ممکن است همان فایلها را به روشی متفاوت وارد مخزن کند. انتخاب الگو نیز باید محدود و روشن باشد؛ دنبال کردن همه پسوندهای یکسان بدون شناخت کاربردشان میتواند فایلهای کوچک و غیرضروری را هم شامل کند.
git lfs version
git lfs install
git lfs track "*.psd"
git add .gitattributes
git add assets/cover.psd
git status
git commit -m "Track design source with LFS"
گیومه دور الگو اهمیت دارد: هدف این است که خود الگو به فرمان برسد، نه اینکه پوسته آن را به فهرست فایلهای حاضر تبدیل کند. نام فایل مثال صرفاً برای توضیح جریان است و باید با فایل واقعی آزمایش جایگزین شود. قبل از commit، خروجی وضعیت را ببینید تا تغییر نامرتبط وارد ثبت نشود. بعد از ثبت، فهرست فایلهای LFS را بررسی کنید. اگر فایل مورد انتظار دیده نمیشود، ابتدا مسیر و قانون تطبیق را بررسی کنید؛ تکرار کورکورانه push مشکل تنظیم الگو را حل نمیکند.
اولین انتقال و آزمون روی دستگاه دوم
یک آزمایش کامل زمانی پایان مییابد که فایل از یک محیط مستقل دریافت شود. پس از push، مخزن را در پوشه تازه یا دستگاه دیگر clone کنید، LFS را نصب داشته باشید و فایل واقعی را باز کنید. مقایسه اندازه و هش فایل اولیه با نسخه دریافتی نشان میدهد محتوا منتقل شده است. تکیه بر ظاهر صفحه وب مخزن کافی نیست؛ برخی میزبانها اشارهگر را نمایش میدهند یا پیشنمایشی تولید میکنند که جای آزمون دریافت واقعی را نمیگیرد.
git lfs ls-files
git push
# در نسخه مستقل مخزن:
git lfs pull
git lfs fsck
فرمان pull اشیای مورد نیاز مرجع جاری را دریافت و در صورت نیاز نسخه کاری را تکمیل میکند. fetch فقط دریافت را انجام میدهد و بهتنهایی نسخه کاری را بهروزرسانی نمیکند. این تفاوت هنگام رفع اشکال مهم است: ممکن است داده داخل حافظه محلی LFS موجود باشد ولی فایل کاری هنوز اشارهگر باشد. فرمان fsck سازگاری اشیای مورد بررسی را کنترل میکند؛ دامنه پیشفرض آن همه تاریخچه دوردست نیست. همچنین طبق راهنمای رسمی، فایل خراب میتواند به پوشه bad منتقل شود، پس این فرمان را صرفاً نمایش یک گزارش بیاثر تصور نکنید.
فایل از قبل در Git بوده است
افزودن یک الگوی تازه، تاریخچه قبلی را خودکار بازنویسی نمیکند. اگر فایل بزرگی در چندین commit معمولی ثبت شده باشد، آن اشیا همچنان در تاریخچه وجود دارند. پیش از تصمیم به مهاجرت، هدف را مشخص کنید: فقط نسخههای آینده باید با LFS ثبت شوند یا کاهش اندازه تاریخچه قدیمی نیز ضروری است؟ این دو هدف عملیات و ریسک متفاوت دارند. شروع با گزارش اطلاعات مهاجرت میتواند نوع فایلها و سهم آنها را روشن کند و از انتخاب همه تاریخچه بدون ضرورت جلوگیری کند.
git lfs migrate info
دامنه پیشفرض migrate محدود است و طبق مستندات به شاخه جاری و تغییراتی که روی remote موجود نیستند توجه دارد؛ نباید خروجی پیشفرض را گزارش کامل همه شاخهها فرض کرد. گزینههای گستردهتر را تنها پس از خواندن راهنمای همان نسخه انتخاب کنید. مهاجرتی که تاریخچه را بازنویسی کند شناسه commitها را تغییر میدهد و نیازمند هماهنگی با اعضای تیم است. برای مخزن مشترک، نسخه پشتیبان قابل بازیابی، توقف موقت تغییرات و برنامه دریافت دوباره همکاران را قبل از اجرا آماده کنید. این مقاله عمداً فرمان بازنویسی سراسری را بهعنوان قدم عادی نصب پیشنهاد نمیکند.
چرا روی رایانه من باز میشود و روی CI نه؟
دستگاه توسعه ممکن است فایل واقعی را از قبل در حافظه محلی داشته باشد. اجرای ساخت روی همان دستگاه موفق میشود، اما عامل ساخت تازه فقط اشارهگر را دریافت میکند. در این وضعیت خطای برنامه گاهی شبیه خرابی فرمت تصویر یا فایل مدل دیده میشود، در حالی که مشکل از دریافت ورودی است. بررسی ابتدای فایل، اندازه آن و خروجی فرمان LFS مسیر تشخیص را کوتاه میکند. اضافه کردن یک کنترل روشن در ابتدای ساخت، خطای زیرساخت دریافت را از خطای منطق برنامه جدا میکند.
در CI باید نصب کلاینت، دسترسی شبکه به محل اشیا و اعتبارنامه مناسب همگی برقرار باشند. داشتن اجازه clone برای Git الزاماً همه خطاهای دسترسی به نقطه پایانی LFS را منتفی نمیکند. برای ثبت شواهد، نام مرجع، نسخه کلاینت و پیام خطا را نگه دارید ولی توکن یا اطلاعات محرمانه اتصال را وارد لاگ عمومی نکنید. اگر ساخت تنها به بخشی از داراییها نیاز دارد، محدود کردن دریافت میتواند مفید باشد؛ بااینحال فهرست لازم باید از وابستگی واقعی ساخت استخراج شود تا خروجی ناقص به اشتباه موفق اعلام نشود.
تفکیک خطای شبکه از شیء گمشده
خطای اتصال، رد احراز هویت و نبود شیء یک مسئله واحد نیستند. در خطای شبکه ابتدا DNS، پراکسی و دسترسی به میزبان اشیا را بررسی کنید. در رد دسترسی، دامنه مجوز و اعتبار اعتبارنامه را بررسی کنید. اگر سرور اعلام میکند شیء مورد اشاره وجود ندارد، باید معلوم شود انتقال اولیه کامل شده یا مخزن Git بدون داده LFS به میزبان دیگری منتقل شده است. پاک کردن پوشه محلی در این مرحله میتواند تنها نسخه موجود فایل را از بین ببرد؛ ابتدا محل نسخه سالم را پیدا کنید.
برای بررسی تیمی، یک نمونه شکست با نام فایل، مرجع Git و شناسه شیء ثبت کنید. سپس همان مورد را از حساب و محیطی که باید مجاز باشد دریافت کنید. اگر فقط یک فایل شکست میخورد، اشکال عمومی نصب احتمال کمتری دارد و باید انتقال همان شیء بررسی شود. اگر همه فایلها شکست میخورند، مسیر اتصال و تنظیم endpoint اهمیت بیشتری پیدا میکند. این تفکیک ساده از تغییر همزمان چند تنظیم جلوگیری میکند و نتیجه هر اصلاح را قابل ارزیابی نگه میدارد.
پشتیبانگیری و جابهجایی مخزن
پشتیبان Git و پشتیبان اشیای LFS دو بخش مرتبط هستند. داشتن همه commitها، بدون محتوای اشارهگرها، برای بازیابی داراییهای پروژه کافی نیست. هنگام انتقال به میزبان جدید، باید وجود اشیای مورد نیاز شاخهها و برچسبهای نگهداریشده نیز بررسی شود. مستندات fetch گزینه دریافت گسترده اشیا را برای سناریوهای پشتیبان و مهاجرت توضیح میدهد؛ دامنه و هزینه آن را پیش از اجرا برآورد کنید. دریافت همه داده ممکن است فضای زیادی مصرف کند و نباید وسط یک ماشین کمظرفیت آغاز شود.
آزمون بازیابی را با یک برچسب قدیمی انجام دهید، نه فقط آخرین شاخه توسعه. اگر نسخه جاری درست باز شود ولی انتشار سال قبل داده خود را نداشته باشد، آرشیو پروژه کامل نیست. برای هر آزمون، مرجع انتخابی، فایلهای ضروری، نتیجه دریافت و هش خروجی را ثبت کنید. این مدرک از یک عبارت کلی مثل «بکاپ داریم» مفیدتر است، زیرا نشان میدهد کدام نسخه واقعاً قابل بازسازی بوده است. سیاست نگهداری نیز باید روشن کند کدام تاریخچه و داراییها قرار است برای چه مدتی قابل بازیابی بمانند.
فضا، هزینه و نگهداری روزمره
LFS فایل را ناپدید نمیکند؛ محل و شیوه مدیریت آن را تغییر میدهد. ظرفیت ذخیره، حجم دانلود و محدودیت میزبان همچنان باید بررسی شود. عددهای تعرفه و سقفها میان سرویسها تفاوت دارند و ممکن است تغییر کنند؛ برای تصمیم خرید، صفحه همان میزبان را در زمان تصمیم بخوانید. یک پروژه با دارایی ثابت و تعداد دریافت کم با پروژهای که هر روز ویدئوی تازه دارد یک الگوی هزینه ندارد. اندازه ورودی، تعداد عاملهای ساخت و دفعات دریافت شاخهها را جدا اندازه بگیرید.
پاکسازی محلی با prune نیز جای حذف داده از سرور نیست. این فرمان براساس قواعد مربوط به مراجع و اشیای اخیر تصمیم میگیرد چه نسخههایی از حافظه محلی قابل حذفاند. پیش از هر پاکسازی، راهنمای نسخه نصبشده و گزینه نمایش آزمایشی را بررسی کنید و مطمئن شوید بازیابی از remote واقعاً ممکن است. پاک کردن دستی کل پوشه اشیا برای آزاد کردن سریع فضا روش مناسبی برای تشخیص مشکل نیست. بهتر است ابتدا مصرف مخزن، فایلهای کاری و حافظه LFS جداگانه اندازهگیری شوند تا بخش پرمصرف مشخص باشد.
قرارداد قابل اجرا برای اعضای پروژه
در راهنمای مشارکت پروژه، پسوندهای مجاز، مسیر داراییها و روش نصب LFS را روشن بنویسید. برای طراح یا تولیدکننده محتوا توضیح دهید که commit، انتقال و دریافت سه مرحله متفاوتاند و تمام شدن مرحله اول پایان کار نیست. یک فایل آزمایشی کوچک و بیحساسیت در فرایند ورود همکار تازه قرار دهید تا پیش از کار روی دارایی اصلی، تنظیمات بررسی شود. در بازبینی تغییرات نیز فایل gitattributes باید مانند تنظیم ساخت بررسی شود؛ حذف تصادفی یک قانون میتواند رفتار افزودن فایلهای بعدی را عوض کند.
برای پایان استقرار، یک معیار پذیرش عملی داشته باشید: همکار تازه بتواند نسخه مشخصی را دریافت کند، فایل واقعی را باز کند و ساخت پروژه بدون تکیه بر حافظه دستگاه قبلی انجام شود. همچنین بازیابی یک انتشار قدیمی و انتقال یک دارایی تازه آزمایش شده باشد. این معیارها نشان میدهند LFS واقعاً در چرخه کار تیم جا افتاده است. ابزار زمانی مفید خواهد بود که رابطه کد و دارایی حفظ شود و هر عضو بداند داده اصلی کجا قرار دارد، چگونه دریافت میشود و در صورت شکست انتقال از چه مسیری باید مسئله را پیگیری کند.