پروژه پیادهسازی شده یک ماشین حساب ساده با عملیاتهای جمع، تفریق، ضرب و تقسیم میباشد و از پرانتز گزاریهای پیچیده نیز پیروی میکند. برای این پروژه ما از سه پکیج استفاده کردیم. در لایه ابتدایی یک رابط کاربری ساده با ترمینال وجود دارد و در لایه دوم و سوم نیز عملیاتهای مربوط به پارس کردن ورودی و در نهایت محاسبه ورودی انجام میشود که در ادامه به توضیح هر یک از این پکیجها میپردازیم.
- این پکیج تنها دارای یک فایل terminal میباشد که در واقع فراهم کننده یک رابط کاربری در ترمینال است و ورودیها را از کاربر میگیرد و با پاس دادن عبارت گرفته شده به پارسر و گرفتن جواب از آن، پاسخ را به کاربر نمایش میدهد.
توسعه این پکیج در برنچ feature/view انجام شده است که در نهایت چون تغییراتی در پکیج parser ایجاد شده بود که این برنچ از آن بیخبر بود، در موقع pull کردن از مستر با یک کانفلیکت رو به رو شد که با موفقیت آن را resolve کردیم و تغییرات لازم را برای رفع مشکلات ناشی از ادغام نیز اعمال کردیم و در نهایت با یک pull request این برنچ با برنچ main ادغام شد.
این پکیج دارای سه فایل میباشد.
- فایل phrase در واقع یک ساختاری از عبارات را در خود دارد که در آن از الگوی composite کمک گرفته شده است و در واقع به کمک آن میتوان درخت عبارات را بسازیم و در نهایت از برگها شروع کنیم و تا ریشه درخت را محاسبه کنیم که مقدار ریشه در واقع همان مقدار عبارتی است که درخت آن تشکیل شده است.
- فایل parser درون خود توابع مربوط به ساخت درخت عبارات از یک رشته ورودی را دارد که در این فایل منطق ماشینحساب و اولویت عملیاتها و ... وجود دارد. همچنین در این فایل از پکیج calculate برای محاسبه مقادیر هر عبارت استفاده شده است.
- فایل arithmetic_exception نیز تنها یک کلاس از نوع Exception دارد که در واقع یک شخصی سازی از Exception میباشد تا اگر خواستیم در ارور متناسب نشان دهیم نیاز به تغییر دیگر قسمتهای کد نداشته باشیم و فقط در همین کلاس به شخصی سازی ارورها بپردازیم.
درابتدا این پکیج در برنچ feature/parser توسعه یافت و پس از مرج شدن با main با استفاده از برنچ refactor/parser به بهبود و ریفکتور آن پرداختیم. در این ریفکتور کردن، در برخی از بخشها توابع calculate را نیز به کار بردیم که پیش از آن با استفاده از lambda در پکیج parse پیادهسازی شده بود. همچنین در ابتدا نام این پکیج parser بود که طی این ریفکتور کردن به علت اینکه نام parser یک built-in در پایتون است، مجبور به تغییر نام این پکیج به parse شدیم.
- این پکیج تنها دارای یک فایل arithmetics میباشد که در آن توابع جمع، تفریق، ضرب و تقسیم به نحوی که نیاز بود پیادهسازی شده است و در نهایت نیز یک تابع برای منتاظر کردن عملیاتها با توابع مورد نظر گذاشته شده است که در پکیج parse از این پکیج برای ساخت درخت phrase و تعیین درست عملیات در عبارات استفاده میشود.
توسعه این پکیج در برنچ feature/calculate انجام شده و پس از آن با استفاده از مکانیزم pull request در گیتهاب با برنچ main ادغام گردیده است.
در این برنچ تمام کار روی readme پروژه انجام شده است که شامل توضیحات پکیجهای پروژه و همچنین افزودن سوالات خواسته شده در رابطه با گیت میباشد. در حین کار بر روی این برنچ چون دو نفر همزمان در حال کار کردن روی آن بودند، موقع push کردن روی این برنچ دچار کانفلیکت شدیم که درنهایت توانستیم آن را resolve کنیم.
پوشهی .git در یک مخزن گیت قرار دارد و شامل تمام اطلاعات لازم برای مدیریت نسخهها و تاریخچهی پروژه است. در این پوشه، اشیاء گیت (objects)، اشارهگرها (references)، فایل HEAD، فایل config و فایلهایی مانند index و logs ذخیره میشوند. پوشهی .git با استفاده از دستور "git init" در ریشهی پروژه ساخته میشود.
در atomic commit و atomic pull-request، عملیات atomic به معنای انجام یک تغییر یا مجموعهای از تغییرات به صورت یکپارچه و غیرقابل تجزیه است. در atomic commit، هر commit به صورت یک snapshot کامل از وضعیت پروژه در یک زمان خاص در نظر گرفته میشود و تغییرات آن به صورت کامل و همزمان اعمال میشوند. در atomic pull-request، همه تغییرات پیشنهاد شده در pull-request به صورت کامل قابل اعمال هستند، و اگر هر بخشی از تغییرات نتواند با موفقیت اعمال شود، تمام pull-request به عنوان نامعتبر در نظر گرفته میشود. مفهوم atomic در سیستمهای کنترل نسخه برای حفظ پایداری و قابلیت اعتماد کد بسیار مهم است.
دستورات Fetch، Pull، Merge و Rebase در گیت برای بهروزرسانی و ادغام تغییرات از ریموت یا شاخههای دیگر استفاده میشوند.
- دستور Fetch: تغییرات جدید را از ریموت دریافت میکند اما به صورت مستقیم در شاخه کاری اعمال نمیشوند. تغییرات در پوشهی .git ذخیره میشوند و میتوان با دستورات دیگر آنها را با شاخه کاری ادغام کرد.
- دستور Pull: ترکیبی از دستور Fetch و Merge است. ابتدا با دستور Fetch تغییرات را از ریموت دریافت کرده و سپس با دستور Merge آنها را با شاخه کاری ادغام میکند. در یک مرحله، تغییرات را به شاخه کاری میآورد.
- دستور Merge: تغییرات یک شاخه را با شاخهی فعلی ادغام میکند. یک commit جدید برای ادغام ایجاد میشود که تغییرات هر دو شاخه را شامل میشود.
- دستور Rebase: تغییرات را از یک شاخه بر روی شاخهی دیگر اعمال میکند. Rebase تغییرات را با استفاده از تغییرات موجود در شاخه هدف بازنویسی میکند و تاریخچه پروژه را بازنویسی میکند.
باید توجه داشت که در استفاده از این دستورات، مهم است که مناسبترین روش را بر اساس نیازهای پروژه انتخاب کنید و اصول تیمی را رعایت کنید. همچنین، تأثیرات احتمالی این دستورات را بر تاریخچه پروژه در نظر بگیرید.
- دستور restore:
از این دستور زمانی استفاده میشود که بخواهیم فایل یا فایلهایی را به نسخه قبلی خود که در زمان آخرین کامیت انجام شده برگردانیم. تغییراتی که کامیت نشدهاند، با این دستور حذف میشوند. در واقع به نوعی هر تغییری پس از آخرین کامیت حذف شده و کلا فایلهای مذکور به نسخه آخرین کامیت در میآیند. حال اگر بخواهیم تغییرات را نگه داریم و فقط از حالت stage خارج کنیم، باید در این دستور از فلگ --staged استفاده کنیم. در این صورت تغییرات انجام شده برگردانده نمیشوند. در واقع فایلهای مذکور تنها از حالت stage شده، خارج میشود ولی تغییرات آن باقی میمانند.
- دستور revert:
دستور revert برای مواقعی است که نیاز است همه چیز به یک کامیت قبل بازگردد. برخلاف دستور restore که یک سری فایل مشخصی که به آن میدهیم را به عقب برمیگرداند، برخی اوقات میخواهیم تمام فایلهای پروژه را به یک نسخه قبل باز گردانیم. مثلا اگر باگی در پروژه وجود دارد یا تغییراتی به اشتباه انجام شدهاند و نیاز است که کامیت اخیر را برگردانیم، از دستور revert استفاده میکنیم تا همه چیز به حالت یک کامیت قبل بازگردد. حال نکتهای که باید به آن توجه کرد این است که دستور revert کامیت را حذف نمیکند، بلکه کامیت جدیدی میسازد که شامل برعکس تغییرات انجام شده است. به این صورت که یک کامیت را میگیرد و یک کامیت جدید شامل معکوس تغییراتی که درون آن کامیت رخ داده میسازد. پس در واقع تغییری در تاریخچه کامیتها ایجاد نمیکند و تنها یک کامیت اضافه میشود.
- دستور reset:
همانطور که در بالا به آن اشاره کردیم، revert کامیتی را از تاریخچه حذف نمیکند. اما برخلاف دستور revert گاهی اوقات میخواهیم همه چیز حتی تاریخچه را نیز به کامیتی در گذشته برگردانیم. برای این کار میتوان از دستور reset استفاده کرد. در واقع این دستور برخلاف revert، واقعا کامیتهای قبلی را پاک میکند و تاریخچه را تغییر میدهد.
- مفهوم stage:
در ابتدا همه فایلها از نظر گیت جزو Untracked files (فایلهایی که گیت تغییرات آنها را دنبال نمیکند) هستند و باید آنها را به ریپازیتوری اضافه کرد. برای اینکار باید از دستور git add استفاده کنیم که در واقع فایل مذکور را به staging area میبرد.
به طور کلی تغییرات در ریپازیتوری ما سه مرحله دارند:
۱. تغییراتی که روی فایلهای لوکال خود انجام میدهیم.
۲. پس از آن باید تغییرات فایلها را stage کنیم که درواقع باید مشخص کنیم که از بین تغییرات مختلف کدام تغییرات را میخواهیم در کامیت بعدی در نظر بگیریم.
۳. در انتها نیز با دستور commit یک کامیت انجام میشود و تغییرات در گیت مشخص میشوند.
در واقع منظور از stage حالتی است که فایلها اگر وارد آن شوند، در کامیت بعدی این فایلهای stage شده لحاظ میشوند و تغییرات روی آنها به ریپازیتوری گیت وارد میشود.
- دستور stash:
گاهی اوقات در حال کار کردن روی یک برنچ هستیم و در مییابیم که مشکلی در برنچ دیگر وجود دارد و باید به حل آن بپردازیم. فرض کنید که تغییرات روی برنچ فعلی هنوز تکمیل نشده و نمیخواهیم آنها را کامیت کنیم. در این صورت اگر برنچ را عوض کنیم، تمام تغییراتی که روی برنچ فعلی دادهایم از دست میرود. برای اینکه این اتفاق نیفتد میتوانیم از دستور git stash استفاده کنیم که یک کپی از پروژه در یک برنچ میگیرد و به کامیت قبلی برمیگردد. حال میتوانیم به برنچهای دیگر برویم و هرگاه کارمان تمام شد و خواستیم به برنچ ابتدایی برگردیم، کافیست با دستور git stash apply تغییراتی که stash کرده بودیم را بازیابی کنیم. گیت این قابلیت میدهد که چندین کپی نیز از پروژه در نسخ مختلف داشته باشیم و هر کدام را که میخواهیم بتوانیم با دستور git stash apply name بازیابی کنیم. همچنین لیست کپی ها را میتوانیم با دستور git stash list مشاهده کنیم.
به طور کلی به حالت هر چیز (مانند فایل، دیتابیس و ...) در یک لحظه زمانی خاص snapshot میگویند که در مورد مبحث گیت نیز snapshot یک برنچ در واقع محتوای تمامی فایلهای گیت در آن برنچ در یک لحظه خاص است.