امروز میخوام براتون از تجربه ۱ سال و خورده ای که توی یک شرکت استارتآپ داشتم بگم. خیلی نمیخوام در مورد همه جوانب صحبت کنم بلکه میخوام مستقیم برم سر اصل مطلب و اونم ورژن کنترلی به اسم گیت (GIT). اگر در مورد ورژن گیت اطلاعاتی ندارین اینجا میتونین توضیحات خیلی خوبی در موردش بخونین.
بزارین یکم مقدمه چینی کنم. خب من به عنوان اولین برنامه نویس این پروژه استخدام شدم و از اونجایی که تا مدتی داشتم تنهایی روی این پروژه کار میکردم و کسی هم نبود روی کارم مدیریت کنه منم هرجوری دلم میخواست داشتم توی پروژه مانور میدادم و از هر ابزاری دوست داشتم استفاده کردم که بعضی جاها به گریه کردن افتادم به خاطر مانورام ولی با یک هفته مرتب سازی فایل های پروژه بخیر گذشت.
بعد از مرتب سازی پروژه به خاطر این که خیالم جمع بشه که گندی بالا نیومده و فایل ها و بخش های پیاده سازی شده مثل قبل کار میکنن یک پروژه جدید روی گیتهاب ساختم و پروژه جدیده رو کنار پروژه قبلیه اونجا آپلود کردم.(یادش بخیر ما هم میتونستیم پروژه خصوصی روی گیتهاب داشته باشیم)
یک روز دیدم خیلی تاریخچه گیت بهم ریخته داره میشه و همه کامیت ها و ادغام ها دارن قاطی میشن و برگردودن یک سری از چیزا دیگه تقریبا غیر ممکنه. از طرفی هم همش میدیدم که پروژه های اوپن سورس خفنی که روی گیت هابه و چند هزار نفر دارن روش کار میکنن همیشه تاریخچه گیت تمیزی داره و این اصلا برام قابل درک نبود. مطمعن بودم یک جای کارم داره میلنگه (که همینطور هم بود).
اینجوری که پیش میرفتم همیشه به یک چیزی مثل شکل زیر میرسیدم آخرش!
مطمعنن شما هم مثل من چند باری با یک چیزی مثل شکل بالا مواجه شدین و چند بار سعی کردین متوجه بشین چی شده!
واسه همین شروع کردم گوگل کردن تا با واژه کامیت اتمیک (Atomic Commit) آشنا شدم و رفتم دنبالش . دقیقا همون چیزی بود که دنبالش بودم. بهتره شروع کنیم.
Atomic: Forming a single irreducible unit or component in a larger system
به زبون خودمونی میگه یک قسمت از یک سیستم رو اینقدر کوچیک کنیم که از اون کوچکتر نشه!
خب اولش منطقی بود و توی گیت هم همین کارو میکنیم و اینقدر کامیت رو کوچیک میکنم تا به کوچک ترین کامیت معنی دار ممکنه برسه (ممکنه این کامیت کوچک شامل چند تا فایل مرتبط به هم نیز بشه).
شاید یک سوال پیش بیاد که خب این حجم از کامیت بازم اعصاب خورد کنه. به اونم میرسیم!
خوب داشتم توی این سایت چرخی میزدم. مثال خیلی قشنگی زده بود و منم بهتر از این بلد نبودم مثال بزنم.
بیاین فکر کنیم یکی داره رو پروژه کار میکنه و بخش ظاهری سایت دستشه و یک کامیت میزنه مثل شکل زیر
راستش این خیلی وحشتناکه مخصوصا برای کسی که میخوای کد رو بازبینی کنه. حالا برای این که مشکل حل بشه از دو تا چیز کمک میگیریم: شاخه (branch) و کامیت اتمیک
حالا بیایم یک شاخه (Branch) جدید به اسم frontEnd بسازیم و تغییرات رو اونجا اضافه کنیم. مثل زیر:
خب الان دیگه خیلی راحت تره برای من اگر جایی موقع اضافه کردن یک ویژگی جدید به سیستم، خراب کاری کردم پیداش کنم و به راحتی میتونم اون کامیت رو برگردونم (revert).
مورد بعدی اینه که برای هر کامیت شما فضای مخصوص به خودش رو دارین تا به غیر از متنی که برای کامیت انتخاب میکنین یک سری توضیحات در مورد کارهای انجام شده توی اون کامیت هم بنویسین. خوب این به شما این قدر رو میده که در مورد هر کامیت اتمی که دارین یک فضای مخصوص داشته باشین که در مورد اون کار هایی که توی اون کامیت انجام دادین یک دل سیر توضیح مفید بدین بدون این که نگران باشین با جای دیگه اشتباه گرفته بشه.
بعد از اینکه این بخش ها گذشت اگر شما زمانی در آینده نه چندان دور خواستین ببینین که برای چی اون کد رو اونجا نوشتین و چه استفاده ای داشته خیلی راحت میتونید تاریخچه اون فایل توی گیت رو جست و جو کنید و شجره نامشو در بیارین. البته این بیشتر به درد مدیر پروژه و بالا دستیا میخوره که میخوان کد شمار رو برسی کنن چون هر برنامه نویسی میدونه برای چی کدی رو نوشته (معمولا).
خب تا اینجا که همه چی مثل قبله فقط با این تفاوت که نه تنها تاریخچمون بهتر نشد بلکه داره شلوغ تر هم میشه. من هم اول همین حس رو داشتم و اصلا درک نمیکردم تا این که یک مفهوم دیگه ای آشنا شدم به اسم تاریخچه خطی.
این تاریخچه اصل و اصولش بر این مبناست که هر شاخه باید بعد از ادغام شاخه قبل ایجاد شده باشه و توی گیت ما نباید تاریخچه ای داشته باشیم که از یک کامیت چند تا شاخه خارج شده باشه و بعد جلو تر به شاخه ادغام شده باشند.
همینطور که توی عکس بالا مشاهده میکنین، گیت سمت چپ میشه تاریخچه غیر خطی و سمت راست میشه خطی.
خب تا اینجا اوکیه ولی اولش ذهن آدم اینجوری درگیر میشه که من چطور میتونم تاریخچه خطی داشته باشم وقتی چند نفر همزمان دارن روی چند تا ویژگی به صورت جدا کار میکنن. برای منم اولش نمیشد تا اینکه با rebase آشنا شدم. من بهش میگم معجزه تمیز کننده.
خوب از اونجایی که گیت به ما یک ابزاری میده که پروژه و تغییرات رو به صورت یک گراف مدیریت کنیم. و زمانی که ما یک شاخه جدید ایجاد میکنیم. پدر اولین کامیت ما توی شاخه یکی از کامیت های شاخه پدره. rebase اومده که به ما این لطف رو بکنه و برای ما جای پدر شاخمون رو عوض کنه.
خب همونجور که توی عکس مشخصه، ابزار rebase میاد و برای ما این کار رو انجام میده که پدر شاخمون رو اخرین کامین شاخه پدر قرار میده و این به ما این قدرت رو میده که بتونیم تاریخچه ای خطی داشته باشیم. از طرفی هم میتونیم آخرین تغییراتی که روی کد اومده رو هم داشته باشیم و با کدی که نوشتیم تست کنیم و ببینیم آیا مشکلی وجود داره یا نه. فقط یادتون باشه اگر شاختون رو از قبل روی منبع فرستادین الان باید force push کنید به دلیل این که اولین کامیت شاختون تغییرات داشته و با منبع یکی نیست.
خب تا اینجا همه چی عالی شد ولی هنوز یک چیز ممکنه مشکل داشته باشه و اونم طولانی بودن لیست کامیت هایی که توی یک شاخه انجام شده. در اینجا هم ابزاری به من کمک کرد به اسم squash.
این ابزار میاد برای ما این ویژگی رو فراهم میکنه که کامیت هایی که ما مشخص کردیم رو برامون یکی میکنه. دیگه چی از این بهتر، هم خطی هم تک کامیت. اینجوری هم تاریخچه خطیه و هم کوچیک و خلاصه.
حالا سوالی که پیش میاد اینه که اون همه توضیحی که واسه کامیت ها نوشتیم پس چی؟ خب همشون پاک میشن و اشکالی هم نداره به دلیل این که کد شما داره وارد منبع میشه و معمولا توضیحات داخل هر کامیت تا زمانی مورد استفاده قرار میگیرن که هنوز کد وارد منبع نشده (این مساله ممکنه توی جاهای مختلف فرق کنه و بعضی جاها از توضیحات به عنوان مستند استفاده کنند.). بعد از این که کد وارد منبع شد یعنی هیچ مشکلی نداشته و همه تست ها انجام شده و تمام.
حالا شما هم میتونید مثل ما با یک ترفند کوچیک ابتدا تمام کامیت های شاختون رو squash کنین و بعد از اون شاخه پدر رو هم روی این شاخه rebase کنین. اینطوری تغییراتتون به آخر شاخه master اضافه میشه و هر دو شاختون به یک وضعیت یکسان میرسن و به راحتی میتونین شاخه ای داشتین روش کار میکردین رو پاک کنین چون همه تغییرات این شاخه رو الان شاخه پدر هم داره و تغییرات این شاخه به اخر شاخه پدر اضافه شده.
اینجوری شد که ما تونستیم یک تاریخچه مرتب داشته باشیم.