آموزش گیت پروژه محور
اگر آموزشهای خشک و فهرستوار Git باعث شدهاند دستورها را زود فراموش کنی، این دوره مسیر متفاوتی دارد. در «آموزش گیت پروژهمحور» قرار نیست فقط چند فرمان را حفظ کنی؛ از همان ابتدا وارد یک پروژه واقعی می
اهداف یادگیری
- درک مفاهیم پایه کنترل نسخه و نصب و پیکربندی گیت
- تسلط بر دستورات اصلی گیت (init, add, commit, status, log, diff)
- مدیریت حرفهای شاخهها (Branching) و ادغام تغییرات (Merging)
- حل اصولی تعارضات کدی (Merge Conflicts)
- کار با گیتهاب (GitHub)، مخازن ریموت، Push ،Pull و ثبت Pull Request
- استفاده از ابزارهای پیشرفته مانند Rebase, Stash, Reset, Revert و Cherry-pick
- کاربرد هوش مصنوعی در مدیریت مخازن گیت و نوشتن Commit پیامهای استاندارد
پیشنیازها
- آشنایی مقدماتی با کامپیوتر و مفاهیم اولیه برنامهنویسی
فصل 1: دعوت هدهد
درس 1: پروژهای که نسخه معتبرش گم شده
چهار فایل نهایی و یک تحویل نزدیک
قرار است وبسایت سفر سیمرغ تا یک ساعت دیگر به کاروان تحویل داده شود، اما اعضای تیم تغییرهایشان را با ساختن کپیهای تازه روی سیستم ذخیره کردهاند. حالا چهار فایل شبیه هم روی میز است و هیچکس دقیقاً نمیداند نسخه اصلی و معتبر کدام است!
final به نام فایلها هیچ تاریخچهای نمیسازد. در این دوره بهجای تکثیر فایلها، همان پروژه واحد را با Git مدیریت میکنی.چرا کپی دستی شکست میخورد؟ (منطق سیستمهای کنترل نسخه)
برای حل ریشهای این مشکل، ابزارهای سیستم کنترل نسخه (Version Control System) به وجود آمدند. منطق این ابزارها بسیار ساده اما فوقالعاده هوشمندانه است:
به جای اینکه برای هر تغییر کوچک کل پوشه یا فایل را کپی کنی، یک سیستم کنترل نسخه مانند Git از وضعیت کدها در لحظات کلیدی یک Snapshot (عکسبرداری از لحظه) میگیرد.
تکثیر فایل با اسامی تکراری؛ ایجاد سردرگمی شدید، نبود نویسنده، عدم امکان مقایسه و احتمال بالای نابودی کدها.
نگهداری یک پوشه واحد، ثبت عکسبرداری (Snapshot) هوشمند از تغییرات، مشخص بودن دقیق نویسنده و امکان سفر در زمان.
تکلیف سه مفهوم: Git، GitHub و نسخه پشتیبان
پیش از شروع کار باید مرز و نقش ابزارها کاملاً شفاف باشد. اشتباه گرفتن Git و GitHub یکی از رایجترین سوءتفاهمها میان تازهکاران است:
نرمافزاری که روی رایانه تو نصب میشود، ۱۰۰٪ آفلاین و بدون نیاز به اینترنت کار میکند و تاریخچه تغییرات را ثبت مینماید.
سرویس آنلاین ابری برای بارگذاری مخازن Git، پشتیبانگیری مطمئن، کدریویو و همکاری با سایر اعضای تیم.
وقتی کدی را با Git روی رایانه خود ثبت میکنی، این ثبت فقط در حافظه سیستم خودت قرار دارد. تا زمانی که آن را به سرویسی مثل GitHub آپلود (Push) نکنی، بهصورت آنلاین یا روی سیستم دیگران قرار نمیگیرد.
دعوت هدهد و مأموریت کاتب
در داستان منطقالطیر عطار، پرندگان پراکندهاند و مقصد مشخصی ندارند. هدهد در میان جمع حاضر میشود، سیمرغ را به عنوان پادشاه معرفی میکند و پرندگان را به سفری بزرگ به سوی کوه قاف دعوت مینماید:
هست ما را پادشاهی بیخلاف
در پس کوهی که هست آن کوه قاف
نام او سیمرغ، سلطان طیور
او به ما نزدیک و ما زو دور دور
تحویلگرفتن پروژه سفر سیمرغ
فایلهای همراه دوره در مخزن رسمی آموزش گیت پروژه محور قرار دارند. ابتدا بستهٔ شروع هنرجو را دانلود کن؛ اگر دانلود مستقیم باز نشد، صفحهٔ فایل ZIP را باز کن و Download raw file را بزن.
فقط همین بستهٔ شروع را بگیر؛ Code → Download ZIP کل مخزن رسمی را دانلود میکند و بستهٔ تمرین نیست. مخزن رسمی را برای شروع clone یا fork نکن؛ تاریخچهٔ پروژهٔ خودت را در درسها از صفر میسازی.
بسته اولیه دوره را استخراج کن و پوشه simorgh-journey را پیدا کن. در آغاز مسیر، تنها یک فایل آماده به نام index.html داخل پوشه قرار دارد:
دیدن نسخه تحویلی در مرورگر
پیش از انجام هر کاری، باید ظاهر فعلی وبسایت پروژه را مشاهده کنی تا نقطه شروع کار مشخص باشد.
simorgh-journey شو.index.html دو بار کلیک کن تا در مرورگر وب باز شود.بازکردن پروژه در VS Code
اگر VS Code نصب نیست، ابتدا نسخه سیستمعامل خودت را از وبسایت رسمی code.visualstudio.com دریافت و نصب کن. در رایانه مدیریتشده از مسئول سیستم کمک بگیر. افزونه، حساب کاربری یا آشنایی با HTML برای این تمرین لازم نیست.
برای ویرایش کدها و اجرای دستورات ترمینال، باید پوشه پروژه را در محیط VS Code باز کنیم.
simorgh-journey را انتخاب کرده و باز کن.| باز کردن ترمینال داخلی | Ctrl + ` |
simorgh-journey باید در پنل سمت چپ (Explorer) دیده شود. تمام دستورات این دوره در ترمینال همین پوشه اجرا میشوند.اطمینان از پوشه فعلی Terminal
دستورات Git همواره روی پوشهای اثر میگذارند که ترمینال در آن باز است. باید مطمئن شوی ترمینال دقیقاً داخل پوشه simorgh-journey قرار دارد.
simorgh-journey باشد. اگر مسیر دیگری را میبینی، مجدداً پوشه پروژه را با Open Folder باز کن.پیداکردن متن آماده تغییر
فایل index.html را در VS Code باز کن. میخواهیم متن وضعیت کاروان را پیدا کرده و نخستین تغییر واقعی پروژه را ایجاد کنیم.
| جستوجو در متن فایل | Ctrl + F / Cmd + F |
ثبت نخستین تغییر قابلمشاهده
اکنون متن پیدا شده را تغییر میدهیم تا حضور کاتب دیجیتال در پروژه ثبت شود.
تغییری که هنوز تاریخچه ندارد
جمله جدید در مرورگر دیده میشود و فایل روی دیسک ذخیره شده است. اما هنوز پوشه پروژه به یک Repository تبدیل نشده است.
اگر همین حالا فایل index.html بهطور تصادفی حذف شود یا کد آن خراب گردد، آیا Git میتواند نسخه قبلی را بازگرداند؟ چرا؟
پروژه واقعی روی میز است
درس 2: ابزار سفر روی رایانه
پر سیمرغ؛ نشانهای که باید آزمود
در داستان منطقالطیر، پرندگان هنوز سیمرغ را از نزدیک ندیدهاند و برای اطمینان از وجود او، نشانهای ملموس میطلبند. هدهد از پر زیبایی میگوید که هنگام پرواز سیمرغ بر سرزمین چین افتاد و دیدن آن نشانه، شوق سفر را در دل همه پرندگان برافروخت:
ابتدای کار سیمرغ ای عجب
جلوهگر بگذشت بر چین نیمشب
در میان چین فتاد از وی پری
لاجرم پُرشور شد هر کشوری
در دنیای توسعه نرمافزار، ما هرگز به آیکونهای روی صفحه یا ظاهر ویرایشگر اعتماد نمیکنیم. برنامهنویسان با اجرای یک فرمان ساده در ترمینال، آمادگی ابزار را بهطور قطعی میسنجند.
git --version در ترمینال است.سنجش Git پیش از نصب دوباره
خیلی از اوقات نرمافزار Git از قبل روی سیستمعامل (مثلاً ابزارهای Xcode در مک یا همراه ابزارهای دیگر) نصب شده است. بنابراین پیش از دانلود فایلهای سنگین، ابتدا حضور آن را آزمایش میکنیم.
راهنمای جامع نصب Git (متناسب با سیستمعامل)
اگر در گام قبلی مشخص شد Git نصب نیست، بر اساس سیستمعامل خود تنها یکی از روشهای زیر را دنبال کن:
اثبات نصب در ترمینال تازه (تازهسازی محیط Shell)
یکی از نکات مهمی که خیلی از برنامهنویسان تازهکار را سردرگم میکند این است که ترمینالهای قدیمی، متغیرهای محیطی سیستم را پس از نصب جدید خودکار بهروزرسانی نمیکنند.
git version در ترمینال جدید به این معنی است که سیستمعامل مسیر فایل اجرایی Git را کاملاً به حافظه سپرده است.پیداکردن مسیر فایل اجرایی Git (متغیر PATH)
سیستمعامل چگونه میداند وقتی دستور git را تایپ میکنی، کدام برنامه روی دیسک اجرا شود؟ این کار از طریق متغیری به نام PATH انجام میشود.
/usr/bin/git یا C:\Program Files\Git\cmd\git.exe) در خروجی، تایید میکند که ترمینال به برنامه Git دسترسی مستقیم دارد.راهنما و مستندات خودکار Git
هیچ برنامهنویسی در دنیا تمام پرچمها و دستورات فرعی Git را حفظ نمیکند! Git یک سیستم راهنمای عالی و داخلی همراه خود دارد:
| خروج از صفحه راهنما (Quit) | q |
| پیمایش صفحه به پایین | Space / Down Arrow |
| پیمایش صفحه به بالا | Up Arrow |
git help را بزنی و با کلید q خارج شوی.رفع خطای command not found
فرآیند نصب Git به پایان رسیده است، اما با تایپ دستور git در ترمینال هنوز خطای command not found یا unrecognized command ظاهر میشود. نخستین بررسیهای منطقی شما چیست؟
نشانه واقعی ابزار پیدا شد
درس 3: نویسنده تاریخچه مشخص میشود
هدهد پیامش را بینام نمیآورد
در داستان منطقالطیر عطار، پرندگان برای پیمودن راه سخت سیمرغ نیاز دارند بدانند راهنمایشان کیست و با چه اعتباری سخن میگوید. هدهد پیامش را بیشناسنامه و گمنام نمیآورد، بلکه خود را پیکی باتجربه و رازدار معرفی میکند که مسئولیت کلامش را میپذیرد:
گفت: ای مرغان! منم بی هیچ ریب
هم برید حضرت و هم پیک غیب
هم ز هر حضرت خبردار آمدم
هم ز فطنت صاحباسرار آمدم
در دنیای توسعه نرمافزار، وقتی دهها برنامهنویس روی یک پروژه بزرگ کار میکنند، هر تغییر (Commit) مثل برگی از شناسنامه پروژه است. اگر تغییری باعث ایجاد باگ شود یا نیاز به قدردانی از سازنده یک ویژگی باشد، سیستم باید بداند چه کسی آن تغییر را ایجاد کرده است.
عدم امکان پیگیری تغییرات، سردرگمی در عیبیابی و بیاعتمادی اعضای تیم
شفافیت کامل، مسئولیتپذیری، امکان قدردانی و پیوند با حسابهای کاربری
ثبت نام سراسری نویسنده (Global Name)
نخستین قدم برای معرفی خود به سیستم، ثبت نام و نام خانوادگی به صورت سراسری (Global) است. پرچم --global به Git میگوید: «این نام را برای تمام پروژههای من روی این رایانه به یاد داشته باش.»
با اجرای این فرمان، Git یک فایل متنی ساده به نام .gitconfig در پوشه اصلی کاربر سیستمعامل (Home Directory) میسازد یا بهروزرسانی میکند.
Ali Rezaei) وارد کن تا در تاریخچه پروژهها و سرویسهای آنلاین مثل GitHub کاملاً خوانا باشد.ثبت ایمیل سراسری نویسنده (Global Email)
پس از نام، باید ایمیل خود را ثبت کنی. Git از ایمیل شما برای اتصال کامیتها به آواتار شخصی (Gravatar) و پیوند دادن فعالیتهای شما به حساب پلتفرمهایی مانند GitHub یا GitLab استفاده میکند.
اگر تمایل نداری ایمیل واقعیات به صورت عمومی در پروژههای متنباز نمایش داده شود، میتوانی از ایمیل محرمانه noreply که GitHub در تنظیمات حساب کاربریات ارائه میدهد استفاده کنی.
بازخوانی و بازبینی شناسنامه ثبتشده
اگر مسیر رایانه مشترک را انتخاب کردهای، فعلاً فقط مفهوم بازخوانی را بخوان؛ نبود هویت شخصی در global طبیعی است. معیار نهایی، بازخوانی هویت مؤثر پس از تنظیم local در درس چهارم است.
پس از اجرای دستورات کانفیگ، چگونه مطمئن شویم اطلاعات به درستی ذخیره شدهاند؟ Git دستورات مشخصی برای استعلام مقادیر ذخیرهشده دارد:
سطوح سهگانه تنظیمات Git و منبع آنها
یکی از قدرتهای بزرگ Git، مدیریت هوشمندانه تنظیمات در سه سطح مختلف است. هر سطح، فایل کانفیگ مستقل خود را دارد:
انتخاب سطح درست برای پروژه کاری
فرض کن در رایانه شخصی خود پروژههای شخصیت را با ایمیل شخصی پیش میبری، اما یک مخزن پروژه شرکت ساختهای و میخواهی نام و ایمیل کاریات فقط در همان مخزن ثبت شود بدون اینکه تنظیم سایر پروژهها تغییر کند.
هویت ثبتشده، هویت تأییدشده نیست
آیا ثبت نام و ایمیل در Git به این معنی است که هویت شما کاملاً اثبات شده و شخص دیگری نمیتواند با نام شما کامیت بزند؟ نام و ایمیل معمولی دقیقاً چه ماهیتی دارند؟
شناسنامه کاتب آماده شد
simorgh-journey را با دستور git init به نخستین مخزن محلی (Repository) سفر تبدیل میکنیم.درس 4: آستانه وادی طلب
خواستن با نخستین قدم واقعی میشود
کاروان پرندگان به دهانه نخستین وادی از وادیهای هفتگانه منطقالطیر، یعنی «وادی طلب»، رسیده است. تا این نقطه، پرندگان فقط درباره مقصد (سیمرغ) شنیده و ابزار پرواز را سنجیدهاند، اما ورود واقعی به راه زمانی رخ میدهد که نخستین قدم برداشته شود. عطار دشواری و شکوه این آغاز را چنین توصیف میکند:
چون فرو آیی به وادی طلب
پیشت آید هر زمانی صد تعب
مال اینجا بایدت انداختن
ملک اینجا بایدت باختن
در دنیای برنامهنویسی، ساخت یک پوشه عادی به تنهایی کاری انجام نمیدهد. عمل واقعی در «وادی طلب»، اجرای فرمان git init است که آن پوشه معمولی را به یک مخزن محلی (Local Repository) زنده، هوشمند و قابل ردیابی تبدیل میکند.
عدم آگاهی از تغییرات فایلها، بدون دیتابیس تاریخچه و امکان بازگشت به گذشته
دارای پوشه مدیریتی مخفی git. و توانایی ثبت لحظات مهم پروژه
git init قرار نیست فایلهای پروژه شما را تغییر دهد یا چیزی را به اینترنت بفرستد؛ این فرمان فقط ساختار مدیریتی مخزن را در همین پوشه ایجاد میکند.دیدن وضعیت پیش از ساخت Repository
پیش از آنکه پوشه پروژه را به مخزن تبدیل کنیم، ابتدا وضعیت فعلی آن را استعلام میگیریم تا واکنش ترمینال را در حالت قبل از ساخت مخزن ببینیم.
ساخت مخزن محلی پروژه (git init)
اکنون وقت آن است که طلسم پوشه معمولی را بشکنی! در ترمینال و داخل ریشه پروژه simorgh-journey فرمان زیر را اجرا کن:
اگر رایانه مشترک است یا نمیخواهی تنظیمات دیگر پروژهها عوض شود، اکنون که مخزن ساخته شده نام و ایمیل واقعی انتخابی خودت را فقط همینجا تنظیم کن:
آنچه داخل پوشه مخفی .git میگذرد
با اجرای git init، یک پوشه مخفی به نام .git در پوشه پروژه ساخته میشود. این پوشه همان مغز و پایگاه داده Git است. فایل اصلی پروژه یعنی index.html بیرون آن در پوشه کاری (Working Tree) قرار دارد:
تحلیل و تفکیک اثر واقعی git init
اکنون که دستور git init را اجرا کردی و ساختار پوشه مخفی .git را دیدی، عمیقتر تحلیل کن: این دستور دقیقا چه چیزی روی دیسک ساخته و چه کارهایی را هنوز انجام نداده است؟
گزارش وضعیت مخزن پس از ساخت (git status)
حالا که مخزن محلی ساخته شده، فرمان git status را دوباره اجرا کن تا تغییر پیام ترمینال را در مقایسه با گام دوم ببینی:
git status صمیمیترین فرمان برنامهنویسان در Git است. هر زمان که در روند پروژه تردید داشتی، اجرای این دستور وضعیت دقیق را به تو نشان میدهد.خواندن نخستین گزارش کوتاه (git status --short)
گاهی اوقات که تعداد فایلهای پروژه زیاد میشود، خروجی کامل git status طولانی خواهد بود. Git یک پرچم فشرده به نام --short ارائه میدهد:
فایل در پوشه کاری هست، اما هنوز به index معرفی نشده و Git آن را ردیابی نمیکند.
فایل به دیتابیس Git معرفی شده و تغییرات آن تحت کنترل لحظهای است.
?? یعنی Git فایل index.html را حس میکند، اما تا زمانی که دستور git add را نزنی، مسئولیت ردیابی آن را بر عهده نمیگیرد.دیدن همان وضعیت در VS Code
رابط گرافیکی VS Code نیز همین وضعیت را به صورت بصری به شما نشان میدهد:
چرا Git فایلها را به صورت خودکار کامیت نمیکند؟
ممکن است این سوال برایت پیش بیاید که چرا Git پس از git init، فایل index.html را به صورت خودکار وارد تاریخچه نکرد و آن را در حالت Untracked باقی گذاشت؟
ذخیره خودکار مانند Google Docs که تمام خطوط و فایلهای موقت را بدون حق انتخاب ذخیره میکند.
برنامهنویس با دستور git add آگاهانه تصمیم میگیرد کدام فایلها و تغییرات وارد ثبت تاریخچه شوند.
git add اولین گام انتخاب آگاهانه فایلها را در ترمینال تجربه خواهیم کرد.چکلیست فنی پایان فصل
برای اطمینان از سلامت کامل محیط و آمادگی برای فصل بعد، این چهار استعلام ساده را در ترمینال پروژه اجرا کن:
نشان پر هدهد
فصل 2: وادی طلب
درس 1: نخستین Snapshot پروژه
ورود به وادی طلب و ضرورت ثبت لحظهها
کاروان پرندگان از دشتهای اولیه عبور کرده و وارد «وادی طلب» شده است. از این نقطه به بعد، هر حرکت باید آگاهانه و با دقت ثبت شود. کاتب کاروان نمیتواند سخنان را در باد رها کند؛ او باید هر دستاورد را در دفتری ماندگار حک کند. عطار این مرحله را چنین توصیف میکند:
چون فرو آیی به وادی طلب
پیشت آید هر زمانی صد تعب
جد و جهد اینجات باید سالها
زآن که اینجا قلب گردد حالها
در فصل قبل مخزن خالی Git را ساختیم، اما هنوز هیچ ثبت تاریخی صورت نگرفته است. در این درس، اولین عکس لحظهای Snapshot واقعی پروژه سفر سیمرغ را خلق میکنیم.
تغییرات زنده روی دیسک که هنوز در دیتابیس تاریخچه ثبت رسمی نشدهاند.
نسخه جاودانه و تغییرناپذیر ذخیرهشده در دیتابیس گیت با شناسه اختصاصی.
معماری سهمنطقهای Git (Working Tree, Index, HEAD)
برای دنبال کردن تغییرها، سه چیز را از هم جدا کن: Working Tree فایلهای روی دیسک است؛ Index / Staging Area نسخه انتخابشده برای commit بعدی؛ و Repository محل نگهداری اشیای تاریخچه در مخزن است.
HEAD نام دیتابیس یا منطقه ذخیرهسازی نیست؛ مرجع موقعیت فعلی توست که معمولاً شاخه فعال را دنبال میکند. پس از اولین commit، عبارت «مقایسه با HEAD» یعنی مقایسه با snapshot کامیت فعلی. پیش از اولین commit هنوز چنین snapshotی وجود ندارد.
مشاهده نقطه شروع و شاخه فعلی پروژه
پیش از آنکه نخستین کامیت را ثبت کنیم، وضعیت فعلی ترمینال را در پوشه simorgh-journey بررسی میکنیم:
git status --short گزارش خلاصه دو ستونه ارائه میدهد؛ ستون چپ مربوط به Index و ستون راست مربوط به Working Tree است.انتقال فایل به Index با دستور git add
اکنون وقت آن است که فایل اصلی پروژه را برای ثبت در کامیت بعدی آماده Stage کنیم. با اجرای دستور زیر، نسخه فعلی فایل وارد Index میشود:
ساخت فایل دوم پروژه و ثبت آن در Index
برای تمرین کار با چند فایل، یک فایل استایل ساده میسازیم. در VS Code فایلی به نام style.css بساز و متن زیر را در آن ذخیره کن:
تفاوت محتوای ثبتشده در Index با Working Tree
برای درک عمیق رفتار Index، این آزمایش عملی را انجام بده: به انتهای فایل style.css خط زیر را اضافه و ذخیره کن (اما فعلاً دستور git add را مجدداً اجرا نکن):
نسخه اول فایل (یک خطی) که قبلاً با git add در Index ثبت شده است.
تغییرات جدید (خط دوم) که روی دیسک ایجاد شده اما هنوز Stage نشده است.
git add اسم فایل را علامت نمیزند؛ بلکه عکس همان لحظه محتوای فایل را در Index ثبت میکند!بهروزرسانی Index با آخرین تغییرات (git add دوباره)
برای اینکه هر دو خط فایل style.css در کامیت نخست قرار گیرند، دستور git add را مجدداً روی این فایل اجرا میکنیم:
ثبت نخستین Commit پروژه (git commit)
حالا وقت آن است که پیشنویس موجود در Index را به عنوان اولین نقطه ثبت رسمی تاریخچه Commit ذخیره کنیم:
git status --short هیچ خروجی ارائه نمیدهد، یعنی تمام تغییرات Index با موفقیت در HEAD ثبت شدهاند و Working Tree کاملاً پاکیزه است.تنظیم شاخه اصلی روی main و استعلام شناسه HEAD
پس از ثبت نخستین کامیت، باید از یکسان بودن نام شاخه اصلی پروژه با استانداردهای مدرن صنعت نرمافزار (مانند GitHub و GitLab) مطمئن شویم. سیستمهای قدیمی گیت ممکن است نام پیشفرض را master بگذارند، اما در این دوره نام انتخابی مشترک main است.
اشارهگر HEAD مثل سنجاق «شما اینجا هستید» روی نقشه است که نشان میدهد هماکنون کدام کامیت و شاخه در پوشه کاری شما فعال است. همچنین هر کامیت یک شناسه اختصاصی ۴۰ کاراکتری SHA-1 Hash دریافت میکند که نمایش کوتاهش معمولاً حداقل ۷ کاراکتر است؛ طول نمایش کوتاه و الگوریتم هش میتواند متفاوت باشد.
تغییر نام قطعی شاخه جاری به main جهت یکپارچهسازی با استانداردهای گیتهاب
نمایش فشرده فقط ۱ کامیت اخیر به صورت تکخطی همراه با شناسه کوتاه و اشارهگرها
پیشبینی رفتار کامیت در تغییرات دوگانه
اگر برنامهنویسی فایلی را ویرایش کند، git add را بزند و سپس خط دیگری به همان فایل اضافه کند اما دوباره Stage نکند؛ هنگام اجرای git commit کدام نسخه ثبت میشود و خط دوم چه سرنوشتی دارد؟
ثبت نخستین نقطه ثبت پروژه
درس 2: گزارش آغاز حرکت
حرکت آگاهانه کاروان در نخستین وادی
پرندگان پس از گفتگوهای بسیار در «وادی طلب»، تصمیم میگیرند تماشاگر نمانند. هدهد پیش میافتد و جمع پراکنده را به کاروانی متعهد با یک مقصد مشترک تبدیل میکند. عطار لحظه این تصمیم را چنین روایت میکند:
چون شنودند این سخن مرغان همه
آن زمان گفتند ترک جان همه
عزم ره کردند عزمی بس درست
ره سپردن را باستادند چست
در توسعه نرمافزار، ساخت مخزن خالی کافی نیست؛ ما باید تغییرات واقعی را ثبت کنیم. هر کامیت خوب باید دارای یک هدف واضح و مشخص باشد و تمام فایلهای مربوط به آن هدف را یکجا در بر بگیرد.
کامیتهای خرد و بیهدف که عیبیابی تاریخچه پروژه را در آینده سخت میکنند.
ترکیب تمام فایلهای مربوط به یک مأموریت (مثلاً کد + لاگ) در یک ثبت واحد.
تشخیص وضعیت فایلهای Modified و Untracked
پیش از آنکه فایلها را به Staging Area / Index بفرستیم، باید نحوه نگاه گیت به تغییرات پوشه کاری Working Tree را بشناسیم:
git add هم برای فایلهای تغییریافته Modified و هم فایلهای تازه Untracked استفاده میشود تا آنها را آماده کامیت کند.بهروزرسانی وضعیت صفحه در فایل index.html
در نرمافزار VS Code فایل index.html را باز کن و خط زیر را پیدا کن:
همین متن را دقیقاً با جمله جدید زیر جایگزین و فایل را ذخیره کن:
مشاهده تغییرات در مرورگر و تایید صحت کارکرد
پیش از Stage کردن، همیشه خروجی زنده پروژه را بررسی میکنیم:
ساخت فایل لاگ متنی (journey-log.txt)
در ریشه پوشه پروژه simorgh-journey فایل جدیدی به نام journey-log.txt بساز و متن زیر را در آن ذخیره کن:
آموزش کاراکتر نقطه در git add . و کارکرد آن
وقتی چند فایل مرتبط دارید، به جای وارد کردن تکتک اسامی، میتوانی از کاراکتر نقطه (.) استفاده کنی. نقطه در ترمینال به معنای «پوشه جاری و تمام زیرپوشههای آن» است:
git add . استفاده کن که مطمئن باشی هیچ فایل موقت، محرمانه یا نامرتبطی در پوشه کاری Working Tree وجود ندارد!بازبینی پیشنویس آماده ثبت (git diff --staged)
پیش از اجرای کامیت، برنامهنویسان حرفهای همواره خلاصه محتوای موجود در Index را با دستور git diff --staged بازبینی میکنند:
ثبت کامیت دوم پروژه با پیام توصیفی
حالا پیشنویس آمادهشده را با یک پیام شفاف و انگلیسی کامیت میکنیم:
git status --short خروجی خالی ارائه میدهد، یعنی تمام تغییرات با موفقیت در دیتابیس ثبت شده و Working Tree کاملاً پاکیزه است.استعلام لاگ تاریخچه کامیتها (git log)
برای مشاهده تاریخچه ثبتشده و اطمینان از ترتیب زمانی کامیتها، دستور زیر را اجرا کن:
تحلیل ریسک استفاده بیمحابا از git add .
فرض کن در پوشه پروژه ۳ فایل تغییر کردهاند: دو فایل مربوط به مأموریت جدید و یک فایل شامل کلمه عبور شخصی یا فایل موقت (.env). چرا استفاده مستقیم از git add . در این شرایط یک خطای بزرگ مهندسی است؟
ثبت رویداد آغاز حرکت
git commit -am را بررسی میکنیم و محدودیتهای آن روی فایلهای جدید را به چالش میکشیم.درس 3: میانبر زیر فشار
حرکت پیوسته در میانه راه
کاروان وارد وادی طلب شده است و هدهد باید وضعیت مسیر را مرتب به پرندگان گزارش کند. برخی پیامها کوچک و فوریاند، اما شتاب در حرکت نباید باعث ثبت فایلهای نامرتبط یا آشفته در تاریخچه شود.
مرد باید کز طلب در انتظار
هر زمانی جان کند در ره نثار
نه زمانی از طلب ساکن شود
نه دمی آسودنش ممکن شود
عطار در حکایت شبلی، طلب را حرکتی پیوسته میبیند؛ جستوجوگر راه حتی برای لحظهای از توجه به مسیر دست نمیکشد. در این گام یک میانبر کاربردی به نام git commit -am را میآزمایی و پیش از استفاده میفهمی چه فایلهایی را وارد Commit میکند و چه فایلهایی را کنار میگذارد.
کالبدشکافی پرچم -am
فرمان git commit -am ترکیب دو پرچم پرکاربرد است:
-a تنها فایلهای تغییریافته Modified و یا حذفشدهای را Stage میکند که از قبل توسط گیت شناسایی شدهاند. هرگز فایلهای پیگیرینشده Untracked را وارد Commit نمیکند!مقایسه میانبر با روش دو مرحلهای
کنترل کامل و تفکیک دقیق فایلها پیش از ثبت. مناسب برای زمانی که چند فایل تغییر کردهاند اما فقط میخواهی برخی از آنها را ثبت کنی.
سرعت بالا در یک خط. تنها برای زمانی مناسب است که همه فایلهای تغییریافته Tracked مربوط به یک هدف مشخص باشند.
-am مرحله Staging Area را حذف یا دور نمیزند؛ بلکه گیت به صورت پنهانی ابتدا git add را روی فایلهای Tracked اجرا کرده و سپس اقدام به ایجاد Commit میکند.اعمال تغییر روی فایل Tracked و تست میانبر
در فایل index.html وضعیت فعلی را پیدا کن:
آن را با متن زیر جایگزین و فایل را ذخیره کن:
حالا استعلام وضعیت کوتاهنوشت را بگیرید:
فایل index.html با علامت قرمز M دیده میشود (Modified). حالا میانبر را اجرا کن:
index.html را به صورت خودکار Stage کرد و Commit جدید را ساخت.ساخت فایل جدید و تجربه شکست میانبر
اکنون یک فایل جدید در ریشه پروژه بساز تا رفتار میانبر را روی فایلهای پیگیرینشده Untracked بیازمایی.
فایل تازه supplies.txt را بساز و متن زیر را در آن ذخیره کن:
استعلام وضعیت بگیرید تا علامت ?? را ببینی:
اکنون عمداً تلاش کن این فایل تازه را با میانبر ثبت کنی:
چرا فایل جدید از میانبر جا ماند؟
گزینه -a صرفاً پروندههایی را که قبلاً شناسنامه Tracked گرفتهاند اسکن میکند. برای این که یک فایل تازه وارد این چرخه شود، باید حداقل یکبار به صورت صریح با فرمان git add به گیت معرفی گردد.
ثبت صریح فایل جدید
برای حل این مشکل، فایل تازه را به روش صریح دو مرحلهای آمادهسازی و ثبت کن:
بررسی کن:
supplies.txt از این پس به یک فایل Tracked تبدیل شد.supplies.txt تغییر کند، استفاده از میانبر git commit -am روی آن کار خواهد کرد!خطر میانبر در تغییرات همزمان
سناریویی را تصور کن که در آن همزمان دو فایل index.html و style.css را دستکاری کردهای و هر دو در وضعیت Modified هستند.
اگر کار شما روی index.html تمام شده باشد اما استایلها هنوز نیمی کاره باشند، اجرای ناآگاهانه میانبر زیر چه خطری دارد؟
-a بدون استثنا تمام فایلهای Tracked تغییریافته را وارد این Commit میکند؛ بنابراین استایلهای نیمهکاره شما نیز ناخواسته ثبت میشوند!git add index.html استفاده کن تا فقط فایل آمادهشده ثبت گردد.سنجش دقیق رفتار -am
اگر دو فایل تغییریافته Tracked و یک فایل جدید Untracked در پروژه داشته باشیم و فرمان git commit -am اجرا شود، چه اتفاقی میافتد؟
میانبر اکنون قابلکنترل است
اکنون Repository شما دارای چند نقطه ثبت شده واقعی است. در درس بعدی مسیر طیشده را با استعلام لاگ git log پیمایش و جزییات یک Commit را بررسی خواهیم کرد.
درس 4: ردگیری یک تغییر در تاریخچه
راهی که پشت سر مانده
کاروان در وادی طلب چند نشانه واقعی ساخته است: صفحه آغاز سفر، گزارش حرکت و فهرست آذوقه. حالا هدهد از کاتب میپرسد: «دقیقاً در کدام نقطه، وضعیت سفر وارد وادی طلب شد؟» پاسخ این پرسش در فایلهای امروز نیست؛ باید رد پای ثبتهای گذشته را دنبال کنیم.
گر تو هم روزی فروآیی به راه
عقبهٔ آن ره کنی یک یک نگاه
بازدانی آنچ ایشان کردهاند
روشنت گردد که چون خون خوردهاند
عطار میگوید فهم رنج راه با نگاهکردن به عقبههایی ممکن میشود که مسافر یکییکی پشت سر گذاشته است. تاریخچه گیت هم راه پیمودهشده پروژه را به ترتیب Snapshotهای ثبتشده نشان میدهد. در این درس با ابزارهای git log و git show تاریخچه را رمزگشایی میکنیم.
معماری و اجزای یک کامیت
هر Commit در دیتابیس گیت یک شیء مستقل و تغییرناپذیر است که از چهار بخش اصلی تشکیل میشود:
نقشه فشرده سفر با git log --oneline
برای دیدن تمام ثبتهای پروژه از جدیدترین به قدیمیترین در یک نمای تکخطی و فشرده، دستور زیر را اجرا کن:
استعلام شناسنامه کامل با git log -1
اگر بخواهی جزییات کامل و شناسنامه تازهترین Commit را مشاهده کنی، از پرچم محدودکننده -1 استفاده کن:
خروجی را بررسی کن: کد هش ۴۰ کاراکتری، نام نویسنده، تاریخ کامل و متن پیام نمایش داده میشوند.
دیدن گراف خطی با git log --graph
برای مشاهده ساختار درختی و پیوندهای میان Commitها، نمای گرافی لاگ را اجرا کن:
چون تا این لحظه شاخه فرعی نساختهایم، یک خط مستقیم متصل را میبینی که تمام نقاط ثبتشده را به ترتیب زمانی نشان میدهد و آخرین نقطه با برچسب HEAD -> main علامت خورده است.
محدود کردن تعداد لاگ با پرچم -n
در پروژههای بزرگ با هزاران ثبت، دیدن کل لاگ کارآمد نیست. با پرچم -n میتوانی تعداد سطرها را محدود کنی:
اکنون تنها ۳ کامیت اخیر نمایش داده شده و کامیتهای قدیمیتر پنهان میشوند. این پرچم چیزی را پاک نمیکند، فقط نمای نمایش را محدود میسازد.
نمایش معکوس تاریخچه با git log --reverse
برای بررسی روند سفر از نقطه آغاز تا به امروز، ترتیب نمایش لاگ را معکوس کن:
نخستین کامیت پروژه با پیام Create initial journey website در سطر اول ظاهر میشود. هش کوتاه ۷ کاراکتری آن را کپی کن؛ در گام بعدی با آن کار داریم.
ذرهبین git show و بررسی جزئیات یک کامیت
عبارت COMMIT_HASH جاینگهدار است. پیش از اجرا، آن را با شناسه واقعی اولین commit که در قدم قبل یادداشت کردی جایگزین کن؛ خود کلمه COMMIT_HASH نام یک commit نیست.
برای باز کردن یک Commit مشخص و مشاهده کدها و تغییرات دقیق آن، از فرمان git show استفاده کن:
تفاوت git log و git show
هدهد میخواهد اول کامیت درست را پیدا کند و بعد تغییرهای همان کامیت را ببیند. در یک یا دو جمله توضیح بده git log و git show چه نقش متفاوتی در این مسیر دارند.
تحویل سالم وادی طلب
پیش از ترک وادی طلب، وضعیت کلی پروژه و ثبتهای اخیر را یکجا کنترل کن:
نشان خواننده تاریخچه و پایان وادی طلب
git add . و git diff --staged.git commit -am و درک مرزهای آن.git log و بررسی کدهای یک کامیت با git show.فصل 3: وادی عشق
درس 1: آینه پیش از ثبت
ورود به آتش وادی عشق
کاروان از وادی طلب گذشته و به سرزمینی رسیده است که هر تصمیم در آن با شور و شتاب همراه میشود. هدهد از کاتب میخواهد پیش از ثبت هر خبر، آن را در آینه دقیق ببیند؛ چرا که هیجانِ تغییر میتواند یک اشتباه کوچک را هم وارد تاریخچه پروژه کند.
بعد ازین وادی عشق آید پدید
غرق آتش شد کسی کانجا رسید
کس درین وادی به جز آتش مباد
وانک آتش نیست عیشش خوش مباد
عطار وادی عشق را با آتشی آغاز میکند که مسافر را بیتفاوت نمیگذارد. در پروژه نرمافزاری هم تغییر لازم است، اما مهندس واقعی پیش از اجرای Commit چشمانش را به تفاوت نسخهها میدوزد. در این مأموریت با ابزار git diff یاد میگیریم چطور تغییرات پوشه کاری Working Tree را خطبهخط بخوانیم.
کالبدشکافی مرز git diff
فرمان git diff بدون پرچم اضافی، پوشه کاری Working Tree را با محیط آمادهسازی Index / Staging Area مقایسه میکند:
diff --git a/file b/file — مشخصکننده نام فایل قدیمی و نسخه جدید روی دیسک.+ و - — خطوط قرمز با علامت - نشاندهنده حذف و خطوط سبز با علامت + نشاندهنده اضافه شدن هستند.رسیدن کاروان به وادی عشق
در نرمافزار VS Code فایل index.html را باز کن و خط زیر را پیدا کن:
همین متن را دقیقاً با جمله جدید زیر جایگزین و فایل را ذخیره کن:
صفحه را در مرورگر وب Refresh کن. با دیدن وضعیت تازه مطمئن میشوی تغییر روی دیسک در پوشه کاری Working Tree درست ذخیره شده است.
ساخت گزارش قابلردگیری سفر
محتوای فعلی فایل journey-log.txt را با گزارش ساختاریافته زیر جایگزین و ذخیره کن:
git add را اجرا نکن. هر دو تغییر باید فقط در Working Tree باقی بمانند.استعلام وضعیت و نماد M قرمز
وضعیت فشرده ترمینال را بررسی کن:
خواندن Patch واقعی با git diff
برای دیدن تغییرات خطبهخط، فرمان زیر را اجرا کن:
به خطوط قرمز با علامت - و خطوط سبز با علامت + توجه کن. بخشهای با علامت @@ همان Hunk یا تکه تغییرات هستند.
تمرکز روی صفحه اصلی با git diff -- filename
وقتی چند فایل تغییر کردهاند، میتوانی با اضافه کردن جداکننده -- و نام فایل، فقط تغییرات همان فایل را ایزوله کنی:
علامت -- به گیت میگوید عبارت بعدی نام مسیر فایل است، نه نام شاخه Branch یا Commit.
اندازه مأموریت در یک نگاه (git diff --stat)
برای دیدن آمار خلاصهشده تغییرات بدون نمایش متن کامل کدها، از پرچم --stat استفاده کن:
+ — تعداد سطرهایی که در پوشه کاری جدید اضافه شدهاند.- — تعداد سطرهایی که پاک یا ویرایش یافتهاند.تغییری که در آینه دیده نمیشود
کاتب فایل تازهای ساخته و در git status --short آن را با علامت ?? میبیند، اما git diff هیچ متنی برای آن نشان نمیدهد. چرا؟
تغییرها دیده شدند، نه ثبت
git diff -- filename.git diff --stat.درس 2: انتخاب تکههای همهدف
ماهی میان دو سوی تغییر
کنار راه وادی عشق، ماهی کوچکی بیرون آب میتپید. هدهد از کاروان خواست فقط ظاهر حرکتش را نبینند؛ مهم این بود که ماهی اکنون کجاست و برای رسیدن به جای درستش از کدام مرز باید بگذرد.
میتپد پیوسته در سوز و گداز
تا بجای خود رسد ناگاه باز
ماهی از دریا چو بر صحرا فتد
میتپد تا بوک در دریا فتد
عطار بیقراری ماهی برای بازگشت به جای خود را چنین تصویر میکند. تغییرهای پروژه نیز ممکن است در Working Tree یا Index قرار داشته باشند. در این درس با سه مقایسه جای دقیق هر تغییر را پیدا میکنی و دو اصلاح مستقل در یک فایل را به دو Commit منسجم و شفاف تقسیم مینمایی.
سه پنجره برای سه مرز diff
برای آن که بدانی کدها در چه مرحلهای از چرخه گیت هستند، سه دستور اصلی مقایسه وجود دارد:
--cached کاملاً هممعنای پرچم --staged است و هر دو تغییرات موجود در Index را نسبت به HEAD میسنجند.مفهوم آمادهسازی تکهای (git add -p)
گاهی در طول یک روز کاری، چند بخش مختلف از یک فایل را دستکاری میکنی (مثلاً هم یک باگ را برطرف میکنی و هم استایل جدید مینویسی). آیا باید همه را در یک کامیت آشفته ثبت کنی؟
git addتمام تغییرات فایل یکجا Stage میشوند، حتی اگر مربوط به دو موضوع کاملاً نامرتبط باشند.
گیت تغییرات فایل را به تکههای کوچک Hunk تقسیم کرده و اجازه میدهد هر تکه را جداگانه Stage کنی.
فرستادن فقط صفحه به Index و تست مرزها
از دو فایل تغییرکرده، فعلاً فقط فایل index.html را Stage کن و دو مقایسه را پشت سر هم ببین:
دیدن هر دو سوی پروژه با --stat
حالا مرزها را در مقیاس کل پروژه و به صورت خلاصهشده مقایسه کن:
دستور اول فقط journey-log.txt را نشان میدهد (غیرآماده)، دستور دوم فقط index.html را (آماده) و دستور سوم هر دو فایل را به طور همزمان نمایش میدهد.
پیداکردن جای هر تغییر در معماری سه منطقهای
پس از Stage شدن index.html و Stage نشدن journey-log.txt، چرا git diff فقط گزارش سفر را نشان میدهد ولی git diff HEAD هر دو فایل را میبیند؟
ثبت ورود کاروان به وادی عشق
گزارش سفر را هم Stage کن، عکس کامل آمادهشده را بازبینی کرده و ثبت کن:
ایجاد دو تغییر مستقل در یک فایل
در فایل journey-log.txt دو جای مختلف و دور از هم را ویرایش کن:
۱. خط Map: Draft را به Map: Reviewed تغییر بده.
۲. خط Song: Draft را به Song: Final تغییر بده و فایل را ذخیره کن.
سپس تفاوت متنی را مشاهده کن:
فاصله میان این دو خط باعث میشود گیت آنها را به عنوان دو تکه Hunk مجزا شناسایی کند. این دو تغییر به دو هدف مستقل تعلق دارند.
انتخاب تعاملی تکهها با git add -p
برای اینکه تنظیمات شخصی نمایش diff دو تکه دور از هم را یکی نکند، در همین فرمان فاصله نمایشی را مشخص میکنیم؛ این گزینههای -c تنظیمات دائمی تو را تغییر نمیدهند.
حالا حالت تعاملی پچ را برای این فایل فعال کن:
یک فایل در دو وضعیت و ثبت کامیتهای جداگانه
محتوای دو سوی فایل را جداگانه بازبینی کن:
دستور اول فقط تغییر Map را در Index نشان میدهد و دستور دوم تغییر Song را در Working Tree میبیند. حالا کامیت اول را ثبت کن:
سپس تغییر باقیمانده را Stage کرده و کامیت دوم را بساز:
Index به ابزار هوشمند انتخاب تبدیل شد
git add -p برای تفکیک Hunkهای نامرتبط..gitignore از چشم گیت پنهان نگه داریم.درس 3: رازهای محلی کاروان
طوطی و راز آب حیات
طوطی سبزپوش جلو آمد و از آب حیات گفت؛ رازی که میخواست فقط برای خودش نگه دارد. هدهد میان مقصد مشترک کاروان و خواستههای شخصی طوطی تفاوت گذاشت: هر چیزی که همراه مسافر است، لازم نیست وارد دفتر مشترک سفر شود.
طوطی آمد با دهان پر شکر
در لباس فستقی با طوقِ زر
من در این زندانِ آهن مانده باز
زآرزوی آب خضرم در گداز
عطار ظاهر زیبا و آرزوی پنهان طوطی را کنار هم میآورد. این حکایت در پروژه یادآور فایلهای محلی و تنظیمات شخصی است؛ فایلهایی که وجودشان روی رایانه شما لازم است، اما نباید وارد دیتابیس عمومی Repository شوند.
فیلتر انتخاب، نه گاوصندوق
فایل .gitignore متنی شامل الگوهای متنی Ignore Pattern است که نحوه تعامل گیت با فایلهای نادیدهگرفتهشده را مشخص میکند:
.gitignore یک ابزار امنیتی یا رمزنگاری نیست! اگر کلید محرمانه یا کلمه عبوری را اشتباهاً کامیت کردهاید، تنها نادیده گرفتن آن کافی نیست و باید بلافاصله آن کلید را باطل و جایگزین کنید.ساخت دو فایل محلی و موقت
در ریشه پروژه فایل .env.local را بساز و مقدار نمایشی زیر را در آن ذخیره کن:
فایل دوم را با نام cache.tmp بساز و متن زیر را قرار بده:
دیدن فایلهای ناخواسته پیش از فیلتر
پیش از تعریف قوانین پنهانسازی، استعلام وضعیت ترمینال را بررسی کن:
git add . بدون بازبینی اجرا شود، هر دو فایل ناخواسته وارد Staging Area خواهند شد.نوشتن نخستین قوانین Ignore
در ریشه پوشه پروژه فایلی به نام .gitignore بساز و این دو الگو را در آن ذخیره کن:
پیداکردن قانونی که فایل را پنهان کرد با git check-ignore
گزارش وضعیت و دلیل دقیق پنهان شدن فایلها را با ابزار git check-ignore عیبیابی کن:
در خروجی دستور اول، فقط خود فایل .gitignore با علامت ?? دیده میشود. خروجی دستور دوم نام فایل قوانین، شماره خط و الگوی دقیق نادیدهگرفتهشدن هر فایل را نشان میدهد.
قانون ویژه پوشه موقت ریشه (/temp/)
این خط جدید را به انتهای فایل .gitignore اضافه کن:
سپس در ریشه پروژه پوشهای به نام temp بساز و فایلی به نام route.txt داخل آن ایجاد کن:
/ الگو را به ریشه مخزن محدود میکند و اسلش پایانی نشان میدهد این قانون مخصوص یک پوشه Directory است.آزمون امن git add .
حالا با خیال راحت دستور انتخاب همهجانبه را اجرا کرده و ورود فایلها را بررسی کن:
A .gitignore وارد Index شده است و فایلهای محلی نادیدهگرفتهشده روی دیسک باقی مانده اما وارد Stage نشدند!رازی که قبلاً وارد تاریخچه شده
فایل config.env قبلاً کامیت شده و اکنون نامش به .gitignore اضافه شده است. چرا گیت هنوز تغییرات آن را ردیابی میکند و برای یک راز واقعی چه کارهایی لازم است؟
ثبت قوانین مشترک پروژه
محتوای آمادهشده فایل قوانین را بازبینی و در یک Commit ثبت کن:
.gitignore خود بخشی از کد پروژه است که با سایر اعضای تیم به اشتراک گذاشته میشود. اکنون Working Tree کاملاً پاکیزه است.رازها از دفتر مشترک بیرون ماندند
/temp/،git restore پوشه کاری را به نسخه امن بازگردانیم.درس 4: بازگرداندن آواز درست
بلبل و دلبستگی ناپایدار
بلبل چنان شیفته گل شده بود که هیچ راه دیگری را نمیدید. هدهد به او گفت زیبایی گل ماندگار نیست و مسافر باید بتواند انتخابی را که از مسیر دورش میکند کنار بگذارد.
هدهدش گفت: ای به صورت مانده باز!
بیش از این در عشق رعنایی مناز
گل اگر چه هست بس صاحبجمال
حسن او در هفتهای گیرد زوال
در پروژه نیز گاهی یک ویرایش اشتباه یا حذف ناخواسته مانند یک وابستگی زودگذر باید کنار گذاشته شود. پاسخ هدهد به بلبل، همین تشخیص و بازگشت آگاهانه را یادآوری میکند.
منبع و مقصد git restore
دستور git restore PATH دارای دو جهت مشخص در معماری گیت است:
اگر فایلی هنوز Stage نشده باشد، محتوای Index با آخرین کامیت HEAD یکسان است؛ در نتیجه بازیابی، فایل را به حالت آخرین Commit برمیگرداند.
git restore تغییرات محلی ذخیرهنشده در پوشه کاری را کاملاً جایگزین میکند و قابل بازگشت نیست. همچنین فایلهای Untracked نسخهای در Index ندارند و با این دستور دستکاری نمیشوند.ساخت یک پیام آشکارا اشتباه
برای تجربه عملکرد بازسازی، ابتدا یک تغییر اشتباه محلی در پوشه کاری ایجاد میکنیم.
عبارت بالا را با پیام اشتباه زیر جایگزین کرده و فایل را ذخیره کن:
index.html را در VS Code باز کن.Status: ROUTE DATA LOST. جایگزین کن.git add را اجرا نکن تا تغییر صرفاً در Working Tree باقی بماند.دیدن چیزی که قرار است حذف شود
پیش از بازگرداندن فایل، همواره باید تغییرات ایجادشده را عیبیابی و بررسی کنی تا محتوای باارزشی را اشتباهاً پاک نکنی.
- متن قبلی و سطر سبز با علامت + پیام اشتباه را نشان میدهد.-- در دستور diff، مسیر فایل را از آرگومانها و گزینههای گیت تفکیک میکند.پیشبینی نسخه بازسازیشده
هیچ تغییری Stage نشده و محتوای Index با HEAD یکسان است.
اگر اکنون دستور git restore index.html اجرا شود، کدام نسخه وارد Working Tree میشود و چه بلایی سر پیام اشتباه میآید؟
بازیابی صفحه و تأیید در مرورگر
پس از اطمینان از اشتباهبودن تغییر، با دستور زیر فایل را به حالت سالم Index بازگردان:
git restore index.html را در ترمینال اجرا کن.git status --short را بزن؛ خروجی باید کاملاً خالی باشد.index.html را در مرورگر Refresh کن.Status: The caravan has entered the Valley of Love. دوباره در مرورگر ظاهر شد و تغییر ناخواسته پاک گردید.بازسازی فایل حذفشده
دستور git restore تنها برای لغو ویرایش خطوط نیست؛ اگر فایلی که در گیت Tracked است به طور کامل از روی دیسک حذف شود نیز میتوان آن را بازسازی کرد.
فایل style.css را از پنل فایلهای VS Code یا ترمینال حذف کن، سپس وضعیت را استعلام کرده و آن را بازیابی کن:
D style.css را نمایش میدهد.style.css دوباره روی دیسک ظاهر شده و خروجی status خالی میشود.style.css در Index ذخیره شده بود و Git توانست آن را روی دیسک بازنویسی کند.دامنه نقطه در دو فایل
وقتی در چندین فایل تغییرات آزمایشی ایجاد کردهای، میتوانی همه آنها را یکجا با پرچم نقطه . لغو کنی.
در journey-log.txt عبارت Weather: Clear را به Weather: Storm تغییر بده و کل محتوای supplies.txt را با عبارت زیر جایگزین کن:
. فایلهای نادیدهگرفتهشده (Ignored) یا پیگیرینشده (Untracked) را حذف نمیکند؛ بلکه صرفاً مسیرهای قابلبازسازی از Index را هدف میگیرد.فایل تازه بدون نسخه پشتیبان
فرض کن فایلی جدید به نام draft.txt در پروژه ساختهای که هنوز Untracked است و هرگز به گیت معرفی نشده است.
error: pathspec draft.txt did not match any file(s) known to gitبازگشت اکنون یک تصمیم آگاهانه است
git diff پیش از بازگرداندنgit restoregit restore .git restore --staged آن را از Index خارج کنیم بدون اینکه ویرایش فایل روی دیسک از دست برود.درس 5: پسگرفتن انتخاب شتابزده
برگهای که زود روی میز رفت
در واپسین منزل وادی عشق، کاتب مقصد بعدی کاروان را روی گزارش نوشت و پیش از بازبینی نهایی، برگه را روی میز آمادهسازی گذاشت. نوشته کاملاً درست بود؛ فقط هنوز زمان ثبت رسمیاش نرسیده بود.
این بار قرار نیست نوشته روی برگه را پاک کنیم. هدف این است که برگه را از روی میز آمادهسازی Staging Area برداریم، محتوا را روی دیسک Working Tree نگه داریم و پس از بازبینی کامل درباره Commit تصمیم بگیریم.
دو Restore با دو مقصد
فرمان git restore بر اساس پرچم ورودی، دو مقصد کاملاً متفاوت در معماری گیت دارد:
مقصد: Working Tree
منبع: Index
تغییرات محلی روی دیسک را پاک کرده و فایل را از Index بازنویسی میکند.
مقصد: Index
منبع: HEAD
انتخاب Stage را لغو کرده اما فایل روی دیسک را دستنخورده نگه میدارد.
در گذشته دستور git reset HEAD PATH برای این کار استفاده میشد، اما معرفی پرچم --staged در دستور جدید git restore قصد دقیق مهندس را شفافتر نشان میدهد.
--staged هرگز محتوای فایل شما در Working Tree را دستکاری یا پاک نمیکند؛ صرفاً آن را از صف ثبت خارج میسازد.نوشتن مقصد بعدی
ابتدا تغییر واقعی مقصد کاروان را در گزارش سفر ایجاد میکنیم.
سطر بالا را با عبارت مقصد وادی بعدی جایگزین کرده و فایل را ذخیره کن:
journey-log.txt را در VS Code باز کن.Next checkpoint: Unknown را پیدا کرده و به Next checkpoint: Valley of Knowledge تغییر بده.دیدن نسخهای که زود آماده شد
فایل را به محیط آمادهسازی اضافه کن و وضعیت Stage آن را بررسی نما:
--staged به گیت میگوید فقط تغییرات موجود در Index را مقایسه کن، نه تغییرات غیرآماده پوشه کاری را.برداشتن فایل از Index
فرض کن تصمیم گرفتهای این تغییر هنوز وارد کامیت نشود. فقط انتخاب Stage را پس بگیر:
پشت صحنه چه اتفاقی افتاد؟ Git نسخه journey-log.txt موجود در Index را از آخرین کامیت HEAD بازسازی کرد. اما فایل روی دیسک در Working Tree دستنخورده باقی ماند.
اثبات باقیماندن نوشته
برای اینکه با چشمان خودت ببینی نوشته روی دیسک باقی مانده، هر دو سوی تغییر را استعلام کن:
کدام لایه تغییر میکند؟
فرق حیاتی git restore journey-log.txt با git restore --staged journey-log.txt چیست و کدامیک میتواند نوشته روی دیسک را از بین ببرد؟
Unstage کردن چند مسیر با نقطه
وقتی چندین فایل را اشتباهاً Stage کردهای، میتوانی همه آنها را یکجا با پرچم نقطه . Unstage کنی.
در فایل supplies.txt سطر فعلی را موقتاً با متن زیر جایگزین کن:
. تمام فایلهای Stageشده در پوشه جاری و زیرپوشهها را از Index خارج میکند، اما هیچ تغییری را از روی دیسک پاک نمیکند.ثبت مقصد و کنارگذاشتن شتاب
اکنون تغییر موقت آذوقه را از دیسک پاک کن، اما تغییر مقصد واقعی را Stage و کامیت کن:
git restore supplies.txt تغییر آزمایشی آذوقه را از دیسک پاک کن.git add journey-log.txt فقط گزارش مقصد واقعی را Stage کن.git diff --staged -- journey-log.txt صحت تغییر آماده ثبت را تأیید کن.git commit پیام کامیت را ثبت نما.تحویل پاک وادی عشق
پیش از پایان فصل سوم، صحت شاخه، وضعیت پوشه کاری و آخرین کامیتهای پروژه را استعلام کن:
main باشی.Set next checkpoint to Valley of Knowledge باید در بالای تاریخچه قرار داشته باشد.نشان نگهبان تغییرها
وادی عشق را با موفقیت پشت سر گذاشتی! اکنون میدانی چطور تغییرات را دقیق پیش از ثبت بخوانی، فایلهای محلی را نادیده بگیری و تغییرات Staging Area را پس بگیری.
بعد از آن بنمایدت پیش نظر
معرفت را وادیی بی پا و سر
هیچ ره دروی نه هم آن دیگرست
سالک تن، سالک جان، دیگرست
git diff پیش از هر ثبت.gitignore و عیبیابی با git check-ignoregit restoregit restore --stagedmain دچار اختلال شود.فصل 4: وادی معرفت
درس 1: راهی که هنوز حرکت نکرده
نقشهای با راههای بسیار
کاروان از وادی عشق بیرون آمده و در آغاز وادی معرفت با یک مسئله تازه روبهرو شده است: همه مأموریتها نباید روی جاده اصلی انجام شوند. هدهد میخواهد گروهی فهرست پرندگان را آماده کند، بیآنکه گزارش پایدار سفر دستخوش تغییر و اختلال شود.
بعد از آن بنمایدت پیش نظر
معرفت را وادیی بی پا و سر
هیچ ره دروی نه هم آن دیگرست
سالک تن، سالک جان، دیگرست
در روایت عطار، راه این وادی برای همه سالکان یکسان نیست. همین تصویر به ما کمک میکند مسیرهای موازی گیت را بفهمیم: هر کار یا قابلیت جدید میتواند راه خودش را داشته باشد، اما همه راهها از یک تاریخچه مشترک آغاز میشوند.
اطمینان از نقطه شروع
پیش از بازکردن راه تازه و شاخهبندی، ابتدا وضعیت فعلی پروژه، شاخه فعال و سه کامیت اخیر را استعلام کن:
main را چاپ کند.Valley of Knowledge در نوک تاریخچه قرار دارد.Branch، نامی روی یک Commit
در کنترل نسخه گیت، دو مفهوم کلیدی وجود دارد که اغلب با کپی فیزیکی فایلها اشتباه گرفته میشوند:
یک اشارهگر سبک و نامدار (در حد یک فایل متنی ۴۱ بایتی) است که صرفاً به شناسه یک Commit خاص اشاره میکند.
یک اشارهگر نمادین (Symbolic Reference) است که نشان میدهد ترمینال و دیسک در حال حاضر کدام شاخه را دنبال میکنند.
ساختن Branch جدید، اشارهگر HEAD را بهطور خودکار جابهجا نمیکند؛ ساخت شاخه و جابهجایی به آن دو دستور کاملاً مستقل هستند.
گذاشتن یک نام تازه روی تاریخچه
برای مأموریت آمادهسازی فهرست پرندگان، یک شاخه جدید به نام feature/bird-roster بساز:
در گیت، سکوت ترمینال پس از اجرای دستور یعنی عملیات با موفقیت انجام شده است.
feature/bird-roster روی همان کامیت فعلی قرار داده است؛ اما هنوز وارد آن شاخه نشدهای!دو نام، یک نقطه آغاز
فهرست شاخههای موجود و شناسه کامیتی که هر کدام به آن اشاره دارند را با پرچم جزئیات ببین:
main را دنبال میکند.main و feature/bird-roster دقیقاً شناسه کامیت یکسانی را نشان میدهند.-v خلاصه پیام و شناسه آخرین کامیت هر شاخه را نمایش میدهد.شاخه ساخته شد، جای ما عوض نشد
نام شاخه فعال فعلی را بدون اطلاعات اضافی بخوان:
خروجی هنوز main است.
git branch NAME فقط برچسب شاخه را میسازد و موقعیت HEAD را تغییر نمیدهد. برای وارد شدن به شاخه جدید باید دستور دیگری اجرا کنی.Commit بعدی کدام نام را جلو میبرد؟
کاتب شاخه feature/bird-roster را ساخته، اما هنوز روی شاخه main ایستاده است.
اگر همین حالا فایلی را تغییر داده و Commit کند، کدام Branch به جلو حرکت میکند و چرا؟
ورود به راه فهرست پرندگان
اکنون وقت آن است که با دستور switch به شاخه مأموریت منتقل شوی:
پیام گیت جابهجایی به شاخه را تأیید میکند: Switched to branch 'feature/bird-roster'
feature/bird-roster را دنبال میکند و کامیتهای بعدی فقط روی این شاخه ثبت خواهند شد.دیدن جای دقیق HEAD
موقعیت جدید خود را با دو دستور مکمل بررسی کن:
feature/bird-roster را به عنوان شاخه فعال چاپ میکند.(HEAD -> feature/bird-roster, main) را نشان میدهد که اثبات میکند HEAD اکنون به شاخه جدید وصل شده است.قطبنمای راههای موازی
git branch) از جابهجایی به شاخه (git switch)git branch -v و git log --decoratefeature/bird-roster ایستادهایم. در درس بعدی، نخستین فایل مستقل این شاخه را میسازیم و تفاوت واقعی دو مسیر را روی دیسک مشاهده خواهیم کرد.درس 2: دو گروه، دو مأموریت
هر گروه به اندازه مأموریتش
هدهد کاروان را به دو گروه تقسیم میکند. بلبل و طوطی باید فهرست همراهان را بنویسند و شاهین باید یادداشتهای مسیر را آماده کند؛ هر گروه مسئول یک خروجی روشن است.
سیر هر کس تا کمال وی بود
قرب هر کس حسب حال وی بود
گر بپرد پشه چندانی که هست
کی کمال صرصرش آید بدست
عطار میگوید سیر هر کس با اندازه و حال خودش پیوند دارد. در پروژه نرمافزاری هم Branchها زمانی مفیدند که هرکدام مأموریتی مشخص داشته باشند، نه اینکه بیهدف زیاد شوند.
feature/bird-roster) فایل میسازد. سپس به main برمیگردی تا با چشم خودت ببینی فایلِ ثبتشده روی یک شاخه، الزاماً روی شاخه دیگر وجود ندارد.وقتی HEAD مسیر را عوض میکند
دستور git switch TARGET_BRANCH شاخهای را که HEAD دنبال میکند تغییر میدهد. گیت هنگام جابهجایی، لایههای خود را هماهنگ میسازد:
Your local changes to the following files would be overwritten by checkout را نشان میدهد تا دادههای شما آسیب نبینند.نوشتن فهرست همراهان
روی شاخه feature/bird-roster فایلی به نام bird-roster.txt بساز و دقیقاً محتوای زیر را در آن قرار بده:
bird-roster.txt را در ریشه پروژه بساز.git status --short را بزن؛ باید علامت ?? bird-roster.txt را ببینی.?? نشان میدهد فایل هنوز Untracked است و گیت آن را ردیابی نکرده است.ثبت خروجی گروه اول
فهرست ساختهشده را Stage کرده، صحت تغییر را بررسی کن و نخستین کامیت این شاخه را ثبت نما:
feature/bird-roster را جلو میبرد. شاخه اصلی main همچنان روی کامیت قبلی باقی مانده است.دیدن نخستین انشعاب
تاریخچه همه شاخهها را به صورت نمودار گرافیکی در ترمینال ببین:
feature/bird-roster کنار کامیت جدید قرار دارند.main یک کامیت عقبتر روی نقطه انشعاب اولیه ایستاده است.--graph و --all تصویر انشعاب واقعی شاخهها را ترسیم میکند.بازگشت به نسخه پایدار
اکنون به شاخه اصلی پروژه برگرد و وضعیت فایلها روی دیسک را کنترل کن:
به پوشه پروژه نگاه کن؛ فایل bird-roster.txt دیگر دیده نمیشود!
main بهروز کرده است که آن فایل در آن وجود ندارد.میانبُر آخرین شاخه
برای رفت و برگشت سریع بین دو شاخه اخیر، از پرچم dash (-) استفاده کن:
وقتی روی شاخه مأموریت برمیگردی، فایل bird-roster.txt بلافاصله روی دیسک ظاهر میشود.
git switch - دقیقا مانند کلید ترکیبی Alt+Tab در سیستمعامل، شما را بین دو آخرین شاخه جابهجا میکند.ساخت و ورود در یک فرمان
برای گروه دوم (یادداشتهای مسیر)، شاخه جدیدی بساز و در همان لحظه وارد آن شو:
گزینه -c (مخفف create) ابتدا شاخه جدید را از کامیت فعلی میسازد و سپس HEAD را به آن منتقل میکند.
main ساختیم، فایل bird-roster.txt در آن وجود ندارد و این شاخه مستقل است.ثبت یادداشتهای مسیر
فایل route-notes.txt را با محتوای زیر بساز و مأموریت گروه دوم را کامیت کن:
آیا تغییر محلی همیشه مانع Switch است؟
یکی از همتیمیها میگوید: «اگر Working Tree تمیز نباشد، Git همیشه اجازه switch نمیدهد.»
این جمله چه ایرادی دارد و تصمیم امن پیش از جابهجایی چیست؟
دو مسیر آماده بازگشت
feature/bird-roster و feature/route-notesgit switchgit switch - برای پرش بین دو شاخه اخیرgit switch -c برای ساخت و جابهجایی یکباره شاخهmain ادغام میکنیم و تفاوت Fast-forward با 3-way Merge را در تاریخچه واقعی مشاهده خواهیم کرد.درس 3: بازگشت دو گروه به main
دو راه با اندازههای متفاوت
گروه فهرست پرندگان و گروه یادداشتهای مسیر، هر دو مأموریتشان را روی شاخههای فرعی تمام کردهاند. اکنون هدهد تصمیم میگیرد از سمت جاده اصلی به استقبال آنها برود تا جهت ادغام و ترکیب گزارشها روشن بماند.
لاجرم بس ره که پیش آمد پدید
هر یکی بر حد خویش آمد پدید
کی تواند شد درین راه جلیل
عنکبوت مبتلا همسیر پیل
عطار در وادی معرفت یادآوری میکند که راهها و توان رهروان هماندازه نیست. در کنترل نسخه گیت هم شکل Merge به موقعیت شاخهها در درخت کامیتها بستگی دارد؛ یک فرمان یکسان میتواند دو خروجی کاملاً متفاوت بسازد.
main میتواند مستقیم تا نوک آن جلو برود (Fast-forward). سپس شاخه دوم را ادغام میکنیم که نیاز به ساخت یک Merge Commit خواهد داشت.جهت Merge و دو شکل تاریخچه
در اجرای دستور git merge SOURCE_BRANCH، شاخهای که روی آن ایستادهای مقصد ادغام است. همیشه جهت حرکت را مشخص کن:
اگر شاخه فعلی جد مستقیم شاخه ورودی باشد، نیازی به کامیت جدید نیست و گیت برچسب شاخه را مستقیماً به جلو منتقل میکند.
اگر هر دو شاخه کامیت مستقل داشته باشند، گیت ۳ نقطه را مقایسه کرده و یک Merge Commit با دو والد میسازد.
git branch --show-current مطمئن شو که روی شاخه مقصد (مانند main) ایستادهای.ادغام مستقیم فهرست
ابتدا به شاخه اصلی برگرد و شاخه فهرست پرندگان را به صورت مستقیم ادغام کن:
خروجی ترمینال عبارت Fast-forward را نشان میدهد.
main را تا نوک شاخه feature/bird-roster جلو برد. پرچم --ff-only تضمین میکند که اگر Fast-forward ممکن نباشد، عملیات متوقف شود.اثبات Fast-forward
تاریخچه کامیتها و وضعیت پوشه کاری را بررسی کن:
main و feature/bird-roster کنار یک کامیت قرار گرفتهاند.bird-roster.txt اکنون بخشی از Snapshot شاخه اصلی است.ادغام سهطرفه مسیر
حالا شاخه یادداشتهای مسیر را از سمت همین main ادغام کن:
این بار main کامیت فهرست را دارد و feature/route-notes کامیت مسیر را؛ هیچکدام جد مستقیم دیگری نیستند.
--no-edit پیام پیشفرض کامیت را پذیرفت.Merge Commit با دو والد
شکل تاریخچه و کالبدشناسی کامیت ادغام را بررسی کن:
parent را نشان میدهد: یکی والد main و دیگری والد feature/route-notes.چرا نتیجه دو Merge فرق داشت؟
هر دو بار دستور git merge را روی شاخه main اجرا کردی.
چرا ادغام نخست Fast-forward بود، اما ادغام دوم یک Merge Commit ساخت؟
کدام راهها به مقصد رسیدهاند؟
فهرست شاخههایی که کامیتهای آنها وارد تاریخچه main شده است را بررسی کن:
هر دو شاخه مأموریت باید در این لیست دیده شوند.
جمعکردن تابلوهای تمامشده
اشارهگرهای شاخههای تمامشده را با روش حذف امن پاک کن:
حذف امن — اگر شاخه کاملاً ادغام نشده باشد، گیت عملیات را متوقف کرده و هشدار میدهد.
حذف اجباری — محافظ ادغام را دور میزند و ممکن است دسترسی به کامیتها را از بین ببرد.
تحویل دو خروجی روی main
فهرست نهایی شاخهها و وضعیت پوشه کاری را بررسی نما:
main در لیست وجود دارد.bird-roster.txt و route-notes.txt روی دیسک حاضر هستند.نقشهخوان ادغام
main)--ff-onlygit branch --mergedgit branch -dدرس 4: دو روایت روی یک خط
وقتی دو راه به یک نقطه میرسند
پس از بازگشت دو گروه، درباره آرایش شبانه کاروان اختلافی پیش میآید. بلبل میخواهد خط آواز را هدایت کند و شاهین میخواهد خط دیدهبانی را؛ هر دو پیشنهاد درستاند، اما کاتب هرکدام را جداگانه روی همان خط از فایل گزارش ثبت میکند.
هیچ کس نبود که او این جایگاه
مختلف گردد ز بسیاری راه
هیچ ره دروی نه هم آن دیگرست
سالک تن، سالک جان، دیگرست
عطار وادی معرفت را جای راههای بسیار میداند؛ تفاوت مسیرها خطا نیست، اما وقتی دو روایت مختلف به یک سطر یا فایل مشترک میرسند، باید آگاهانه میانشان نسبت برقرار کرد. گیت در چنین لحظهای بهجای حدس زدن نابجا، کار را متوقف میکند.
Conflict یعنی Git انتخاب نمیکند
گیت برای ادغام ۳ نسخه را میسنجد: مبنای مشترک، نوک شاخه فعلی و نوک شاخه ورودی. اگر هر دو مسیر یک بخش از فایل را به دو شکل ناسازگار تغییر داده باشند، انتخاب خودکار ممکن است کد صحیح را نابود کند.
UU (Unmerged) مشخص میشود.git merge --abort مخزن را به حالت قبل از ادغام برمیگرداند.بازکردن مسیر بلبل
از شاخه اصلی main یک شاخه جدید برای پیشنهاد بلبل بساز و شاخه فعال را تأیید کن:
خروجی فرمان دوم باید feature/nightingale-route باشد.
روایت بلبل از آرایش
در فایل journey-log.txt سطر زیر را پیدا کن:
فقط همان سطر را با پیشنهاد بلبل جایگزین کن:
feature/nightingale-route ثبت شد.روایت شاهین روی main
به شاخه اصلی main برگرد. در این Snapshot سطر آرایش هنوز نسخه قدیمی Formation: Stable است:
همان سطر را این بار با پیشنهاد شاهین جایگزین کرده و کامیت کن:
دیدن دو نوک جدا
پیش از اجرای ادغام، انشعاب متعارض دو شاخه را در گراف تاریخچه ببین:
ساخت تعارض واقعی
پیشنهاد بلبل را از سمت شاخه main ادغام کن تا بروز تعارض را تجربه کنی:
CONFLICT (content): Merge conflict in journey-log.txtدستور status عبارت
UU journey-log.txt را نشان میدهد.UU (Unmerged) یعنی هر دو سوی ادغام این مسیر را تغییر دادهاند و تا زمانی که تعارض آن را حل نکنی، کامیت ادغام ثبت نمیشود.خواندن سه نشانگر تعارض
این بلوک نمونه خروجی Git است، نه متنی برای افزودن به فایل. اگر نمایش تعارض diff3 فعال باشد، یک بخش مبنای مشترک با نشانگر ||||||| هم میبینی؛ در حل نهایی همه نشانگرها و نسخههای رقیب را با سطر ترکیبی قدم بعد جایگزین کن.
فایل journey-log.txt را در VS Code باز کن. گیت دو روایت را میان نشانگرهای سهگانه زیر محصور کرده است:
main) است.چرا Git یکی را برنده نکرد؟
گیت هر دو متن را میبیند. چرا نمیتواند خودش تشخیص دهد کدام جمله درستتر است و وضعیت مخزن تا پیش از حل چه معنایی دارد؟
نوشتن روایت ترکیبی
تمام بلوک نشانگرها و دو جمله رقیب را پاک کن و فقط ترکیب هوشمندانه زیر را به جای آنها بنویس:
git diff --check را بزن تا از نبود خطای فاصله مطمئن شوی.git add journey-log.txt را اجرا کن تا حل تعارض به گیت اعلام شود.git add روی فایل متعارض، به گیت اعلام کرد که تعارض این مسیر با موفقیت حل شده است.بستن Merge و پاکسازی راه
نتیجه حلشده را کامیت کن و شاخه فرعی تمامشده را پاک کن:
نشان راهبر مسیرهای موازی
نشان «راهبر مسیرهای موازی» را به دست آوردی! اکنون شاخهها و HEAD را دقیق میشناسی، مسیرهای مستقل میسازی، دو شکل Merge را تشخیص میدهی و Conflict را با خواندن نشانگرها حل میکنی.
بعد ازین وادی استغنا بود
نه درو دعوی و نه معنی بود
میجهد از بینیازی صرصری
میزند بر هم به یک دم کشوری
git branch و git switchgit branch --merged و حذف امن شاخههاgit stash تغییرات ناتمام را موقتاً کنار بگذاریم.فصل 5: وادی استغنا
درس 1: یادداشت نیمهتمام و پیام فوری
باد ناگهانی در میانه کار
طوطی هنوز گزارش مسیر را کامل نکرده که پیامی فوری از گروه آذوقه میرسد. گزارش نیمهتمام برای Commit آماده نیست، اما تغییر فوری هم نمیتواند منتظر بماند؛ پاککردن نوشته یا ثبت یک Commit ناقص هر دو انتخابهای اشتباهی هستند.
کاروان وارد وادی استغنا شده است؛ جایی که بادِ عطار نظم آشنای یک سرزمین را در یک دم برهم میزند. مسئله این درس هم مدیریت همین وقفه است: کار نیمهتمام را موقتاً در کشوی مخفی کنار میگذاری تا مسیر اصلی برای مأموریت فوری تمیز شود.
بعد ازین وادی استغنا بود
نه درو دعوی و نه معنی بود
میجهد از بینیازی صرصری
میزند بر هم به یک دم کشوری
فرمان git stash دقیقاً برای چنین وقفههایی طراحی شده است. این ابزار تغییرهای Staged و Unstaged شما را موقتاً در پشتهای صفیمانند ذخیره کرده، Working Tree را به وضعیت تمیز آخرین Commit برمیگرداند و اجازه میدهد پس از انجام کار فوری، به همان نوشتههای نیمهکاره بازگردید.
git stash مثل یک کشوی ابزار کشویی در کارگاه است. وسایل نیمهکاره روی میز را برمیداری، توی کشو میگذاری تا میز برای کار اضطراری خالی شود.Stash چه چیزی را کنار میگذارد؟
دستور git stash بهصورت پیشفرض تغییرات فایلهای Tracked (فایلهای ردیابیشده در گیت) را ذخیره کرده و Working Tree را به وضعیت HEAD بازمیگرداند. این ذخیره یک Commit عادی روی شاخه نیست و در git log معمولی دیده نمیشود.
-u یا --include-untracked استفاده کنید..gitignore هستند، حتی با -u هم کنار گذاشته نمیشوند مگر از پرچم -a استفاده کنید.تغییرات را روی فایلها اعمال میکند، اما مدخل Stash را در پشته باقی میگذارد.
تغییرات را اعمال کرده و در صورت موفقیت، مدخل مربوطه را از پشته حذف میکند.
drop (حذف یک Stash مشخص) و clear (پاک کردن تمام پشته) تغییرات ذخیرهشده را بدون اعمال روی کد شما پاک میکنند. همیشه قبل از پاک کردن پشته، از عدم نیاز به آن مطمئن شوید.شروع از میز خالی
قبل از شروع تمرین، ابتدا وضعیت شاخه، تغییرات فعلی و پشته Stash را بررسی کنید تا مطمئن شوید روی یک نقطه تمیز قرار دارید:
main باشید و دو فرمان دوم و سوم هیچ خروجی نشان ندهند. این محیط تمیز حاصل پایان موفق فصل چهارم است.بازبینی گذرگاه شمالی
در فایل route-notes.txt که از قبل ردیابی میشود (Tracked)، وضعیت گذرگاه شمالی را بهصورت نیمهکاره تغییر دهید:
route-notes.txt خط زیر را پیدا کنید:پیشنویس تازه دیدهبانی
اکنون یک فایل گزارش تازه به نام scout-report.txt ایجاد کنید تا رفتار Stash را با فایلهای ردیابینشده (Untracked) آزمایش کنیم:
scout-report.txt را بسازید و متن زیر را در آن بنویسید: M route-notes.txt (تغییر Tracked) و ?? scout-report.txt (فایل Untracked) را نشان دهد.اولین بسته، فقط برای فایل Tracked
حالا فرمان git stash push را همراه با یک پیام توضیحی روشن اجرا کنید و وضعیت مخزن را ببینید:
route-notes.txt از Working Tree کنار رفته و تمیز شده، اما ?? scout-report.txt همچنان باقی مانده است! چرا که Stash معمولی فایلهای Untracked را برنمیدارد.چرا گزارش تازه جا ماند؟
چرا Stash در مرحله قبل تغییر route-notes.txt را ذخیره و پاک کرد، اما فایل scout-report.txt همچنان در git status باقی ماند؟ برای کنارگذاشتن این فایل تازه چه گزینهای لازم است؟
بسته دوم با فایل تازه
اکنون گزارش دیدهبانی تازه را هم با پرچم -u به پشته Stash اضافه کنید:
stash@{0} (گزارش دیدهبانی) و Stash قبلی در stash@{1} (بازبینی گذرگاه) قرار گرفته است. عضو جدیدتر همیشه در بالای پشته (اندیس 0) قرار میگیرد.ثبت ورود و وضعیت آذوقه
دو سطر مربوط به وادی در journey-log.txt کنار هم نیستند. هرکدام را در جای فعلی خودش تغییر بده؛ کل فایل یا خطهای میان آنها را با کادر دوخطی جایگزین نکن.
میز کار شما اکنون کاملاً تمیز است! حالا میتوانید مأموریت فوری گروه آذوقه را انجام دهید و ثبت کنید:
supplies.txt متن را با این گزارش جایگزین کنید:journey-log.txt خطوط مربوط به وادی را بهروز کنید:دیدن تفاوت Apply و Pop
حالا نوبت بازگرداندن کارهای نیمهکاره است. ابتدا تفاوت apply (اعمال بدون حذف از پشته) و pop (اعمال همراه با حذف از پشته) را تجربه میکنیم:
stash@{1} را pop کردید، حذف شد و عضو باقیمانده همچنان اندیس stash@{0} گرفت! به همین دلیل pop دوم روی stash@{0} اجرا شد.تکمیل گزارش و خالیکردن پشته
اکنون هر دو کار نیمهکاره برگردانده شدهاند. فایلها را به نسخه نهایی تغییر دهید و یک Commit تمیز بسازید:
route-notes.txt عبارت Under review را به Confirmed تغییر دهید.scout-report.txt را به نسخه نهایی زیر تغییر دهید:مدیر وقفههای کاروان
شما در این درس یاد گرفتید چگونه وقفههای ناگهانی را بدون نامرتب کردن تاریخچه Commitها مدیریت کنید:
git stash push -m "..." برای ذخیره موقت تغییرات فایلهای Tracked.-u برای ذخیره همزمان فایلهای جدید و Tracked نشده.apply (حفظ در پشته) و pop (حذف پس از اعمال).در درس بعدی، سراغ تغییرات موقت نمیرویم؛ بلکه خودِ اشارهگر شاخه و تاریخچه local را جابهجا کرده و اثر پرچمهای soft، mixed و hard فرمان git reset را روی سه لایه Git بررسی میکنیم.
درس 2: یک Commit عقب، نوشتهها سر جایشان
اندازه اشتباه در پهنه تاریخچه
یکی از کاتبان یک یادداشت درست را با پیام مبهم ثبت کرده است. قرار نیست برای اصلاح یک Commit محلی، کل کار انجامشده پاک شود؛ اما کاتب باید بداند با عقببردن اشارهگر شاخه، کدام لایهها دستنخورده باقی میمانند.
عطار در وادی استغنا اندازههای آشنا را کنار هم میگذارد تا نشان دهد بزرگی هر چیز به مقیاسی که از آن نگاه میکنیم وابسته است. در Git هم یک جابهجایی کوچک در Reference شاخه، به معنای نابودی فایلهای کد شما نیست.
هفت دریا یک شمر اینجا بود
هفت اخگر یک شرر اینجا بود
هشت جنت نیز اینجا مردهایست
هفت دوزخ همچو یخ افسرده ایست
با پرچم git reset --soft فقط نوک تاریخچه شاخه را عقب میبرید و کدهای تغییریافته را در Index (بخش Staged) نگه میدارید. سپس با حالت --mixed میتوانید همان تغییر را از حالت Staged بیرون بیاورید، بیآنکه فایلهای Working Tree شما دستخوش تغییر شوند.
--soft و --mixed در فرمان git reset و مشاهده رفتار آنها روی ۳ لایه گیت.سه لایه و یک مقصد
در حالت معمول، HEAD نام شاخه فعال شما را دنبال میکند. اجرای git reset TARGET اشارهگر شاخه فعال را به Commit مقصد میبرد، و پرچم انتخابی تعیین میکند که Index و Working Tree چه وضعیتی پیدا کنند:
HEAD~1 یعنی «یک Commit قبل از HEAD فعلی». قبل از هر Reset همیشه تاریخچه را با git log چک کنید.ساخت آزمایشگاه بازنویسی
برای اینکه تمرینهای این درس آسیبی به شاخه اصلی نزند، یک شاخه آزمایشی جدید بسازید:
sandbox/reset-lab انجام میشود تا شاخه اصلی main سالم بماند.روشنکردن فانوس اردو
ابتدا یک تغییر معتبر و دقیق در فایل route-notes.txt اعمال و Commit کنید. این نقطه، مقصد امن ما در Resetهای بعدی خواهد بود:
route-notes.txt عبارت Night camp: Ready را پیدا کرده و به عبارت زیر تغییر دهید:HEAD~1 بعدی ما خواهد بود.ثبت شتابزده شمارش آذوقه
اکنون تغییر جدیدی در supplies.txt ایجاد کرده و آن را با یک پیام ضعیف و شتابزده ثبت کنید:
supplies.txt را به عبارت زیر تغییر دهید:HEAD~1 است.عقببردن نرم Branch
حالا شاخه آزمایشی را با پرچم --soft یک Commit به عقب برگردانید:
supplies.txt کجاست؟ در مرحله بعد ببینید!نوشته باقیمانده در Index
برای اینکه ببینید تغییرات Commit حذفشده از بین نرفتهاند، status و staged diff را چک کنید:
M در ستون سمت چپ (رنگ سبز) قرار دارد. این یعنی --soft Commit را پاک کرد اما تغییرات فایل را بهصورت Staged تحویل شما داد تا پیامش را اصلاح کنید!Mixed، فقط برای خالیکردن Index
اکنون بدون پرچم (یا با پرچم --mixed)، فرمان reset را روی همین HEAD جاری اجرا کنید:
M به ستون سمت راست (رنگ قرمز) منتقل شد. فایل همچنان تغییریافته است اما دیگر در Stage نیست. دستور git reset HEAD دقیقاً همین کار را انجام میدهد.کنارگذاشتن آزمایش شتابزده
تغییر Unstaged را مشاهده کرده و سپس آن را ریست کنید تا شاخه پاک شود:
آیا Soft واقعاً بیخطر است؟
چرا نام --soft به این معنا نیست که فرمان همیشه بیخطر است؟ همچنین توضیح دهید چرا git reset --mixed HEAD در این تمرین اشارهگر شاخه را جابهجا نکرد، اما وضعیت Stage را تغییر داد؟
نقشهخوان سه لایه
در این درس رفتار علمی Reset روی ۳ لایه گیت را یاد گرفتید:
--soft (حفظ Index و Working Tree) و --mixed (حفظ فقط Working Tree).HEAD~1 برای اشاره به Commit والد (یک نود قبلتر در تاریخچه).sandbox/*.در درس بعد، حالت --hard را بررسی میکنیم و میبینیم چگونه گیت فایلها را با Commit مقصد یکسان میکند و چطور میتوان با reflog Commitهای ظاهراً نابودشده را نجات داد!
درس 3: پرتگاه Hard و طناب نجات
پیش از وزیدن باد، نشانی بگذار
شاهین پناهگاهی اضطراری روی نقشه پیدا میکند، اما هدهد میخواهد پیش از آزمایش بازگشت سخت، نشانی روشن از Commit فعلی بگذارند. در این بخش شجاعت یعنی شناخت دامنه خطر و داشتن راه برگشت.
عطار در وادی استغنا از جهانی میگوید که حتی افلاک و ستارگان در آن همچون برگی کوچک میشوند. فرمان git reset --hard هم میتواند تغییرات روی میز کار را در یک لحظه از نمای فعلی بردارد؛ پس نباید بیمقدمه و بدون احتیاط اجرا شود.
گر بریخت افلاک و انجم لخت لخت
در جهان کم گیر برگی از درخت
گر ز ماهی در عدم شد تا به ماه
پای مور لنگ شد در قعر چاه
در این درس یک Commit مفید میسازیم، یک شاخه پشتیبان (Backup Branch) روی آن قرار میدهیم و سپس Hard Reset را اجرا میکنیم. خواهید دید که تغییرات Commitشده از طناب نجات برمیگردند، اما ویرایشهای ثبتنشده روی دیسک چنین تضمینی ندارند!
دامنه دقیق Hard Reset
اجرای git reset --hard TARGET سه لایه شاخه فعال، Index و فایلهای Tracked در Working Tree را همزمان با Snapshot مقصد هماهنگ میکند. تمام ویرایشهای Staged و Unstaged آن فایلها حذف خواهند شد.
backup/xyz پیش از Reset، سادهترین و امنترین راه نجات Commitها است.کنترل لبه پرتگاه
پیش از ادامه، نام شاخه، وضعیت فایلها و آخرین Commitها را کنترل کنید:
sandbox/reset-lab باشید، وضعیت تمیز باشد و Commit فانوس در بالای log دیده شود.ثبت پناهگاه اضطراری
در انتهای فایل route-notes.txt یک خط جدید اضافه کنید و آن را Commit نمایید:
route-notes.txt:بستن طناب به Commit سالم
پیش از اجرای Hard Reset، یک اشارهگر یا شاخه پشتیبان روی همین Commit بسازید:
sandbox/reset-lab و backup/before-hard-reset اکنون دقیقاً به یک شناسه Commit اشاره میکنند.یادداشت محلی بدون پشتیبان
محتوای supplies.txt را بهصورت زیر تغییر دهید اما آن را Commit نکنید:
supplies.txt به عبارت زیر:چه چیزی برمیگردد و چه چیزی نه؟
اگر اکنون git reset --hard HEAD~1 اجرا شود، چه اتفاقی برای شاخه آزمایشی، خط پناهگاه Commitشده، تغییر Commitنشده آذوقه و شاخه پشتیبان میافتد؟
اجرای بازگشت سخت کنترلشده
اکنون فرمان Hard Reset را اجرا کرده و پاک شدن تغییرات را در Working Tree مشاهده کنید:
route-notes.txt پاک شد و فایل supplies.txt بدون هیچ ردی به حالت قبلی برگشت! ویرایش ثبتنشده آذوقه برای همیشه نابود شد.رد پا در Reflog
رد حرکت HEAD را در Reflog و موقعیت شاخه پشتیبان ببینید:
کشیدن Commit از طناب نجات
اکنون شاخه آزمایشی را به کمک شاخه پشتیبان به موقعیت Commit پناهگاه بازگردانید و سپس شاخه پشتیبان را پاک کنید:
Emergency shelter: Marked دوباره برگردانده شد! اما یادداشت Commit نشده آذوقه برنگشت؛ زیرا فقط تغییرات Commitشده شانس بازیابی دارند.نگهبان مقصدهای خطرناک
در این درس کنترل کامل بر Hard Reset و راههای نجات کد را کسب کردید:
git reset --hard روی فایلهای ردیابیشده در Working Tree.git reflog برای پیدا کردن شناسه Commitهای ناپدیدشده.در درس بعدی و پایانی این فصل، کارهای سالم انجامشده را به شاخه اصلی main منتقل کرده و نحوه لغو ایمن Commitهای عمومی را با دستور git revert فرا خواهیم گرفت.
درس 4: اصلاحیهای که گذشته را پاک نمیکند
خبر اشتباه میان همه پرندگان
خبر نادرستی درباره بستهبودن پناهگاه در دفتر اصلی ثبت شده و همه گروهها آن را دیدهاند. اگر کاتب اکنون تاریخچه را با Reset عقب بکشد، نسخهای که دیگران دارند با روایت او متفاوت میشود؛ راه بهتر نوشتن یک اصلاحیه شفاف در ادامه همان دفتر است.
در وادی استغنا، عطار حادثههای بسیار بزرگ را در مقیاسی دیگر کوچک میبیند. کاتب هم قرار نیست برای یک خبر اشتباه تمام گذشته را جابهجا کند؛ فقط اثر همان تغییر را با یک Commit تازه خنثی میکند.
گر دو عالم شد همه یک بارنیست
در زمین ریگی همان انگار نیست
گر نماند از دیو وز مردم اثر
از سر یک قطره باران در گذر
فرمان git revert تفاوتهای یک Commit مشخص را معکوس کرده و نتیجه را در یک Commit جدید ثبت میکند. به همین دلیل برای تاریخچهای که قبلاً Push شده یا به اشتراک گذاشته شده است، روشی بسیار ایمنتر و حرفهایتر از Reset محسوب میشود.
Reset جابهجا میکند، Revert اضافه
آگاهی از زمان مناسب برای استفاده از این دو ابزار کلیدی گیت، مرز بین یک توسعهدهنده تازهکار و حرفهای است:
اشارهگر شاخه را به گذشته برمیگرداند و تاریخچه را بازنویسی میکند. مناسب برای شاخههای محلی (Local) قبل از Push.
تاریخچه را دستنخورده نگه میدارد و یک Commit جدید برای خنثیسازی میسازد. مناسب برای شاخههای عمومی (Shared/Remote).
بازگرداندن دستاورد آزمایشگاه به main
کارهای سالم انجامشده در شاخه آزمایشی sandbox/reset-lab را به شاخه اصلی منتقل کنید:
main هستند.تحویل سالم پیش از اصلاحیه
قبل از ثبت تغییر اشتباه، وضعیت شاخه اصلی را کنترل کنید:
main باید وجود داشته باشد و Commit پناهگاه در بالای تاریخچه قرار گرفته باشد.ثبت عمدی خبر بستهبودن پناهگاه
در فایل route-notes.txt وضعیت پناهگاه را عمداً به اشتباه تغییر دهید و Commit کنید:
route-notes.txt عبارت Emergency shelter: Marked را به عبارت زیر تغییر دهید:شناخت دقیق Commit هدف
قبل از خنثیسازی، جزییات و Diff دقیق Commit اخیر را بررسی کنید:
Marked به Closed کاملاً مشخص است.ساخت Commit اصلاحیه
اکنون اثر Commit اخیر را با فرمان git revert معکوس کنید:
Marked برگرداند. Commit اشتباه هنوز در تاریخچه هست و این Commit اصلاحی بعد از آن قرار گرفته است.اثبات باقیماندن هر دو روایت
حالت فایلها، Log شاخه و تمیزی کلی مخزن را بررسی کنید:
اگر Revert وسط راه متوقف شد
در تمرین فعلی revert موفق بوده است؛ این فرمانها را اکنون اجرا نکن. فقط اگر در آینده revert روی تعارض متوقف شد، یکی از دو مسیر زیر را انتخاب کن.
برای ادامه: فایلهای متعارض را اصلاح کن، PATH را با مسیر واقعی جایگزین کن و سپس:
یا اگر تصمیم به انصراف از همان عملیات ناتمام داری، بهجای ادامه:
Reset یا Revert برای تاریخچه مشترک؟
یک Commit اشتباه قبلاً به همتیمیها رسیده و Push شده است. چرا معمولاً git revert COMMIT از عقببردن main با Reset انتخاب مناسبتری است و چه محدودیتی همچنان دارد؟
نشان نگهبان تاریخچه
تبریک! شما فصل پنجم را با موفقیت پشت سر گذاشتید و نشان نگهبان تاریخچه را کسب نمودید.
git stash.--soft، --mixed و --hard در git reset.reflog).git revert بدون بازنویسی گذشته.کاروان اکنون سبکبار و با یک تاریخچه واحد از وادی استغنا بیرون میآید. عطار در آغاز منزل بعد (وادی توحید)، چهرههای بسیار را رو به یک افق میبیند. در فصل ششم، با ابزار git tag نقاط مهم این تاریخچه سالم را نشانگذاری خواهیم کرد.
بعد از این وادی توحید آیدت
منزل تفرید و تجرید آیدت
رویها چون زین بیابان درکنند
جمله سر از یک گریبان برکنند
فصل 6: وادی توحید
درس 1: مهری برای یک نسخهٔ قابل اعتماد
نشانی که باید پس از عبور هم پیدا شود
کاروان به نقطهای رسیده که گزارش مسیر، آذوقه، دیدهبانی و پناهگاه همگی درست و سنجیده شدهاند. اگر فردا چند تغییر تازه به دفتر پروژه اضافه شود، عبارت «نسخه خوب دیروز» دیگر نشانی دقیق و قابل استنادی نیست؛ کاتب باید همین Commit تأییدشده را با یک مهر ثابت و دائمی نامگذاری کند.
کاروان وارد وادی توحید شده است؛ جایی که راههای بسیار به یک نشان مشترک و مقصدی واحد میرسند. برچسب (Tag) نیز نامی خوانا و انسانی برای یک نقطه مشخص از تاریخچه ارائه میدهد، بیآنکه شاخه تازهای برای ادامه کار بسازد.
بعد از این وادی توحید آیدت
منزل تفرید و تجرید آیدت
رویها چون زین بیابان درکنند
جمله سر از یک گریبان برکنند
مأموریت این درس ساخت یک برچسب شناسنامهدار (Annotated Tag) به نام v0.7.0 روی نسخه سالم و سپس اثبات عملی ثابتماندن نشانی آن با پیشروی شاخه به سمت جلو است.
نامی خوانا برای یک شیء مشخص
هر Commit با یک کد هش ۴۰ کاراکتری SHA-1 شناسایی میشود؛ اما استفاده از این کدهای پیچیده برای گفتگو درباره نسخههای انتشار (Releases) در تیم غیرعملی است. برچسب (Tag) یک اشارهگر ثابت با نامی خوانا مانند v0.7.0 است که در مسیر refs/tags/ ذخیره میشود.
اشارهگری متحرک است. با هر Commit جدید روی شاخه، اشارهگر به خودی خود جلو میرود تا نوک توسعه را نشان دهد.
اشارهگری ثابت است. روی یک Commit مشخص میماند و حتی با ثبت Commitهای بعدی روی شاخه، جابهجا نمیشود.
آیا این نقطه آمادهٔ مهر انتشار است؟
پیش از ساخت Tag و ممهور کردن نسخه، ابتدا باید از سلامت کامل و تمیز بودن Working Tree و شاخه فعال اطمینان حاصل کنیم:
main باشد و دو دستور میانی (status و diff) هیچ خروجی متنی نشان ندهند که به معنای پاک بودن کامل مخزن است.بازبینی خود نسخه، نه فقط وضعیت آن
نسخهای که قرار است نام v0.7.0 بگیرد باید دارای دادههای معتبر و نهایی باشد. پیش از صدور مهر انتشار، گزارشهای اصلی پروژه را بازخوانی و بازبینی کنید:
دو نوع برچسب برای دو نوع نیاز
در Git دو نوع برچسب (Tag) وجود دارد که بر اساس میزان حساسیت و کاربرد پروژه انتخاب میشوند:
ثبت نسخهٔ ۰٫۷ روی Commit تأییدشده
چون HEAD اکنون روی Commit تأییدشده قرار دارد، برچسب شناسنامهدار را بدون نیاز به وارد کردن کد هش و مستقیماً روی نقطه فعلی میسازیم:
-a مشخص میکند که Tag از نوع شناسنامهدار (Annotated) است و پرچم -m پیام توضیحی برچسب را در دیتابیس Git ثبت میکند.خواندن شناسنامهٔ مهر
پس از ساخت برچسب، وجود آن در فهرست Tagها و اطلاعات شناسنامهای ثبتشده در آن را بررسی کنید:
اثبات اینکه نام و HEAD به یک نقطه میرسند
یک Annotated Tag ابتدا به یک Tag Object اشاره میکند و آن شیء به Commit اصلی وصل است. با علامت ^{} میتوانید کد هش Commit پشت این Tag را استخراج و با HEAD مقایسه کنید:
یک قدم پس از نسخهٔ نشانهگذاریشده
دو سطر کادر در دو جای جدا از journey-log.txt قرار دارند. هر سطر را جداگانه در محل فعلی ویرایش کن و تمام خطوط بین آنها را نگه دار.
اکنون کاروان یک قدم به جلو میرود. فایل journey-log.txt را بهروز کرده و Commit جدیدی ثبت کنید تا رفتار برچسب در برابر پیشروی شاخه را مشاهده کنیم:
journey-log.txt این دو خط را پیدا کنید:Tag ماند و main جلو رفت
حالا موقعیت شاخه main و برچسب v0.7.0 را در تاریخچه لاگ مقایسه کنید:
main یک Commit جلو رفته است اما برچسب v0.7.0 دقیقاً روی Commit قبلی باقی مانده است. عدد 1 نشاندهنده یک Commit تفاوت است.اگر نسخهٔ منتشرشده اشتباه نشانه خورد
تیم Tag نسخه v0.7.0 را در مخزن مرکزی منتشر کرده و چند عضو تیم آن را در رایانه خود دریافت کردهاند. سپس مشخص میشود Commit واقعی انتشار، یک قدم جلوتر بوده است. چرا جابهجا کردن بیخبر همان برچسب خطرناک است و راهکار مهندسی و شفافتر چیست؟
v0.7.1) انجام دهید.یک مهر، دو نقطهٔ روشن
در این درس نحوه نشانهگذاری ثابت نقاط تاریخچه پروژه را به طور کامل فرا گرفتید:
git tag -a NAME -m "MSG".git rev-parse 'TAG^{}'.git diff TAG..BRANCH و git rev-list.در درس بعدی، مسئله انتخاب یک نقطه نیست؛ بلکه یک شاخه آزمایشی دارای چند Commit است و ما میخواهیم فقط یک Commit مشخص از آن را با ابزار git cherry-pick جدا کرده و به شاخه اصلی پیوند بزنیم!
درس 2: نجات یک پیام از شاخهٔ آزمایشی
یک پیام لازم میان دو تغییر
یک گروه آزمایشی در پروژه، هم راهنمای علامتهای فانوس را نوشته و هم پیشنویس بنری را ساخته که هنوز رنگ و طرح آن معلوم نیست. مسیر اصلی پروژه (main) فقط به راهنمای کاربردی نیاز دارد؛ ادغام کامل این شاخه (Merge)، پیشنویس ناتمام را هم وارد تاریخچه اصلی پروژه میکند.
هدهد از کاتب میخواهد میان چند تغییر مختلف، فقط همان تغییر مناسب و آماده را دستچین کند. بیت زیبایی از عطار در وادی توحید، الگوی فکری این انتخاب سنجیده است:
گر بسی بینی عدد، گر اندکی
آن یکی باشد درین ره در یکی
چون بسی باشد یک اندر یک مدام
آن یک اندر یک، یکی باشد تمام
برای حل این مسئله، اثر Commit راهنما را با فرمان git cherry-pick روی شاخه اصلی main بازسازی میکنیم؛ در حالی که شاخه آزمایشی و پیشنویس ناتمام، دستنخورده سر جای خود باقی میمانند.
Cherry-pick دقیقاً چه چیزی را برمیدارد؟
دستور git cherry-pick COMMIT_HASH ابتدا تغییرات معرفیشده توسط Commit منتخب را نسبت به والدش محاسبه کرده، آن را روی HEAD فعلی اعمال میکند و یک Commit تازه میسازد:
جداکردن آزمایش از مسیر اصلی
ابتدا از وضعیت تمیز شاخه اصلی main یک شاخه آزمایشی جدید میسازیم تا تغییرات جدید را در محیطی ایزوله ثبت کنیم:
experiment/signal-kit ثبت میشوند و شاخه main دستنخورده میماند.ثبت راهنمای قابلاستفاده
فایل جدید signal-guide.txt را ایجاد کرده و محتوای راهنمای فانوس را در آن ثبت کنید:
signal-guide.txt را ساخته و متن زیر را در آن قرار دهید:ثبت پیشنویسی که هنوز آماده نیست
در همان شاخه آزمایشی، فایل draft-banner.txt را برای بنر ناتمام ایجاد و ثبت کنید:
draft-banner.txt را بسازید و متن زیر را در آن قرار دهید:main است.انتخاب Commit از روی محتوا
کامیتها را صرفاً از روی ترتیب حدس نزنید. لاگ و diff دقیق کامیت راهنما را بازبینی کرده و کد هش آن را استخراج کنید:
HEAD~1):Add lantern signal guide را یادداشت کنید تا در دستور Cherry-pick استفاده شود.ایستادن روی مقصد پیش از انتخاب
دستور git cherry-pick همواره تغییرات را روی HEAD فعلی اعمال میکند. بنابراین باید ابتدا روی شاخه مقصد (main) بایستید:
main بیتغییر باقی خواهد ماند!بازسازی فقط Commit راهنما
اکنون کد هش یادداشتشده کامیت راهنما را جلوی دستور git cherry-pick قرار داده و اجرا کنید:
main پیاده کرد و کامیت جدیدی با همان پیام و محتوا ساخت.اثبات اینکه پیشنویس وارد نشد
برای اثبات اینکه فایل پیشنویس draft-banner.txt وارد شاخه اصلی نشده، درخت فایلها و لاگ گرافیکی را چک کنید:
signal-guide.txt در main قرار گرفته است. تغییر راهنما روی شاخه آزمایشی و main دیده میشود. اگر والد، محتوا و تمام فرادادهها یکسان باشند، حتی شناسه commit ممکن است همان بماند؛ تفاوت هش شرط موفقیت این تمرین نیست.وقتی انتخاب وسط راه متوقف میشود
اگر تغییرات کامیت منتخب با فایلهای شاخه مقصد تداخل داشته باشد، Git پروسه را متوقف میکند تا تعارض را حل کنید:
git cherry-pick -n COMMIT_HASH تغییرات فقط در Working Tree و Index اعمال میشوند اما کامیت خودکار ساخته نمیشود.انتخاب یک Commit یا پذیرفتن یک مسیر؟
شاخه یک همتیمی دارای پنج کامیت است که هر پنج تغییر برای محصول نهایی آمادهاند. آیا Cherry-pick کردن تکتک آنها بهترین انتخاب است؟ چه زمانی Merge و چه زمانی Cherry-pick مناسبتر است؟
کنارگذاشتن Branch آزمایشی با آگاهی
شاخه آزمایشی هنوز کامیت پیشنویس ادغامنشده دارد و مأموریتش تمام شده است. با آگاهی کامل آن را با پرچم -D حذف کنید:
-d اگر شاخه کامیت ادغامنشده داشته باشد اجازه حذف نمیدهد؛ اما پرچم -D حذف را بهصورت اجباری انجام میدهد.پیام مفید رسید، بار اضافه نرسید
در این درس یاد گرفتید چگونه فقط تغییرات آماده را بدون وارد کردن کارهای نیمهکاره دستچین کنید:
git cherry-pick COMMIT_HASH در بازسازی تغییرات روی HEAD.git log و git show.--continue و --abort.git branch -D.در درس بعدی، دو کامیت محلی را روی یک پایه تازه بازپخش خواهیم کرد. آنجا تغییر کد هشها را قبل و بعد از git rebase مقایسه میکنیم!
درس 3: صف تازه برای گزارش رسیدن
گزارشی که از کاروان عقب مانده است
کاتب روی یک شاخه جدید، دو بخش از گزارش رسیدن کاروان را مینویسد. در همان زمان، دفتر اصلی پروژه روی main یادداشت تازهای دریافت میکند؛ حالا شاخه گزارش بر پایه یک Commit قدیمیتر ایستاده است.
هدهد میخواهد گزارش محلی پیش از تحویل نهایی، روی تازهترین نقطه main بازپخش شود تا تاریخچهای کاملاً خطی و یکدست داشته باشیم. عطار در وادی توحید مفهوم عمیق فرارفتن از اعداد را چنین بیان میکند:
نیست آن یک کان احد آید ترا
زان یکی کان در عدد آید ترا
چون برونست از احد وین از عدد
از ازل قطع نظر کن وز ابد
مأموریت این درس، بازپخش کامیتهای شاخه خصوصی با دستور git rebase روی پایه جدید شاخه main، درک تفاوت Rebase و Merge و علت تغییر کد هش کامیتهاست.
بازپخش روی پایهٔ تازه
وقتی روی شاخه ویژگی ایستادهاید و دستور git rebase main را اجرا میکنید، گیت کامیتهای این شاخه را موقتاً کنار گذاشته، نوک شاخه را روی main جدید قرار میدهد و کامیتها را به ترتیب بازپخش میکند:
main در طی عملیات Rebase جلو نمیرود؛ فقط شاخه فعلی به بالای main منتقل میشود.مرز امن بازنویسی تاریخچه
دستور Merge ساختار دو خط تاریخچه را حفظ میکند؛ اما Rebase هویت کامیتهای بازپخششده را تغییر میدهد. بنابراین قانون طلایی Rebase این است:
کامیتهایی که هنوز Push نشدهاند یا کس دیگری روی آنها کار نمیکند. Rebase عالی، تمیزکننده و ایمن است.
کامیتهایی که Push شده و اعضای تیم کدهای خود را روی آن بنا کردهاند. هرگز Rebase نکنید!
ساخت Branch خصوصی گزارش
از وضعیت تمیز شاخه اصلی main، شاخه گزارش رسیدن را ایجاد کنید:
بخش اول گزارش رسیدن
فایل جدید arrival-report.txt را با متن اولیه زیر بسازید و Commit کنید:
arrival-report.txt با محتوای زیر:بخش دوم گزارش رسیدن
خط جدیدی به انتهای فایل اضافه کرده و Commit دوم را بسازید:
arrival-report.txt:عکس قبل از بازنویسی
برای اینکه تغییر کد هشها را پس از Rebase لمس کنید، یک Tag موقت روی نوک فعلی شاخه بگذارید:
جلو رفتن مستقل main
به شاخه main برگردید و Commit جدیدی بسازید تا شاخه اصلی یک قدم جلو برود:
journey-notes.txt با محتوای زیر:main یک کامیت جلو رفت در حالی که شاخه feature/arrival-report بر پایه کامیت قبلی main ساخته شده بود.دیدن واگرایی پیش از تصمیم
گراف انشعاب شاخهها را قبل از اجرای Rebase بازبینی کنید:
main یک مسیر و شاخه feature/arrival-report مسیر دیگری را طی کردهاند. اکنون زمان همصف کردن آنها با Rebase است.بازپخش دو Commit روی main
روی شاخه گزارش سوئیچ کرده و دستور git rebase main را اجرا کنید:
main بازنویسی و منتقل شدند.هویت تازه، محتوای آشنا
حالا کد هشهای جدید را با Tag موقت before-rebase مقایسه کنید:
تحویل خطی بدون Merge Commit
چون شاخه گزارش اکنون کاملاً خطی و جلوی main قرار دارد، آن را با --ff-only ادغام کرده و شاخهها و تگهای موقت را پاک کنید:
ممیزی پایان وادی
وضعیت نهایی مخزن را ممیزی کنید:
main و Tag رسمی v0.7.0 باقی ماندهاند و مخزن کاملاً منظم است.آیا هر Branch منتشرشده ممنوع است؟
یک Branch شخصی را دیروز Push کردهاید، اما هیچکس آن را دریافت نکرده یا کارش را بر کامیتهایش نساخته است. آیا Rebase مطلقاً ممنوع است؟ معیار تصمیم و خطر اصلی چیست؟
نشان نگهبان یک تاریخچهٔ روشن
تبریک! شما فصل ششم را با موفقیت پشت سر گذاشتید و با سه ابزار قدرتمند Git برای کنترل تاریخچه آشنا شدید:
git tag -a.git cherry-pick.git rebase.کاروان اکنون آماده ورود به وادی هفتم (وادی حیرت) است، جایی که ارتباط مخزن محلی روی سیستم با مخزن ابری در GitHub برپا خواهد شد!
بعد ازین وادی حیرت آیدت
کار دایم درد و حسرت آیدت
هر نفس اینجا چو تیغی باشدت
هر دمی اینجا دریغی باشدت
فصل 7: وادی حیرت
درس 1: نشانی آشیانه، نه خود آشیانه
دفتر محلی و آشیانهای که هنوز خالی است
پروژه simorgh-journey اکنون روی رایانه کاتب تاریخچهای کامل دارد؛ اما اگر سیستم آسیب ببیند یا همتیمی بخواهد آن را ببیند، این دفتر محلی به تنهایی کافی نیست. کاروان به یک Remote Repository احتیاج دارد تا Git بتواند با آن داده رد و بدل کند.
این نخستین قدم در وادی حیرت است: یک پروژه میتواند در چند مکان مختلف تاریخچه داشته باشد، اما هیچ نسخهای خودبهخود و بدون فرمان ما از نسخه دیگر باخبر نمیشود! باید آدرس مقصد را تعریف و سپس آگاهانه Fetch یا Push کنیم.
بعد ازین وادی حیرت آیدت
کار دایم درد و حسرت آیدت
هر نفس اینجا چو تیغی باشدت
هر دمی اینجا دریغی باشدت
origin و تست دسترسی اولیه، بدون ارسال هیچ کامیت یا برچسبی.Local و Remote دو مخزن مستقلاند
مخزن محلی (Local Repository) شامل Working Tree و دیتابیس .git روی سیستم شماست. مخزن روی GitHub مخزنی کاملاً جداگانه است؛ میتواند Commitهایی داشته باشد که نسخه محلی ندارد و برعکس.
عبارت Remote در تنظیمات Git محلی، فقط یک نام کوتاه برای URL مخزن دیگر و قواعد دریافت داده از آن است. افزودن Remote هیچ فایل یا کامیتی را منتقل نمیکند؛ بلکه فقط راه ارتباطی را تعریف مینماید.
مخزن روی سیستم شما با دیتابیس .git و تمام شاخهها و کامیتهای محلی.
مخزن آنلاین روی GitHub یا سرور دوردست که نقش مرکز هماهنگی و پشتیبان پروژه را دارد.
تحویل تمیز فصل قبل
پیش از اتصال به Remote، مطمئن شوید که روی شاخه اصلی main قرار دارید و وضعیت مخزن کاملاً تمیز است:
main باشید.v0.7.0 در لیست برچسبها دیده شود.ساخت مقصد خالی در GitHub
این بخش به اینترنت و حساب شخصی GitHub نیاز دارد. اگر حساب نداری، ابتدا حساب را بساز و مراحل تأیید آن را کامل کن. برای مخزن تمرینی عمومی فقط دادههای نمایشی دوره را منتشر کن؛ هیچ راز یا اطلاعات خصوصی واقعی وارد فایلها نشده باشد.
در GitHub یک Repository تازه با نام دقیق simorgh-journey بسازید. برای ادامه ساده دوره، تنظیمات را روی حالت Public بگذارید:
+ در بالا راست کلیک کرده و New repository را بزنید.simorgh-journey بگذارید.Create repository کلیک کرده و لینک HTTPS آن را کپی کنید.یک نام کوتاه برای یک مقصد دور
نام origin قرارداد رایج در Git برای Remote اصلی است، اما واژهای جادویی یا اجباری نیست. در هر Repository محلی میتوانید چند Remote با نامهای متفاوت داشته باشید.
فلشهای نمودار زیر امکان ارتباط را نشان میدهند. تا زمانی که فرمانی مانند Fetch یا Push اجرا نشود، دو Repository کاملاً مستقل میمانند.
upstream یا backup نیز تعریف کنید.ثبت origin با URL واقعی
در این قدم، origin باید به مخزن simorgh-journey در حساب خودت اشاره کند. مخزن رسمی فایلهای دوره فقط محل دریافت بستهٔ شروع است؛ URL آن را جای آدرس نمونهٔ فرمان زیر نگذار.
ابتدا عدم وجود Remote را بررسی کرده، سپس URL واقعی اکانت خود را جای عبارت نمونه بگذارید:
git remote -v آن را بررسی کرده و در صورت نیاز URL را ویرایش کنید.دیدن URL دریافت و ارسال
آدرس ذخیرهشده را از دو راه مختلف بررسی کنید:
پشت صحنهٔ Remote در تنظیمات Git
دو بخش مهم تنظیم محلی Remote را مستقیماً از فایل تنظیمات Git بخوانید:
+refs/heads/*:refs/remotes/origin/* مشخص میکند که شاخههای مقصد هنگام Fetch در کدام فضای محلی ثبت شوند.آزمون دسترسی بدون انتقال پروژه
از Git بخواهید ارجاعات (References) مقصد را بدون دریافت داده فهرست کند:
چرا Remote هنوز پشتیبان نیست؟
کاتب فرمان git remote add origin URL را اجرا کرده و سپس سیستمش خاموش و فایلهای محلی آسیب میبینند. چرا فقط اضافه کردن origin نسخه پشتیبان نساخته بود؟
پل ساخته شد، نامه هنوز اینجاست
اکنون پروژه محلی یک Remote به نام origin با URL واقعی دارد و دسترسی آن را بدون انتقال تاریخچه آزمودهاید:
origin را ثبت و با دستورهای git remote -v و ls-remote تست کردید.v0.7.0 را به GitHub انجام خواهیم داد!درس 2: اولین تحویل به GitHub
نامهای که باید مقصد دقیق داشته باشد
نشانی آشیانه ثبت شده، اما Git هنوز نمیداند کدام شاخه محلی باید با کدام شاخه دوردست جفت شود. نخستین ارسال باید هم شاخه main را منتقل کند و هم رابطه پیگیری (Upstream Tracking) آن را مشخص سازد.
در وادی حیرت، هر قدم پرسشی تازه میسازد. اینجا هم موفقشدن یک Push پایان بررسی نیست؛ باید بدانیم چه ارجاعاتی (References) فرستاده شدهاند، چه چیزهایی مثل Tag جا ماندهاند و Upstream دقیقاً چه کمکی میکند.
هر نفس اینجا چو تیغی باشدت
هر دمی اینجا دریغی باشدت
آه باشد، درد باشد، سوز هم
روز و شب باشد، نه شب نه روز هم
-u، بررسی Upstream، ارسال صریح Tag، ایجاد کامیت جدید محلی، مشاهده ahead 1 و در نهایت Push کوتاه پایانی.Push چه چیزی را بهروز میکند؟
فرمان git push آبجکتهای لازم را فرستاده و از Remote میخواهد ارجاع (Reference) مقصد را بهروز کند. در دستور git push -u origin main، مقصد ریموت origin و شاخه منبع main است.
سوئیچ -u یا --set-upstream رابطه پیگیری میان main محلی و origin/main را در تنظیمات محلی ثبت میکند؛ بنابراین فرمانهای بعدی مقصد پیشفرض و وضعیت ahead/behind را میشناسند.
git push تمام کامیتها و شیءهای جدید محلی را به دیتابیس آنلاین فرستاده و اشارهگر origin/main را بهروز میکند.-u رابطه پیگیری دائمی بین main محلی و origin/main ریموت ایجاد میکند.status عینا به شما میگوید چند کامیت از سرور جلوتر یا عقبتر هستید.git push -u origin main، در دفعات بعدی فقط کافیست دستور کوتاه git push را اجرا کنید.بازبینی پیش از نخستین ارسال
شاخه، وضعیت status و آدرس ریموت را پیش از اولین انتقال دوباره بررسی کنید:
main باشید.origin باید به اکانت خودتان در GitHub اشاره کند.فرستادن main و ساخت Upstream
نخستین ارسال شاخه اصلی را همراه با پرچم -u انجام دهید:
دیدن رابطهٔ پیگیری
پس از Push موفق، جفتشدن شاخهها را از چند زاویه بررسی کنید:
## main...origin/main نشان میدهد شاخه محلی شما عینا با ریموت هماهنگ است و هیچ کامیت جلوتر یا عقبتری ندارد.Tag با Push شاخه سفر نکرد
فرمان git push عادی شاخهها، الزاماً Tagهای محلی را نمیفرستد! ابتدا Tag محلی را مشاهده کرده و سپس همان نسخه رسمی را صریحاً ارسال کنید:
git push --tags استفاده کنید، اما ارسال دانه به دانه تگهای رسمی مانند v0.7.0 دقت و امنیت بیشتری دارد.بازبینی تحویل در GitHub
صفحه Repository خود را در GitHub تازه کنید. فایلهای پروژه را باز کرده و سپس بخش Tags یا Releases را ببینید:
Tags را باز کنید و وجود v0.7.0 را تأیید نمایید.git rev-parse --short HEAD گرفته و با GitHub مقایسه کنید.یک چکلیست برای ارسالهای بعدی
در ریشه پروژه فایل چکلیست sharing-checklist.txt را بسازید:
sharing-checklist.txt را ساخته و متن زیر را در آن قرار دهید:Local یک Commit جلوتر است
پیش از Push دوم، اختلاف قابل دسترسی بودن Commitها را مشاهده کنید:
[ahead 1] نشان میدهد دیتابیس محلی شما دقیقاً ۱ کامیت جدید دارد که هنوز روی سرور آنلاین فرستاده نشده است.Push کوتاه با مقصد شناختهشده
به کمک Upstream تنظیمشده در قدم ۴، اکنون اجرای فرمان کوتاه کافی است:
ahead حذف شد و هر دو مخزن محلی و ابری عینا روی یک کامیت همنقطه شدند.چرا Push ممکن است رد شود؟
همتیمی شما کامیت تازهای روی origin/main فرستاده و Local شما آن را ندارد. چرا یک Push عادی ممکن است با خطای non-fast-forward رد شود و قدم امن بعدی چیست؟
دو سوی مسیر همنقطه شدند
شاخه main و Tag رسمی روی GitHub قرار گرفتهاند، Upstream تنظیم شده و چکلیست اشتراکگذاری نیز با Push کوتاه به مقصد رسیده است:
git push -u origin main.v0.7.0.git push کوتاه به لطف Upstream.درس 3: خبر رسید، دفتر تکان نخورد
دیدن خبر پیش از پذیرفتن آن
روی GitHub خبر تازهای در گزارش مسیر ثبت شده، اما کاتب نمیخواهد فایلهای روی دستگاه ناگهان تغییر کنند. او ابتدا فقط دادههای جدید را میگیرد تا بداند چه کسی چه چیزی را عوض کرده است.
در وادی حیرت، ندانستن با نگاه دقیق پاسخ میگیرد، نه با حدس! Fetch همین فاصله امن را میدهد: خبر Remote به Repository محلی میرسد، اما شاخه جاری و Working Tree هنوز تصمیم نگرفتهاند آن را بپذیرند.
مرد حیران چون رسد این جایگاه
در تحیر مانده و گم کرده راه
هرچ زد توحید بر جانش رقم
جمله گم گردد ازو، گم نیز هم
Fetch نقشهٔ محلی Remote را تازه میکند
فرمان git fetch origin آبجکتها و ارجاعات (References) اعلامشده از مقصد را دریافت میکند. طبق RefSpec معمول، شاخه main دوردست در مرجع محلی origin/main بازتاب پیدا میکند.
شاخه origin/main خودِ شاخه زنده روی GitHub نیست؛ بلکه آخرین وضعیت شناختهشده آن در دیتابیس محلی شماست. Fetch آن را تازه میکند، ولی main، Index و Working Tree سیستم شما را جابهجا نمیکند.
git fetch origin تمام کامیتها و شیءهای جدید را از سرور دانلود کرده و در دیتابیس محلی قرار میدهد.origin/main محلی به جدیدترین کامیت سرور منتقل میشود تا آخرین وضعیت آنلاین را بازتاب دهد.main، فایلهای روی دیسک و Working Tree شما کاملاً دستنخورده و بدون تغییر میمانند.origin/main شاخه زنده سرور نیست؛ بلکه آخرین عکس ثبتشده از سرور در دیتابیس محلی شماست.ثبت وضعیت شناختهشده پیش از خبر
پیش از ساخت تغییر دوردست، همنقطه بودن دو Reference و محتوای فایل را بررسی کنید:
ساخت یک Commit در سمت GitHub
در صفحه GitHub فایل journey-notes.txt را باز و ویرایش کنید. این خط را به انتهای آن بیفزایید:
main با پیام Review checkpoint from GitHub.Local هنوز از خبر بیاطلاع است
بدون اجرای Fetch، همان فرمانهای محلی را تکرار کنید تا بیاطلاعی Git ثابت شود:
دریافت خبر بدون ادغام
اکنون داده تازه را با دستور Fetch از مقصد دریافت کنید:
[behind 1] را نشان میدهد؛ یعنی داده دریافت شده اما Working Tree هنوز دستنخورده مانده است.سه Reference، سه نقش متفاوت
موقعیت شاخه جاری (main)، اشارهگر ریموت محلی (origin/main) و آخرین Commit را کنار هم ببینید:
main و HEAD روی جای قبلی ایستادهاند، در حالی که origin/main کد هش جدید سرور را دارد.خواندن Commitی که فقط Remote دارد
پیش از هرگونه ادغام، Commit و تغییر فایل را در لاگ و diff بازبینی کنید:
دیدن Branchهای شناختهشدهٔ Remote
ارجاعات ردیابی ریموت (Remote-tracking References) را در سیستم محلی فهرست کنید:
origin/* فقطخواندنی هستند و کار روزمره و کامیتهای شما روی شاخه محلی main انجام میشود.Fetch برای چند مقصد و پاکسازی نقشه
فرمان git fetch --all همه Remoteهای تعریفشده را دریافت میکند. همچنین git fetch --prune origin مرجعهای ردیابی که شاخهشان در سرور حذف شده را پاک مینماید.
--prune باعث میشود شاخههای ریموت محلی که از روی سرور پاک شدهاند، از نقشه محلی شما نیز حذف شوند.چرا فایل پس از Fetch تغییر نکرد؟
Fetch موفق بوده و origin/main جلو رفته است، اما فایل journey-notes.txt روی دیسک هنوز خط تازه را ندارد. آیا داده دانلود نشده است؟ توضیح دهید چه چیزی تغییر کرده و چه چیزی نه.
خبر در دسترس است، تصمیم هنوز نه
کامیت دوردست اکنون در دیتابیس Local و پشت نام origin/main قابل مشاهده است؛ با لاگ و Diff آن را خواندید، اما main و فایلهای جاری عمداً دستنخورده ماندند:
origin/main را عینا مشاهده کردید.git log main..origin/main و git diff تغییرات آنلاین را پیش از اعمال بررسی کردید.درس 4: وقتی هر دو سوی دفتر جلو رفتهاند
خبر دیده شده؛ حالا نوبت تصمیم است
کاتب Commit تازه GitHub را با Fetch دیده و Diff آن را خوانده است. چون main محلی تغییر مستقلی ندارد، میتوان خبر را بدون ساخت Merge Commit پذیرفت؛ اما مرحله بعد آسانتر نیست، چون هر دو سمت به صورت مستقل جلو خواهند رفت.
در وادی حیرت، مرز «این سو» و «آن سو» روشن نمیماند. در Git نیز واگرایی (Divergence) یعنی Local و Remote هر کدام Commitی دارند که دیگری ندارد؛ راه حل از روی شکل تاریخچه و قرارداد تیم انتخاب میشود.
در میانی یا برونی از میان
بر کناری یا نهانی یا عیان
فانیی یا باقیی یا هر دوی
یا نهٔ هر دو توی یا نه توی
Pull یعنی Fetch و سپس یکپارچهسازی
فرمان git pull ابتدا Fetch میکند و سپس شاخه دریافتشده را با شاخه جاری یکپارچه میسازد. روش یکپارچهسازی میتواند Merge، Rebase یا فقط Fast-forward باشد.
پس فرمول ساده «Pull = Fetch + Merge» همیشه دقیق نیست! پیش از اجرای Pull باید بدانید روی کدام شاخه هستید، Upstream چیست و در صورت واگرایی کدام سیاست را میخواهید.
origin/main را به روز میکند.پذیرفتن خبر فقط با Fast-forward
در پایان درس قبل main محلی فقط عقب بود. Pull را طوری اجرا کنید که اگر این فرض غلط بود، Merge Commit ناخواسته ساخته نشود:
main محلی بدون ساخت کامیت اضافه پیش برده شد.اثبات ورود خبر به Working Tree
محتوا و همنقطه بودن دو سمت را در Working Tree و دیتابیس گیت بررسی کنید:
Remote checkpoint: Reviewed اکنون در فایل قرار دارد و هر دو اشارهگر همنقطهاند.سه پاسخ برای تاریخچهٔ واگرا
اگر هر دو سمت جلو رفته باشند، پرچم --ff-only متوقف میشود. پرچم --no-rebase با Merge تاریخچهها را پیوند میدهد و پرچم --rebase کامیتهای محلی را بازپخش مینماید.
یک کامیت ادغام (Merge Commit) میسازد و تاریخچه دو شاخه را پیوند میدهد.
کامیتهای محلی شما را موقتاً برداشته، ریموت را اعمال کرده و کامیتهای شما را روی آن بازپخش میکند (تاریخچه خطی).
git pull --rebase باعث جلوگیری از کامیتهای تکراری ادغام و حفظ تاریخچه تمیز و خطی میشود.ساخت خبر دوم در Remote
در GitHub و روی شاخه main فایل تازه remote-observation.txt را بسازید:
remote-observation.txt را با محتوای زیر در GitHub ایجاد کنید:Add an observation from the remote nest مستقیم روی سرور کامیت کنید.ساخت Commit مستقل در Local
در نسخه محلی این خط را به انتهای journey-notes.txt اضافه کنید:
دیدن واگرایی پیش از Pull
نقشه Remote را با Fetch تازه کنید و میزان واگرایی را اندازه بگیرید:
## main...origin/main [ahead 1, behind 1] نشان میدهد هر دو سمت ۱ کامیت جلوتر از نقطهانشعاب مشترک هستند.Pull با بازپخش Commit محلی
چون کامیت محلی خصوصی است و دو تغییر روی فایلهای متفاوتاند، Pull مبتنی بر Rebase را اجرا کنید:
همان تغییر با Hash تازه
نتیجه Rebase را با Tag موقت مقایسه کنید و سپس نشانه آزمایش را حذف نمایید:
[ahead 1] قرار گرفت.فرستادن نتیجهٔ یکپارچه
نتیجه خطی یکپارچهشده را به GitHub بفرستید و همنقطه بودن دو سوی مسیر را کنترل کنید:
اگر Pull وسط Conflict متوقف شد
در یک پروژه دیگر، git pull --rebase روی Conflict متوقف شده است. پس از حل فایل چه فرمانهایی لازماند و اگر بخواهید کل عملیات را لغو کنید چه میکنید؟
git rebase --continue یا --abort و برای pull بستر merge از git merge --abort استفاده کنید.دو تاریخچه دوباره هممسیر شدند
یک بار main را فقط Fast-forward کردید و بار دوم واگرایی واقعی را با بازپخش کامیت خصوصی حل نمودید. سپس نتیجه را Push کردید تا هر دو سمت دوباره همنقطه شوند:
git pull --ff-only برای پذیرش امن تغییرات بدون ساخت کامیت اضافی.ahead 1, behind 1).git pull --rebase برای ایجاد تاریخچه خطی و تمیز.درس 5: یک دستگاه دیگر، همان سفر
دفتر تازهای که گذشته را هم میشناسد
پرندهای تازه میخواهد از دستگاه دیگری به سفر بپیوندد. دانلود چند فایل آخر کافی نیست؛ او باید Commitها، Branchهای قابلمشاهده، Tag نسخه و نشانی Repository اصلی را هم داشته باشد.
در پایان حیرت، سالک هم دل پرعشق دارد و هم خود را تهی میبیند. Clone نیز نسخهای مستقل میسازد که در آغاز با مقصد همنقطه است، اما پس از آن میتواند راه محلی خودش را طی کند.
عاشقم اما ندانم بر کیم
نه مسلمانم نه کافر، پس چیم
لیکن از عشقم ندارم آگهی
هم دلی پرعشق دارم هم تهی
Clone چه چیزی میسازد؟
فرمان git clone URL DIRECTORY یک پوشه تازه، Working Tree شاخه آغازین و Repository محلی با دیتابیس .git میسازد. Remote مبدأ معمولاً خودکار با نام origin ثبت میشود.
Clone عادی تمام تاریخچه لازم و Remote-tracking References را دریافت میکند، اما از هر شاخه دوردست یک شاخه محلی قابل-Commit نمیسازد؛ فقط شاخه آغازین Checkout میشود.
انتخاب آزمایشگاه بیرون از پروژه
یک پنجره ترمینال تازه باز کن و به پوشهای برو که داخل پروژه فعلی نباشد. پوشه آزمایش را بساز:
ساخت Working Copy دوم
اینجا مخزن شخصی خودت را که در درسهای همین فصل push کردهای clone میکنی، نه مخزن رسمی دوره. عبارت YOUR_GITHUB_USERNAME را با نام حساب خودت جایگزین کن تا تاریخچه و فایلهای ساختهشده تا این نقطه وارد نسخهٔ دوم شوند.
نشانی URL واقعی پروژه را جایگزین و Clone را در پوشه مشخص بساز:
ممیزی اجزای Clone
وجود Working Tree، دیتابیس و تنظیم Remote را در نسخه کلونشده بررسی کن:
main تمیز و در حال پیگیری origin/main باشد.v0.7.0 باید به طور کامل منتقل شده باشد..git باید به صورت یک دایرکتوری معتبر وجود داشته باشد.تطبیق تاریخچه با نسخهٔ دور
نوک Local و Remote-tracking Reference و فایلهای اصلی را مقایسه کن:
HEAD محلی و origin/main باید دقیقاً یکسان و برابر با نسخه سرور باشند.چرا ZIP جای Clone را نمیگیرد؟
دانلود ZIP فقط یک عکس لحظهای (Snapshot) از فایلها میدهد، اما Repository محلی، تاریخچه کامیتها، شاخهها و Remote آماده ندارد.
فقط فایلهای پروژه بدون هیچ تاریخچه کامیت یا پوشه .git یا آدرس remote.
تاریخچه کامل کامیتها، تمام تگها، تنظیمات origin و دیتابیس .git کامل.
--depth 1 یک Shallow Clone با تاریخچه محدود میسازد، اما برای پروژههای عادی Clone معمولی بهترین گزینه است.ثبت حضور دستگاه دوم
داخل پوشه fresh-copy فایل clone-note.txt را بساز:
تغییر را بازبینی و کامیت کن:
main ایجاد کرده است.فرستادن Commit از Clone دوم
چون Clone رابطه Upstream را ساخته است، کامیت را با فرمان کوتاه بفرست:
ahead 1 و پس از آن وضعیت همگام دیده شود. این Push، ریپازیتوری دستگاه اول را خودکار تغییر نمیدهد.دیدن خبر دستگاه دوم در نسخهٔ اول
به پنجره ترمینال Repository اصلی (simorgh-journey) برگرد. بدون Pull، فقط نقشه Remote را تازه و کامیت دستگاه دوم را بررسی کن:
[behind 1]) و فایل clone-note.txt هنوز در Working Tree آن ظاهر نشده باشد.بستن حلقهٔ همکاری میان دو نسخه
چون نسخه اول کامیت محلی تازهای ندارد، خبر را فقط با Fast-forward بپذیر:
Clone کدام Branchها را محلی میکند؟
Remote پنج Branch دارد. پس از Clone، چرا معمولاً فقط Branch آغازین در git branch دیده میشود، اما نامهای بیشتری در git branch -r هستند؟
نشان نگهبان دو سوی سفر
از یک Repository محلی به یک چرخه واقعی همکاری رسیدی: مقصد را تعریف کردی، Branch و Tag را فرستادی، خبر Remote را بیخطر دیدی، واگرایی را حل کردی و از Clone دوم Commitی به نسخه اول رساندی.
پروژه اصلی روی main تمیز و با origin/main همنقطه است. کاروان اکنون آماده همکاری گستردهتر با Fork و Pull Request است.
بعد ازین وادی فقرست و فنا
کی بود اینجا سخن گفتن روا
عین وادی فراموشی بود
لنگی و کری و بیهوشی بود
git clone.fresh-copy).git fetch و git pull --ff-only.فصل 8: وادی فقر و فنا
درس 1: یک دفتر، دو راه مشارکت
در آستانه آخرین وادی
کاروان به آخرین وادی رسیده است. پرندگان هنوز دفترهای جداگانهای از مسیر دارند؛ هدهد از آنها میخواهد پیش از تحویل گزارش نهایی، راه افزودن و بررسی نوشتههای یکدیگر را روشن کنند.
در منطقالطیر، وادی فقر و فنا پایان خودبینی سالکان است. این مضمون زمینه روایت ماست؛ در پروژه واقعی قرار نیست فایل یا هویت کسی از بین برود، بلکه هر تغییر باید شفاف و قابلپیگیری بماند.
بعد ازین وادی فقرست و فنا
کی بود اینجا سخن گفتن روا
عین وادی فراموشی بود
لنگی و کری و بیهوشی بود
simorgh-journey را ادامه میدهیم.پیش از باز کردن دفتر
در ترمینال مخزن اصلی فصل هفتم این فرمانها را اجرا کن؛ در نسخه آزمایشی همتیمی یا پوشه یک Clone دیگر نباش:
origin مخزن حساب خودت در GitHub باشد. خروجی وضعیت باید خالی باشد؛ فایل ناتمام را آگاهانه commit یا stash کن.شروع از آخرین main
با درخت کاری تمیز به شاخه اصلی برگرد. ابتدا خبرهای ریموت را بگیر و سپس فقط جلو رفتن بدون ادغام را بپذیر:
--ff-only شکست خورد، تاریخچهها واگرا هستند؛ از reset یا force push استفاده نکن. اگر main محلی جلوتر است، با git push origin main آن را منتشر کن.کدام نسخه، کجا؟
Fork یک مخزن مرتبط روی اکانت سرور میسازد، Clone مخزن را همراه دیتابیس و تنظیمات به سیستم محلی میآورد، و Branch نامی جابهجاشونده برای یک کامیت در همان مخزن است.
برای مخزن خودت، شاخه و Pull Request در همان مخزن کافی است. برای مخزنی که اجازه Push مستقیم نداری، فورک میسازی و از شاخه فورک به مخزن مبدأ PR میفرستی.
کپی آنلاین مخزن دیگری در حساب GitHub تو برای مشارکت مستقل.
دانلود مخزن و دیتابیس .git به رایانه محلی برای کار روزمره.
نقشه ریموت خودت را بخوان
تنظیمات Remote و شاخه محلی خودت را چک کن:
origin نام قراردادی ریموت توست. عبارت upstream دو کاربرد دارد: نام ریموت مبدأ فورک، و شاخه دنبالشونده مثل origin/main.اگر مهمان پروژه دیگری بودی
برای این مسیر اختیاری، ابتدا مخزن عمومی شخص دیگری را در GitHub فورک کن؛ نام آزاد مثل simorgh-contribution انتخاب و فورک خودت را در یک پوشه جدا clone کن. origin در آن clone باید فورک خودت باشد. سپس URL مبدأ واقعی را جای ORIGINAL_OWNER بگذار. بدون این آمادهسازی، الگوی زیر را اجرا نکن. پس از مطالعه به مخزن اصلی دوره برگرد.
این مسیر اختیاری برای مشارکت در پروژههای متنباز دیگران است (در مخزن اصلی اجرا نکن):
قانون کوچک مشارکت
در ریشه پروژه فایل CONTRIBUTING.md را بساز:
اول ببین، بعد ثبت کن
تغییر فایل را بازبینی و کامیت کن:
قرارداد به لانه دور میرسد
کامیت را به GitHub ارسال کن و وضعیت را بررسی کن:
CONTRIBUTING.md را ببین.برای هر در، کلید خودش
مالک یک مخزن هستی؛ در مخزن دوم فقط اجازه خواندن داری. برای هرکدام مسیر Branch تا PR را توضیح بده. آیا Clone به تنهایی دسترسی Push ایجاد میکند؟
درس 2: گزارش سیامین مسافر
گزارشی که باید به جمع برسد
از آن همه پرنده، گروه کوچکی به درگاه رسیدهاند. در روایت ما هدهد میخواهد تعداد رسیدهها و نام آخرین مسافر ثبت شود، اما نوشته تازه پیش از ورود به دفتر اصلی باید بازبینی و تأیید شود.
عطار رسیدن اندک مسافران را پس از راهی بس دشوار روایت میکند. تمرین ما ثبت یک گزارش کوتاه است.
عاقبت از صد هزاران تا یکی
بیش نرسیدند آنجا اندکی
caravan-registry.txt را میسازیم و پیش از ادغام، برایش یک Pull Request ایجاد میکنیم.پیشنهاد، نه ادغام خودکار
Pull Request یا PR صفحه گفتوگو، بازبینی و بررسی تفاوت دو شاخه است. base شاخه مقصد و compare شاخه پیشنهاددهنده تغییرات است.
باز کردن PR هنوز شاخه مقصد را تغییر نمیدهد و push هم معادل ادغام نیست.
شاخه اصلی و مقصد نهایی که تغییرات قرار است به آن اضافه شود.
شاخه ویژگی که شامل کامیتهای پیشنهادی شماست.
شاخه گزارش را بساز
با وضعیت محلی تمیز، یک شاخه ویژگی جدید بساز:
یک گزارش سهخطی
در ریشه پروژه فایل تازه caravan-registry.txt را با این محتوا بساز (عمداً نقش آخرین مسافر را نمینویسیم تا بعداً بازبینی انجام شود):
بسته تغییر را وارسی کن
تغییرات را stage کرده و قبل از کامیت diff آن را دقیقاً چک کن:
ثبت و ارسال شاخه
تغییر را کامیت کن و شاخه جدید را به origin بفرست:
درخواست با مقصد مشخص
در مخزن خودت بخش Pull requests و سپس New pull request را باز کن. base را main و compare را feature/arrival-registry قرار بده. Files changed باید فقط گزارش سهخطی جدید را نشان بدهد.
شرحی که بازبین بتواند آزمایش کند
عنوان و شرح مناسبی برای PR خود بنویس:
فرق شاخهها را محلی ببین
تفاوت دو شاخه را روی سیستم خودت هم بررسی کن:
درخواست باز است؛ چرا سایت عوض نشد؟
یک Pull Request باز کردهای و تغییرات روی GitHub مشخص است؛ اما چرا هنوز شاخه اصلی main و سایت این تغییر را ندارند؟
درس 3: بازبینی با یک اصلاح واقعی
دوباره به نوشته نگاه کن
پرندگان کنار هم گزارش رسیدن را میخوانند. تعداد درست است، اما یک نفر میپرسد: آخرین مسافر چه مسئولیتی داشته؟ هدهد میخواهد این پرسش به یک اصلاح روشن تبدیل شود، نه قضاوت درباره نویسنده.
در پایان داستان، نگاه پرندگان به خود و جمع دگرگون میشود. اینجا هم بازخوانی جمعی چیزی را آشکار میکند که در اولین نوشتن ندیده بودیم.
چون نگه کردند آن سی مرغ زود
بیشک این سی مرغ آن سیمرغ بود
چه کسی چه اختیاری دارد؟
Code Review بررسی تغییر است؛ Comment نظر، Approve تأیید بازبین و Request changes درخواست اصلاح است.
تأیید به تنهایی نه ادغام میکند و نه تضمین میکند قواعد مخزن رعایت شدهاند.
ثبت نظر یا درخواست تغییر روی خطوط کد پیشنهادی.
تأیید نهایی و ادغام شاخه ویژگی در شاخه اصلی main.
نظر دقیق و محترمانه
در بخش Files changed درخواست، کنار خط Last traveler یک کامنت ثبت کن:
همان شاخه، اصلاح کوچک
روی سیستم محلی به همان شاخه ویژگی برو:
با وضعیت تمیز، خط زیر را به انتهای caravan-registry.txt اضافه کن (سه خط قبلی حفظ شوند):
پاسخ به بازبینی را ارسال کن
اصلاح جدید را کامیت و push کن تا همان PR بهروز شود:
قبل از ادغام، روش را انتخاب کن
Merge commit دو کامیت شاخه ویژگی را نگه میدارد و یک کامیت ادغام با دو والد میسازد.
Squash and merge تغییرها را در یک کامیت جدید روی مقصد جمع میکند. Rebase and merge کامیتها را خطی بازاعمال میکند.
حفظ تمام کامیتهای شاخه ویژگی + یک کامیت Merge شفاف.
ترکیب کامیتها در یک کامیت واحد یا بازپخش خطی آنها روی main.
بازبینی نهایی درخواست
در صفحه PR روی GitHub، بخش Files changed را بررسی کن تا مطمئن شوی ۴ خط فایل caravan-registry.txt کامل و تمیز دیده میشوند.
ادغام روی سرور
روی دکمه Merge pull request کلیک کن، گزینه Create a merge commit را انتخاب کرده و Confirm merge را بزن.
Pull request successfully merged and closed ظاهر میشود. اکنون میتوانی دکمه Delete branch را بزنی تا شاخه ریموت پاک شود.نسخه محلی را برسان
به شاخه main محلی برگرد و تغییرات ادغامشده را از سرور بگیر:
caravan-registry.txt و کامیت Merge است.اکنون که merge commit روی main دریافت شده، شاخه محلی تمامشده را هم جمع کن. حذف شاخه در GitHub، شاخه محلی را حذف نمیکند:
چرا درخواست تازه نسازیم؟
چرا برای اعمال نظر بازبین، کامیت جدید را روی همان شاخه push کردیم و یک Pull Request تازه نساختیم؟
درس 4: آزمایش یک چرخه انتشار
پیش از سپردن دفتر
کاروان گزارش نهایی را آماده کرده، اما هدهد دو کار را جدا میکند: جمع کردن نوشتههای تازه و آماده کردن نسخهای که دیگران خواهند خواند.
جدا کردن کارها زمانی ارزش دارد که آشفتگی را کمتر کند. صرفاً با نام شاخهها درباره کیفیتشان قضاوت نمیکنیم.
این به صورت هر دو یکسان باشدت
در صفت فرق فراوان باشدت
این نقشه برای هر تیم نیست
Git Flow یک قرارداد مدیریت شاخههاست: شاخه feature از develop جدا میشود؛ شاخه release برای آمادهسازی نسخه جدا شده و در نهایت هم به main و هم به develop ادغام میشود.
شاخه اصلی توسعه که ویژگیهای جدید در آن جمع میشوند.
شاخههای آمادهسازی انتشار و نسخه پایدار نهایی.
دو خط کار محلی
ابتدا مطمئن شو روی شاخه main و با وضعیت تمیز هستی، سپس شاخههای develop و feature را بساز:
یک ویژگی کوچک اما واقعی
فایل release-notes.txt را با محتوای اولیه بساز:
ویژگی به محل جمع شدن کار میرسد
شاخه feature را به develop ادغام کن و شاخه موقت را حذف کن:
آمادهسازی نسخه جدا میشود
شاخه release برای نسخه 1.0.0 بساز و Status را آماده انتشار کن:
در فایل release-notes.txt عبارت Status: Draft را به Status: Ready تغییر بده:
نسخه آماده به main میرود
شاخه release آماده را به main ادغام کن:
اصلاح انتشار گم نشود
تغییرات انجامشده در release (مثل تغییر Status به Ready) را به develop هم برگردان (Backport):
پیش از ادامه، نسخه فایل در هر دو شاخه را بخوان و مطمئن شو اصلاح آمادهسازی به هر دو رسیده است:
آزمایش را جمع کن
تغییرات آمادهشده روی main را به origin ارسال کن:
یک اصلاح جا مانده
چرا اصلاح انجامشده روی شاخه release/1.0.0 را علاوه بر main، به شاخه develop هم ادغام (Backport) کردیم؟
درس 5: نسخهای با نام روشن
آینهای از کار انجامشده
پرندگان روبهروی آینه میایستند. دفترشان دیگر وعدهای برای آینده نیست؛ گزارش رسیدن و اصلاحهایی است که واقعاً ثبت کردهاند. هدهد میخواهد این لحظه نامی مشخص داشته باشد تا بتوان دوباره به آن برگشت.
خویش را دیدند سیمرغ تمام
بود خود سیمرغ سی مرغ مدام
v1.0.0، متن وضعیت صفحه و معرفی پروژه را با خروجی واقعی هماهنگ میکنیم.نام نسخه دقیقاً چه میگوید؟
Tag نامی ثابت برای یک کامیت مشخص در تاریخچه است. تگ annotated پیام، نویسنده و تاریخ دارد.
در Semantic Versioning (نسخهگذاری معنایی)، فرمت MAJOR.MINOR.PATCH نشاندهنده میزان و نوع تغییرات است.
دارای پیام، نویسنده و تاریخ ثبت (مناسب نسخه رسمی).
فقط یک اشارهگر ساده به یک کامیت بدون متادیتای اضافی.
وضعیت صفحه با سفر هماهنگ شود
فقط متن داخل پاراگراف status در index.html را جایگزین کن؛ تگهای HTML را نگه دار. در journey-log.txt دو سطر نامبرده را جداگانه در محل فعلی تغییر بده، نه اینکه کل گزارش را با دو خط جایگزین کنی.
در شاخه main محلی، فایل index.html و journey-log.txt را بهروزرسانی کن:
در index.html متن status را به خط زیر تغییر بده:
در journey-log.txt مقادیر زیر را تنظیم کن:
معرفی صادقانه پروژه
در ریشه پروژه فایل README.md را بساز:
پیش از نامگذاری آزمایش کن
تغییرات را قبل از کامیت بازبینی کن:
خروجی نهایی را ثبت کن
تغییرات نهایی را کامیت کرده و به origin فرست:
تگ را روی جای درست بگذار
یک تگ رسمی annotated به نام v1.0.0 روی آخرین کامیت بساز:
مقصد تگ را با commit نهایی مقایسه کن:
ارسال فقط همین تگ
تگ ساختهشده را صریحاً به origin بفرست:
صفحه انتشار با تگ موجود
در GitHub وارد بخش Releases شو و یک Release جدید بر اساس تگ v1.0.0 بساز:
Releases در GitHub شو.Draft a new release کلیک کن.v1.0.0 موجود را انتخاب کن.Simorgh Journey 1.0.0 بگذار.release-notes.txt را در توضیحات قرار بده و دکمه Publish release را بزن.اشتباه بعد از انتشار
اگر بعد از انتشار v1.0.0 متوجه غلط املایی در README شدی، آیا باید تگ v1.0.0 را حذف یا جابهجا کنی؟ راه درست چیست؟
درس 6: دفتر سفر روی وب
دفتر از دست کاروان بیرون میرود
کاروان به پایان راه رسیده و حالا میخواهد دیگران هم دفتر سفر را بخوانند. هدهد میگوید فرستادن نشانی کافی نیست؛ باید از نگاه خوانندهای که فایلهای محلی ما را ندارد، صفحه را امتحان کنیم.
محو او گشتند آخر بر دوام
سایه در خورشید گم شد والسلام
main روی GitHub Pages منتشر میکنیم.میزبانی با نسخهگذاری فرق دارد
GitHub Pages فایلهای ایستا مانند HTML، CSS و تصاویر را روی وب میزبانی میکند. مخزن و Release به خودی خود سایت زنده نیستند.
سایت آنلاین زنده وب برای نمایش فایلهای ایستا به کاربران.
نقاط ثبتشده در تاریخچه برای دانلود سورسکد و نسخهها.
فایل ورودی روی سرور حاضر است؟
مطمئن شو فایل index.html روی main سرور با حروف کوچک وجود دارد:
منبع انتشار را تعیین کن
در مخزن GitHub وارد Settings → Pages شو و تنظیمات زیر را اعمال کن:
Build and deployment منبع را روی Deploy from a branch بگذار.main و پوشه را /(root) انتخاب کن.Save کلیک کن.منتظر نتیجه ساخت، نه حدس
وارد تب Actions شو و وضعیت انتشار GitHub Pages را ببین:
از چشم خواننده باز کن
لینک انتشار (مانند https://USERNAME.github.io/simorgh-journey/) را در یک پنجره Incognito مرورگر باز کن.
دفتر تحویل را کامل کن
نشانی نمونه را عیناً کپی نکن؛ آن را با URL واقعی که در قدم قبل باز کردی جایگزین کن. اگر انتشار اینترنتی در دسترس نبود، این قدم افزودن URL و commit آن را اجرا نکن و همان محدودیت را در تحویل بنویس.
آدرس سایت وب خودت را در انتهای README.md بیفزا:
پنجرهای اختیاری به jj
آشنایی کوتاه با سیستمهای مدرنتر کنترل نسخه مثل Jujutsu (jj):
jj ابزاری مدرن است که مفاهیم کامیت، شاخه و Working Copy را با سادگی بیشتر و مدیریت خودکار کامیتهای پیشفرض پیادهسازی میکند.
سایت جدید، نسخه قدیمی
اگر یک کامیت جدید روی main بزنید و push کنید، آیا سایت GitHub Pages خودکار بهروز میشود؟ اگر تگ جدید بزنید چطور؟
نشان سیمرغ با شاهد
برای تحویل، بهجای تکیه به پیام موفقیت، شاهدها را جمع کن: URL درخواست با وضعیت Merged، صفحه Release متصل به v1.0.0 و URL واقعی سایت که در پنجره خصوصی باز شده است. هر بخش در دسترس نبوده را صریحاً انجامنشده بنویس.
شاخه main و وضعیت و stash تمیز باشند؛ گزارش نسخه چهارخطی و یادداشت develop دارای Ready باشد. اگر قدم افزودن URL را انجام دادی، عدد آخر ۱ است؛ اگر بهعلت محدودیت انتشار آن را انجام ندادی، ۰ است. در هیچیک تگ را جابهجا نکن.