شروع به کار با گیت (git) - درباره ورژن کنترل

5 دقیقه

زمان مطالعه

5

1 رای

۵۳

بازدید

۱۴۰۵/۶/۶

تاریخ انتشار

این فصل نقطهٔ شروع کار با گیت است. ابتدا مروری بر تاریخچهٔ ابزارهای کنترل نسخه خواهیم داشت، سپس نحوهٔ راه‌اندازی گیت روی سیستم شما را توضیح می‌دهیم و در پایان به پیکربندی و نخستین گام‌های کار با آن می‌پردازیم. در انتهای این فصل خواهید دانست گیت چرا به وجود آمده و چه مشکلی را حل می‌کند، و خواهید توانست محیط کار خود را برای استفاده از آن آماده کنید.

درباره ورژن کنترل (About Version Control)

«کنترل نسخه» (version control) چیست و چرا باید برای شما اهمیت داشته باشد؟ کنترل نسخه سیستمی است که تغییرات یک فایل یا مجموعه‌ای از فایل‌ها را در طول زمان ثبت می‌کند تا بتوانید بعداً به نسخه‌های مشخصی از آن‌ها بازگردید. در مثال‌های این کتاب، فایل‌هایی که تحت کنترل نسخه قرار می‌گیرند کد منبع نرم‌افزار هستند، اما در عمل می‌توانید تقریباً هر نوع فایلی روی کامپیوتر را به همین شکل مدیریت کنید.

اگر طراح گرافیک یا طراح وب هستید و می‌خواهید هر نسخه از یک تصویر یا طرح را نگه دارید — که تقریباً همیشه همین‌طور است — استفاده از یک «سیستم کنترل نسخه» (Version Control System یا VCS) انتخاب هوشمندانه‌ای است. چنین سیستمی به شما اجازه می‌دهد یک فایل مشخص یا کل پروژه را به وضعیت پیشین بازگردانید، تغییرات را در طول زمان با هم مقایسه کنید، و ببینید چه کسی، چه زمانی و با چه تغییری باعث بروز یک مشکل شده است. به بیان ساده، اگر چیزی را خراب کردید یا فایلی را از دست دادید، بازیابی آن به‌سادگی ممکن خواهد بود؛ و همهٔ این مزایا با سرباری بسیار اندک به دست می‌آید.

برای اینکه بدانید گیت چرا به شکل امروزی‌اش طراحی شده است، بهتر است ابتدا ببینید ابزارهای پیش از آن چه مشکلاتی را حل کردند و کجا کم آوردند. تاریخ کنترل نسخه را می‌توان تقریباً در سه نسل خلاصه کرد: نسل محلی که تاریخچه را روی همان ماشینِ توسعه‌دهنده نگه می‌داشت، نسل متمرکز که تاریخچه را به یک سرور مشترک منتقل کرد تا همکاری تیمی ممکن شود، و نسل توزیع‌شده که یک کپی کامل از تاریخچه را به هر توسعه‌دهنده داد. هر نسل مسئله‌ای از نسل پیشین را حل کرد و در عوض دشواری‌های تازه‌ای آورد.

سیستم‌های کنترل نسخه محلی (Local Version Control Systems)

روشی که بسیاری از افراد برای کنترل نسخه به کار می‌برند این است که فایل‌ها را در پوشه‌ای دیگر کپی می‌کنند (و اگر کمی باتجربه‌تر باشند، پوشه‌ای که نامش شامل تاریخ است). این روش به دلیل سادگی بسیار رایج است، اما به‌شدت خطاپذیر است: به‌راحتی ممکن است فراموش کنید در کدام پوشه هستید، فایل اشتباهی را بازنویسی کنید یا فایل‌هایی را کپی کنید که قصدش را نداشتید.

برای حل همین مشکل بود که برنامه‌نویسان از دههٔ ۱۹۷۰ سراغ سیستم‌های کنترل نسخهٔ محلی رفتند؛ سیستم‌هایی با یک پایگاه دادهٔ ساده که تمام تغییرات اعمال‌شده بر فایل‌های تحت کنترل را ثبت می‌کردند.

Local version control diagram
نمودار 1. Local version control diagram

نخستین نمونهٔ شناخته‌شده از این خانواده، SCCS بود که مارک راکایند (Marc Rochkind) در سال ۱۹۷۲ در آزمایشگاه‌های بل توسعه داد و برای مدت‌ها ابزار استاندارد کنترل نسخه در دنیای یونیکس به شمار می‌رفت. یک دهه بعد، والتر تیکی (Walter F. Tichy) در دانشگاه پردیو سیستم RCS را ساخت که به دلیل سادگی و سرعت بیشتر، جایگزین SCCS شد و هنوز هم همراه بسیاری از سیستم‌عامل‌ها عرضه می‌شود.

«RCS» با نگهداری مجموعه‌ای از پچ‌ها (یعنی تفاوت‌های میان نسخه‌های متوالی یک فایل) در قالبی ویژه روی دیسک کار می‌کند؛ سپس می‌تواند با اعمال پیاپی این پچ‌ها، هر نسخه از فایل را در هر نقطه‌ای از زمان بازسازی کند.

SCCS و RCS در شیوهٔ ذخیره‌سازی تاریخچه تفاوتی بنیادی داشتند و همین تفاوت توضیح می‌دهد چرا RCS در عمل سریع‌تر بود. SCCS تمام بازبینی‌های یک فایل را به‌صورت «درهم‌بافته» (interleaved delta، که به آن weave هم گفته می‌شود) در یک فایل واحد نگه می‌داشت؛ در این قالب هر خط با نشانه‌هایی همراه است که مشخص می‌کند آن خط در کدام بازبینی‌ها حضور دارد، بنابراین هزینهٔ بازسازی نسخهٔ قدیمی و جدید تقریباً یکسان است. RCS در مقابل از «دلتای معکوس» (reverse delta) استفاده می‌کرد: تازه‌ترین بازبینی روی شاخهٔ اصلی به‌صورت کامل ذخیره می‌شود و نسخه‌های قدیمی‌تر با اعمال پیاپی تفاوت‌های معکوس ساخته می‌شوند، در حالی که روی شاخه‌های فرعی همچنان دلتای مستقیم (forward delta) به کار می‌رود. چون در کار روزمره بیشترین درخواست‌ها مربوط به آخرین نسخه است، این طراحی رایج‌ترین عملیات را به ارزان‌ترین عملیات تبدیل می‌کرد.

تفاوت مهم دیگر در مدل همکاری بود. در RCS فایل با دستور co -l (یعنی checkout همراه با قفل) بیرون آورده می‌شد و تا زمانی که همان کاربر تغییر خود را با ci ثبت نکرده بود، دیگران اجازهٔ ویرایش آن فایل را نداشتند. این مدل «قفل انحصاری» (exclusive locking) از بروز تعارض جلوگیری می‌کرد، اما کار موازی را هم عملاً از بین می‌برد: اگر همکار شما فایلی را قفل کرده و به مرخصی رفته بود، تا بازگشت او کاری از دست کسی برنمی‌آمد. سیستم‌های بعدی این مدل را کنار گذاشتند و به‌جای آن مدل «ویرایش موازی و سپس ادغام» (merge) را برگزیدند که در آن چند نفر هم‌زمان روی یک فایل کار می‌کنند و ابزار، تغییرات را در پایان با هم تلفیق می‌کند.

محدودیت اصلی این نسل از ابزارها آن بود که واحد کارشان «یک فایل» بود، نه «یک تغییر منسجم در پروژه». به همین دلیل مفهومی مانند کامیت اتمی — یعنی ثبت هم‌زمان و تفکیک‌ناپذیر تغییرات چند فایل به‌عنوان یک واحد — در آن‌ها وجود نداشت؛ مفهومی که بعدها به یکی از پایه‌های سیستم‌های مدرن تبدیل شد. در عمل یعنی اگر یک تغییر منطقی به سه فایل دست می‌زد، سه ثبت جداگانه با سه شمارهٔ بازبینی مستقل انجام می‌شد و هیچ چیز در خودِ سیستم این سه را به هم گره نمی‌زد؛ بازگرداندن آن تغییر یا فهمیدن اینکه دقیقاً کدام مجموعه فایل با هم عوض شده‌اند، بر عهدهٔ حافظه و نظم شخصی توسعه‌دهنده بود.

یادداشت

RCS امروز هم به‌عنوان یکی از بسته‌های پروژهٔ گنو نگهداری می‌شود و در بسیاری از توزیع‌های یونیکس و لینوکس در دسترس است. کاربرد متداول امروزی‌اش نسخه‌بندی سریع تک‌فایل‌های پیکربندی روی یک ماشین است — مثلاً نگه‌داشتن تاریخچهٔ تغییرات یک فایل در /etc — نه مدیریت یک پروژهٔ نرم‌افزاری تیمی.

سیستم‌های کنترل نسخه متمرکز (Centralized Version Control Systems)

چالش بزرگ بعدی زمانی پیدا شد که توسعه‌دهندگان نیاز داشتند با همکارانی روی سیستم‌های دیگر همکاری کنند. پاسخ به این نیاز، پیدایش «سیستم‌های کنترل نسخه متمرکز» (Centralized Version Control Systems یا CVCS) بود. در این سیستم‌ها — مانند CVS، Subversion و Perforce — یک سرور مرکزی تمام فایل‌های نسخه‌بندی‌شده را نگه می‌دارد و کلاینت‌ها فایل‌ها را از همان نقطهٔ مرکزی دریافت (checkout) می‌کنند. این معماری سال‌ها استاندارد عملی کنترل نسخه بود.

Centralized version control diagram
نمودار 2. Centralized version control diagram

سرشناس‌ترین عضو این خانواده، CVS بود که دیک گرونه (Dick Grune) در سال ۱۹۸۶ آن را در قالب مجموعه‌ای از اسکریپت‌های شل روی RCS بنا کرد و نسخهٔ بازنویسی‌شده به زبان C در سال ۱۹۸۹ منتشر شد. همین ریشه‌داشتن در RCS، هم نقطهٔ قوت CVS بود و هم منشأ بیشتر کاستی‌هایش: CVS در واقع لایه‌ای شبکه‌ای و چندکاربره روی یک انبارهٔ فایل‌محور بود و بسیاری از محدودیت‌های آن انباره را به ارث برد.

شناخته‌شده‌ترین مشکلات عملی CVS این‌ها بودند:

  • نبود نسخه‌بندی پوشه‌ها: CVS تنها فایل‌ها را نسخه‌بندی می‌کرد. ساختن، حذف یا جابه‌جا کردن یک پوشه رویدادی نبود که در تاریخچه ثبت شود، بنابراین بازسازی دقیق ساختار پروژه در یک نقطهٔ گذشته همیشه شدنی نبود.
  • نبود کامیت اتمی: ثبت تغییرات فایل‌به‌فایل انجام می‌شد. اگر ارتباط شبکه در میانهٔ کار قطع می‌شد، بخشی از فایل‌ها ثبت شده و بخشی ثبت‌نشده باقی می‌ماند و مخزن در وضعیتی ناسازگار رها می‌شد.
  • ضعف در تغییر نام و جابه‌جایی: تغییر نام یک فایل به‌صورت «حذف قدیمی + افزودن جدید» انجام می‌شد و پیوند تاریخچه گسسته می‌شد؛ یعنی تاریخچهٔ پیش از تغییر نام به‌سادگی قابل دنبال کردن نبود.
  • شمارهٔ بازبینی برای هر فایل: هر فایل شمارهٔ مستقل خودش را داشت (۱٫۱، ۱٫۲ و…) و هیچ شناسهٔ واحدی برای «وضعیت کل پروژه در یک لحظه» وجود نداشت؛ برای این کار باید دستی برچسب (tag) می‌گذاشتید.
  • رفتار پیش‌فرض متن‌محور: CVS فایل‌ها را به‌طور پیش‌فرض متنی فرض می‌کرد و فایل‌های باینری باید صراحتاً با گزینهٔ -kb علامت‌گذاری می‌شدند، وگرنه در معرض تبدیل خط‌پایان و جایگزینی کلیدواژه‌ها قرار می‌گرفتند و خراب می‌شدند.

پروژهٔ Subversion در سال ۲۰۰۰ توسط شرکت CollabNet و دقیقاً با هدف رفع همین کاستی‌ها آغاز شد؛ نسخهٔ ۱٫۰ آن در سال ۲۰۰۴ منتشر شد و در سال ۲۰۱۰ به یکی از پروژه‌های سطح‌بالای بنیاد آپاچی تبدیل شد. شعار غیررسمی پروژه در سال‌های نخست، «یک CVS بهتر» بود و همین به‌خوبی توضیح می‌دهد چه چیزهایی را تغییر داد:

  • کامیت اتمی: هر ثبت یک تراکنش روی کل مخزن است؛ یا همهٔ تغییرات با هم اعمال می‌شوند یا هیچ‌کدام. دیگر امکان ندارد نیمی از یک تغییر در مخزن بنشیند.
  • شمارهٔ بازبینی سراسری: به‌جای شمارهٔ جداگانه برای هر فایل، کل مخزن یک عدد صحیح افزایشی دارد (مثلاً r1234) که به یک عکس لحظه‌ای از تمام درخت پروژه اشاره می‌کند. همین یک تغییر، ارجاع‌دادن به یک وضعیت مشخص از پروژه را ساده کرد.
  • نسخه‌بندی پوشه‌ها و کپی ارزان: پوشه‌ها هم شهروند درجه‌یک شدند و کپی و انتقال به‌صورت عملیات ثبت‌شده در تاریخچه درآمدند. به همین دلیل در Subversion شاخه و برچسب چیزی جز کپی یک پوشه نیستند و هزینهٔ ساختنشان تقریباً صفر است.
  • متادیتای نسخه‌بندی‌شده: می‌توان به فایل‌ها و پوشه‌ها «خواص» (properties) نسبت داد — مانند svn:ignore یا svn:executable — و خودِ این خواص نیز مانند محتوای فایل، تاریخچه دارند.

نمونهٔ شاخص تجاری این نسل، Perforce است که امروز با نام Helix Core شناخته می‌شود. Perforce با آنکه معماری متمرکز دارد، هنوز هم در پروژه‌های بسیار بزرگ — به‌ویژه در صنعت بازی‌سازی و تولید محتوای دیجیتال — جایگاه محکمی دارد. دلیلش دقیقاً همان‌جایی است که سیستم‌های توزیع‌شده ضعیف‌اند: یک پروژهٔ بازی می‌تواند ده‌ها یا صدها گیگابایت دارایی باینری داشته باشد (مدل سه‌بعدی، بافت، صدا، ویدیو) که نه قابل ادغام‌اند و نه به‌خوبی فشرده می‌شوند. در مدل متمرکز، کلاینت فقط زیرمجموعه‌ای از فایل‌ها را که واقعاً نیاز دارد دریافت می‌کند و نه کل تاریخچه را؛ و مدل «چک‌اوت انحصاری» به هنرمندی که روی یک فایل باینری کار می‌کند تضمین می‌دهد که هیچ‌کس هم‌زمان همان فایل را تغییر نمی‌دهد — تضمینی که برای فایل غیرقابل‌ادغام، از هر الگوریتم merge باارزش‌تر است.

این معماری نسبت به سیستم‌های محلی مزایای روشنی دارد. برای نمونه، هر عضو تیم تا حد خوبی می‌داند دیگران مشغول چه کاری هستند؛ مدیران سیستم می‌توانند به‌دقت تعیین کنند چه کسی به چه چیزی دسترسی داشته باشد — حتی در سطح یک مسیر مشخص از درخت پروژه؛ و نگهداری یک سرور مرکزی به‌مراتب ساده‌تر از مدیریت پایگاه‌دادهٔ محلی روی تک‌تک کلاینت‌هاست.

با این حال، معایب جدی هم دارد. آشکارترین ایراد، «نقطهٔ شکست واحد» است که سرور مرکزی ایجاد می‌کند: اگر آن سرور یک ساعت از دسترس خارج شود، در تمام آن مدت هیچ‌کس نمی‌تواند همکاری کند یا تغییرات نسخه‌بندی‌شدهٔ خود را ثبت کند. و اگر دیسکِ میزبانِ پایگاه‌دادهٔ مرکزی خراب شود و نسخهٔ پشتیبان مناسبی وجود نداشته باشد، عملاً همه‌چیز از دست می‌رود — کل تاریخچهٔ پروژه، به‌جز نسخه‌های پراکنده‌ای که شاید روی سیستم‌های محلی افراد باقی مانده باشد. سیستم‌های محلی نیز دقیقاً از همین ضعف رنج می‌برند: هر جا کل تاریخچهٔ پروژه در یک نقطه متمرکز باشد، خطر از دست رفتن کامل آن وجود دارد.

وابستگی به شبکه فقط مسئلهٔ خرابی سرور نیست؛ در این مدل تقریباً هر عملیات معناداری به رفت‌وبرگشت با سرور نیاز دارد. دیدن تاریخچهٔ یک فایل، مقایسهٔ وضعیت فعلی با یک بازبینی قدیمی، یا ثبت یک تغییر — همه در گرو در دسترس بودن سرور و کیفیت اتصال شبکه‌اند. همین موضوع باعث می‌شد کامیت‌ها بزرگ و کم‌تعداد شوند: وقتی هر ثبت هزینهٔ زمانی دارد و بلافاصله دیگران را تحت تأثیر قرار می‌دهد، توسعه‌دهنده ترجیح می‌دهد تغییرات را روی هم انباشته کند و یک‌جا بفرستد.

یادداشت

مخازن متمرکز هنوز در بسیاری از سازمان‌ها فعال‌اند و گیت برای کار با آن‌ها ابزار دارد. دستور git svn به شما اجازه می‌دهد یک مخزن Subversion را به‌عنوان مخزن راه دور گیت به کار ببرید، و git p4 همین نقش را برای Perforce بازی می‌کند. این‌ها را در بخش Git و Subversion و Git و Perforce می‌بینید، و اگر قصد مهاجرت کامل دارید، بخش مهاجرت به گیت نقطهٔ شروع مناسبی است.

سیستم‌های کنترل نسخه توزیع‌شده (Distributed Version Control Systems)

اینجاست که «سیستم‌های کنترل نسخه توزیع‌شده» (Distributed Version Control Systems یا DVCS) وارد می‌شوند. در یک DVCS — مانند Git، Mercurial یا Darcs — کلاینت‌ها تنها آخرین نسخهٔ فایل‌ها را دریافت نمی‌کنند، بلکه کل مخزن را همراه با تمام تاریخچه‌اش به‌طور کامل کپی می‌کنند. بنابراین اگر سروری که تیم از طریق آن همکاری می‌کرد از بین برود، می‌توان مخزن را از روی کپی هر یک از اعضا بازیابی کرد. به بیان دیگر، هر clone خودش یک نسخهٔ پشتیبان کامل از تمام داده‌هاست.

Distributed version control diagram
نمودار 3. Distributed version control diagram

نکتهٔ تاریخی جالب اینکه دو نمایندهٔ شاخص این نسل، یعنی Git و Mercurial، هر دو در آوریل ۲۰۰۵ و در واکنش به یک رویداد مشترک متولد شدند: پایان یافتن دسترسی رایگان جامعهٔ کرنل لینوکس به ابزار BitKeeper. لینوس توروالدز کار روی Git را در همان ماه آغاز کرد و مت مکال (Matt Mackall) نیز چند روز بعد Mercurial را معرفی کرد. داستان کامل این ماجرا را در بخش بعدی (در آینده اضافه خواهد شد) خواهید خواند.

پیش از این دو، پروژه‌های دیگری هم همین ایده را دنبال کرده بودند و سرنوشت‌های متفاوتی پیدا کردند:

  • Darcs که دیوید راندی (David Roundy) در سال ۲۰۰۳ به زبان هسکل نوشت و بر پایهٔ ایده‌ای به نام «نظریهٔ پچ‌ها» بنا شده بود: در Darcs واحد بنیادی، پچ است نه عکس لحظه‌ای پروژه، و پچ‌ها می‌توانند مستقل از ترتیبشان جابه‌جا شوند. این مدل زیبا اما در برخی حالت‌ها بسیار کند بود و Darcs هرگز به کاربرد گسترده نرسید.
  • Bazaar (یا GNU Bazaar) که شرکت Canonical آن را از سال ۲۰۰۵ توسعه داد و برای مدتی ابزار رسمی توسعهٔ اوبونتو و میزبان Launchpad بود. توسعهٔ فعال آن متوقف شد و امروز ادامهٔ کارش را انشعابی جامعه‌محور به نام Breezy پیش می‌برد.
  • Mercurial که برخلاف دو مورد بالا هنوز زنده است و در برخی سازمان‌های بزرگ استفاده می‌شود، هرچند سهم عمومی‌اش پس از آنکه Bitbucket در سال ۲۰۲۰ پشتیبانی از آن را کنار گذاشت به‌شدت کاهش یافت. ایده‌های آن بی‌وارث نماندند: Sapling، سیستم کنترل نسخه‌ای که Meta منتشر کرده، ریشه در Mercurial دارد.

افزون بر این، بسیاری از این سیستم‌ها می‌توانند به‌خوبی با چندین مخزن راه دور (remote) به‌صورت هم‌زمان کار کنند؛ بنابراین می‌توانید در یک پروژهٔ واحد، هم‌زمان با گروه‌های مختلفی از افراد و به شیوه‌های متفاوت همکاری کنید. همین قابلیت است که پیاده‌سازی جریان‌های کاری متنوعی را ممکن می‌کند — از جمله مدل‌های سلسله‌مراتبی — که در سیستم‌های متمرکز عملاً شدنی نیستند. اگر می‌خواهید ببینید این جریان‌ها در عمل چه شکلی دارند، فصل جریان‌های کاری توزیع‌شده (در آینده اضافه خواهد شد) را ببینید.

مزیت‌های عملی این معماری فراتر از «پشتیبان‌گیری» است و در کار روزمره خود را نشان می‌دهد:

  • کار آفلاین: چون کل تاریخچه روی دیسک شماست، ثبت کامیت، دیدن تاریخچه، مقایسهٔ نسخه‌ها، ساخت شاخه و بررسی اینکه هر خط را چه کسی نوشته، همگی بدون هیچ ارتباط شبکه‌ای انجام می‌شوند و در حد میلی‌ثانیه طول می‌کشند.
  • شاخه‌بندی ارزان: ساختن یک شاخه در گیت عملاً هزینه‌ای ندارد. همین ارزانی است که فرهنگ «شاخهٔ موضوعی» (topic branch) را ممکن کرده: برای هر ویژگی یا رفع اشکال، شاخه‌ای جدا بسازید، آزادانه رویش آزمایش کنید و اگر به نتیجه نرسید بی‌دردسر دورش بیندازید. جزئیات را در فصل انشعاب‌گیری در گیت (در آینده اضافه خواهد شد) می‌بینید.
  • بازبینی کد پیش از ادغام: چون کامیت‌ها می‌توانند مدتی به‌صورت محلی یا روی یک شاخهٔ جداگانه بمانند، امکان بازبینی و بحث دربارهٔ تغییرات پیش از ورودشان به شاخهٔ اصلی فراهم می‌شود؛ چیزی که در مدل متمرکز — که هر کامیت بی‌درنگ همه را تحت تأثیر قرار می‌داد — دشوار بود.
  • مدل fork و pull request: چون هیچ‌کس برای داشتن یک کپی کامل و قابل ثبت‌کامیت از پروژه نیازی به مجوز نوشتن روی مخزن اصلی ندارد، هر فرد می‌تواند نسخهٔ خودش را بردارد، تغییر دهد و سپس ادغام آن را پیشنهاد کند. این همان الگویی است که همکاری در پروژه‌های متن‌باز را در مقیاس امروزی ممکن کرد. شرح این جریان کاری در بخش مشارکت در یک پروژه (در آینده اضافه خواهد شد) آمده است.
یادداشت

«توزیع‌شده» به معنای «بدون سرور مرکزی» نیست. بیشتر تیم‌ها یک مخزن مشترک (روی GitHub، GitLab یا یک سرور داخلی) را به‌عنوان مرجع رسمی پروژه تعیین می‌کنند. تفاوت در این است که این تمرکز یک قرارداد تیمی است، نه یک الزام فنی: از دید گیت، آن مخزن هیچ امتیاز ذاتی‌ای بر کپی‌های دیگر ندارد و در صورت نیاز می‌توان مرجع را به هر کپی سالم دیگری منتقل کرد.

در مقابل، این معماری هزینه‌هایی هم دارد که کمتر دربارهٔ آن‌ها صحبت می‌شود و بهتر است از همان ابتدا بشناسیدشان:

  • فایل‌های باینری حجیم: چون هر clone تمام تاریخچه را می‌آورد، هر نسخه از هر فایل باینری که روزی وارد پروژه شده تا ابد در مخزن می‌ماند. فایل‌های باینری معمولاً به‌خوبی فشرده و دلتاگیری نمی‌شوند، بنابراین چند صد مگابایت دارایی که ده‌ها بار به‌روزرسانی شده‌اند می‌توانند مخزن را برای همیشه سنگین کنند. پاسخ متداول به این مشکل Git LFS است که به‌جای خود فایل، یک اشاره‌گر متنی کوچک را در مخزن نگه می‌دارد و محتوای واقعی را روی سروری جداگانه ذخیره می‌کند.
  • نبود قفل انحصاری: گیت مدل «ویرایش موازی و سپس ادغام» را برگزیده و به‌طور پیش‌فرض راهی برای قفل کردن یک فایل ندارد. برای کدی که با ابزار متنی ادغام‌شدنی است این انتخاب درستی است، اما برای فایل باینری غیرقابل‌ادغام دردسرساز می‌شود؛ به همین دلیل Git LFS قابلیت قفل فایل را جداگانه اضافه کرده است.
  • حجم clone در مخازن بسیار بزرگ: در مخزنی با سال‌ها تاریخچه، دریافت کامل همه‌چیز می‌تواند کند و پرهزینه باشد. گیت برای این حالت چند راهکار دارد: clone کم‌عمق برای گرفتن فقط چند کامیت آخر، clone جزئی برای به تعویق انداختن دریافت محتوای فایل‌ها تا زمان نیاز، و sparse-checkout برای اینکه فقط بخشی از درخت پروژه در پوشهٔ کاری شما باز شود.
$ git clone --depth 1 https://github.com/git/git.git
$ git clone --filter=blob:none https://github.com/git/git.git

دستور نخست تنها آخرین کامیت را دریافت می‌کند (clone کم‌عمق) و برای مواردی مانند سرورهای ساخت خودکار که به تاریخچه نیازی ندارند مناسب است. دستور دوم یک clone جزئی می‌سازد: ساختار کامیت‌ها دریافت می‌شود اما محتوای فایل‌ها فقط هنگام نیاز از سرور گرفته می‌شود. هر دو حجم دریافت اولیه را به‌شدت کم می‌کنند، به این بهای روشن که برخی عملیات محلی دیگر واقعاً محلی نیستند و به شبکه نیاز پیدا می‌کنند.

این معماری امروز به الگوی غالب توسعهٔ نرم‌افزار تبدیل شده است؛ برای نمونه، در نظرسنجی سالانهٔ توسعه‌دهندگان Stack Overflow در سال ۲۰۲۲ بیش از ۹۳ درصد پاسخ‌دهندگان اعلام کردند که از Git به‌عنوان سیستم کنترل نسخهٔ خود استفاده می‌کنند. با این حال، همان‌طور که دیدید، هیچ نسلی جانشین کامل نسل پیش از خود نشد: سیستم‌های متمرکز هنوز در حوزه‌هایی که دارایی‌های باینری بزرگ و کنترل دسترسی ریزدانه حرف اول را می‌زنند جای خود را دارند، و RCS هنوز برای نسخه‌بندی یک فایل تنها روی یک ماشین ابزار کاملاً معقولی است. آنچه Git را به انتخاب پیش‌فرض تبدیل کرد، ترکیب کار آفلاین، شاخه‌بندی ارزان و مدل همکاری بدون نیاز به مجوز مرکزی بود.

این محتوا چطور بود؟

نظر شما به بهبود محتوا کمک می‌کند

امیر دایی
امیر دایی
500k دنبال‌کننده

از بچگی عاشق برنامه نویسی بودم