تمرین عملی گروهی
در این تمرین، شما و همتیمیتان نقش مهندسان نرمافزاری را بازی میکنید که روی هسته یک ماشین حساب کار میکنند. هدف این است که با چالشهای واقعی کار تیمی مثل Merge Conflict و History Rewrite دست و پنجه نرم کنید.
پیشنیاز: گروههای ۲ نفره تشکیل دهید (نفر اول: Maintainer، نفر دوم: Contributor).
مرحله ۱: راهاندازی اولیه
مسئولیت: نفر اول (Maintainer)
-
در گیتهاب یک ریپازیتوری Public با نام
git-workshop-calcبسازید. -
در تنظیمات ریپازیتوری (Settings > Collaborators)، نفر دوم را اضافه کنید.
-
نفر دوم باید دعوتنامه ایمیل شده را قبول کند.
-
هر دو نفر پروژه را روی سیستم خود
cloneکنند. -
نفر اول: یک فایل با نام
main.cبسازید و کد اولیه زیر را در آن قرار دهید، سپس Push کنید:
#include <stdio.h>
// Function declarations
int add(int a, int b);
int multiply(int a, int b);
int power(int base, int exp);
int main() {
printf("Calculator v1.0\n");
return 0;
}
از این لحظه به بعد، هیچکس حق ندارد مستقیماً روی برنچ main کامیت کند (Direct Commit ممنوع). همه تغییرات باید از طریق برنچ و Pull Request باشد.
مرحله ۲: توسعه موازی
در این مرحله هر دو عضو همزمان روی دو ویژگی مختلف کار میکنند.
وظایف:
-
نفر اول: برنچ
feature/addرا بسازد و تابعaddرا پیادهسازی کند. -
نفر دوم: برنچ
feature/multiplyرا بسازد و تابعmultiplyرا پیادهسازی کند.
دستور کار:
-
هر کس برنچ خود را بسازد (
git checkout -b ...). -
کد مربوطه را در انتهای فایل
main.cاضافه کنید. -
تغییرات را
addوcommitکنید. -
برنچ خود را به گیتهاب
pushکنید. -
در گیتهاب، یک Pull Request به سمت
mainباز کنید. -
PR نفر مقابل را بازبینی (Approve) کرده و سپس Merge کنید.
-
خیلی مهم: بعد از ادغام، هر دو نفر در سیستم خود دستور
git pull origin mainرا اجرا کنند تا کدهای یکدیگر را دریافت کنند.
مرحله ۳: ایجاد Conflict
حالا میخواهیم عمداً یک Merge Conflict ایجاد کنیم. هر دو نفر قرار است تابع power (توان) را پیادهسازی کنند، اما با روشهای متفاوت!
وظایف:
-
نفر اول: در برنچ
feature/power-loop، تابع توان را با حلقه (Loop) بنویسد. -
نفر دوم: در برنچ
feature/power-recursive، تابع توان را به صورت بازگشتی (Recursive) بنویسد.
دستور کار:
-
هر دو نفر برنچهای جدید را بسازند.
-
دقیقاً در یک محل مشخص از فایل
main.c(انتهای فایل)، تابعint power(...)را پیادهسازی کنند. -
هر دو نفر
commitوpushکنند. -
هر دو نفر Pull Request بسازند.
-
نفر اول PR خود را بدون مشکل Merge کند.
-
نفر دوم هنگام Merge با خطا مواجه میشود (چون خطوط فایل تغییر کردهاند).
حل Conflict (توسط نفر دوم):
-
در سیستم محلی، به برنچ خود بروید.
-
برنچ
mainرا در برنچ خود ادغام کنید:git merge main. -
فایل
main.cرا باز کنید. علائم<<<<<<<و=======را پیدا کنید. -
با مشورت همتیمی، یکی از پیادهسازیها (یا ترکیبی از هر دو) را نگه دارید.
-
فایل را ذخیره،
addوcommitکنید. -
دوباره
pushکنید و PR را در گیتهاب کامل کنید.
مرحله ۴: آزمایشگاه خرابکاری
حالا که پروژه کامل شد، بیایید کمی با ابزارهای بازگردانی بازی کنیم.
-
آخرین نسخه
mainرا دریافت کنید (git pull). -
در فایل
main.cیک تغییر خرابکارانه بدهید (مثلاً کل کدها را پاک کنید!). -
با دستور
git diffتغییرات را بررسی کنید و ببینید چه فاجعهای رخ داده. -
پشیمان شدید؟ با دستور زیر فایل را نجات دهید:
git restore main.c -
حالا یک خط کامنت به فایل اضافه کنید و آن را
commitکنید.
مرحله ۵: سفر در زمان
میخواهیم تاریخچه را دستکاری کنیم و سپس آن را نجات دهیم.
۱. تمیز کردن تاریخچه (Interactive Rebase):
-
دو کامیت الکی (مثلاً اضافه کردن خط فاصله) انجام دهید.
-
با دستور زیر، ۲ کامیت آخر را با هم یکی (Squash) کنید:
git rebase -i HEAD~2(در ادیتوری که باز میشود، جلوی کامیت دوم کلمه
pickرا بهsquashتغییر دهید).
۲. بازگشت به عقب (Hard Reset):
-
حالا فرض کنید کلاً پشیمان شدید و میخواهید به ۳ کامیت قبل برگردید:
git reset --hard HEAD~3 -
اوه نه! کامیتهای اصلی پروژه هم پریدند!
۳. عملیات نجات (Reflog):
-
نترسید. لیست تمام حرکتهایتان را ببینید:
git reflog -
هش (Hash) مربوط به زمانی که پروژه سالم بود (قبل از Reset) را پیدا کنید.
-
زمان را به عقب برگردانید:
git reset --hard <COMMIT_HASH>
پایان تمرین
اگر توانستید فایل main.c را سالم و شامل ۳ تابع (add, multiply, power) تحویل دهید، شما این تمرین را به پایان رساندهاید!
# وضعیت نهایی مورد انتظار در main.c
#include <stdio.h>
...
int main() { ... }
int add(...) { ... }
int multiply(...) { ... }
int power(...) { ... }