در این بخش دوم از مجموعه خود با عنوان “لغو اشتباهات با Git” ، ما با شجاعت دوباره خطر را در چشم خواهیم دید: من چهار سناریوی جدید برای روز قیامت آماده کرده ام – البته شامل برخی از روش های هوشمندانه برای نجات گردن ما! اما قبل از غواصی: نگاهی به مقاله های قبلی در Git بیاندازید تا روش های بیشتری برای نجات خودکار داشته باشید که به شما کمک می کند اشتباهات خود را با Git برطرف کنید!
بیا بریم!
بازیابی شعبه حذف شده با استفاده از Reflog
آیا تابحال شعبه ای را حذف کرده اید و اندکی بعد فهمیده اید که نباید آن را انجام می دادید؟ در یک احتمال بعید که شما این احساس را نمی دانید ، می توانم به شما بگویم که احساس خوبی نیست. مخلوطی از غم و عصبانیت شما را فرا می گیرد ، در حالی که شما به تمام کارهای سختی که متعهد آن شاخه است فکر می کنید ، همه رمز ارزشی که اکنون از دست داده اید.
خوشبختانه ، راهی وجود دارد که آن شاخه را از بین ببرد – با کمک یک ابزار Git به نام “Reflog”. ما در بخش اول سری خود از این ابزار استفاده کرده بودیم ، اما در اینجا کمی تازه سازی وجود دارد: Reflog مانند مجله ای است که Git هر حرکت اشاره گر HEAD را در مخزن محلی شما یادداشت می کند. به عبارت دیگر ، واژه های کمتر مزاحم: هر زمان که تسویه حساب کنید ، متعهد شوید ، ادغام شوید ، دوباره پایه بزنید ، گیلاس انتخاب کنید و غیره ، یک ورودی در ژورنال ایجاد می شود. این باعث می شود که Reflog به یک شبکه ایمنی کامل در هنگام خراب شدن کارها تبدیل شود!
بیایید نگاهی به یک مثال عینی بیندازیم:
$ git branch
* feature/login
master
می بینیم که در حال حاضر شعبه خود را داریم feature/login
بررسی شد بگذارید بگوییم این شاخه ای است که قصد حذف آن را داریم (سهوا). با این حال ، قبل از انجام این کار ، باید شاخه دیگری را تغییر دهیم زیرا نمی توانیم شاخه HEAD فعلی خود را حذف کنیم!
$ git checkout master
$ git branch -d feature/login
شاخه ویژگی های ارزشمند ما اکنون از بین رفته است – و من یک دقیقه به شما فرصت می دهم تا (الف) از شدت اشتباه خود مطلع شوید و (ب) کمی عزاداری کنید. بعد از اینکه اشک را پاک کردید ، باید راهی برای بازگرداندن این شاخه پیدا کنیم! بیایید Reflog را باز کنیم (به سادگی با تایپ کردن) git reflog
) و ببینید چه چیزی برای ما ذخیره کرده است:

در اینجا برخی از نظرات برای کمک به شما در درک نتیجه:
- اول از همه ، شما باید بدانید که Reflog ورودی های خود را به ترتیب زمانی مرتب می کند: جدیدترین موارد در بالای لیست هستند.
- بالاترین (و در نتیجه جدیدترین) مورد ، کالای موجود است
git checkout
دستوری که قبل از حذف شاخه اجرا کردیم. در اینجا در Reflog وارد شده است زیرا یکی از این “حرکات اشاره گر HEAD” است که Reflog آن را با رعایت وظایف لازم ثبت می کند. - برای لغو اشتباه فاحش خود ، می توانیم به سادگی به کشور برگردیم قبل از که – که به وضوح و به وضوح در Reflog ثبت شده است!
بنابراین بیایید این را امتحان کنیم ، با ایجاد یک شاخه جدید (با نام شاخه “گمشده” ما) که از این هش حالت “قبل” SHA-1 شروع می شود:
$ git branch feature/login 776f8ca
و voila! شما خوشحال خواهید شد که ببینید ما اکنون شاخه به ظاهر گمشده خود را بازیابی کرده ایم! 🎉
اگر از یک رابط کاربری گرافیکی دسک تاپ مانند «Tower»، می توانید یک میانبر خوب بگیرید: به سادگی ضربه بزنید CMD + با بر روی صفحه کلید خود برای خنثی کردن آخرین دستور – حتی اگر فقط با خشونت شاخه ای را حذف کرده باشید!
انتقال تعهد به شعبه دیگری
در بسیاری از تیم ها ، توافق نامه ای برای عدم تعهد در شاخه های طولانی مدت مانند وجود دارد main
یا develop
: شاخه هایی از این قبیل فقط باید تعهدات جدید را از طریق ادغام دریافت کند (به عنوان مثال ادغام یا دوباره سازی). و البته ، البته ، اشتباهات اجتناب ناپذیر است: ما بعضی اوقات این شاخه ها را فراموش کرده و مرتکب آن می شویم! بنابراین چگونه می توانیم ظرفیتی را که ایجاد کرده ایم پاک کنیم؟

خوشبختانه این نوع مشکلات به راحتی قابل اصلاح هستند. بیایید آستین بالا بزنیم و دست به کار شویم.
اولین قدم این است که به شاخه مقصد صحیح بروید و سپس مرتکب استفاده بیش از حد از آن شوید cherry-pick
دستور:
$ git checkout feature/login
$ git cherry-pick 776f8caf
اکنون تعهد خود را در شعبه مورد نظر ، جایی که در وهله اول قرار داشت ، خواهید داشت. عالی!
اما هنوز یک چیز باقی مانده است که باید انجام دهیم: ما باید شاخه ای را که در آن قرار دارد تمیز کنیم به طور تصادفی در ابتدا فرود آمد! cherry-pick
دستور ، به اصطلاح ، یک نسخه از تعهد را ایجاد کرد – اما نسخه اصلی هنوز در شاخه طولانی مدت ما وجود دارد:

این بدان معنی است که ما باید به شاخه طولانی مدت خود برگردیم و استفاده کنیم git reset
برای حذف آن:
$ git checkout main
$ git reset --hard HEAD~1
همانطور که می بینید ، ما از git reset
در اینجا دستور دهید تا تعهد معیوب را پاک کنید. HEAD~1
پارامتر به Git می گوید که “1 نسخه پشت سر HEAD برگرد” ، به طور موثر بالاترین (و در مورد ما: ناخواسته) تعهد را از تاریخچه آن شاخه پاک می کند.
و voila: تعهد اکنون همان جایی است که باید در وهله اول انجام می شد و شاخه طولانی مدت ما تمیز است – گویی که اشتباه ما هرگز اتفاق نیفتاده است!
ویرایش پیام یک تعهد قدیمی
قاچاق اشتباه تایپی به یک پیام متعهد بسیار آسان است – و فقط بعداً می توانید آن را کشف کنید. در چنین حالتی ، قدیمی خوب --amend
گزینه از git commit
برای رفع این مشکل نمی توان استفاده کرد ، زیرا فقط برای آخرین مرتکب کار می کند. برای اصلاح هر تعهدی که قدیمی تر از آن باشد ، باید به ابزاری Git به نام “Interactive Rebase” متوسل شویم.

ابتدا باید به Interactive Rebase بگوییم که می خواهیم کدام قسمت از تاریخچه مرتکب را ویرایش کنیم. این کار با تغذیه آن به یک هش متعهد انجام می شود: والدین مرتکب کسی شوید که می خواهیم آن را دستکاری کنیم.
$ git rebase -i 6bcf266b
سپس یک پنجره ویرایشگر باز می شود. این شامل لیستی از همه تعهدات است بعد از موردی که ما به عنوان مبنای Rebase Interactive در دستور ارائه دادیم:

در اینجا ، مهم است که شما نکن اولین انگیزه خود را دنبال کنید: در این مرحله ، ما انجام می دهیم نه هنوز پیام متعهد را ویرایش کنید. در عوض ، ما فقط به Git چه می گوییم نوعی دستکاری ما می خواهیم با کدام متعهد (ها) انجام دهیم. به راحتی ، لیستی از کلمات کلیدی عملی که در نظرات در پایین این پنجره ذکر شده است. برای پرونده ما ، خط شماره 1 را با مشخص می کنیم reword
(در نتیجه جایگزین استاندارد می شود pick
)
تنها کاری که باید در این مرحله انجام شود ذخیره و بستن پنجره ویرایشگر است. در عوض ، یک پنجره ویرایشگر جدید باز می شود که حاوی پیام فعلی تعهدی است که ما مشخص کردیم. و اکنون بالاخره زمان ویرایش های ما است!
در اینجا تمام مراحل در یک نگاه برای شما قرار داده شده است:
اصلاح یک عهد شکسته (به روشی بسیار زیبا)
در آخر ، ما می خواهیم نگاهی به آن بیندازیم fixup
، چاقوی ارتش سوئیس از ابزارهای خنثی کردن. به زبان ساده ، به شما امکان می دهد یک مرتکب شکسته / ناقص / نادرست را پس از واقعیت برطرف کنید. این به دو دلیل واقعاً ابزاری فوق العاده است:
- مهم نیست مشکل چیست.
ممکن است شما اضافه کردن یک پرونده را فراموش کرده باشید ، باید چیزی را حذف کرده باشید ، یک تغییر نادرست انجام دهید یا یک اشتباه تایپی داشته باشید.fixup
در همه این شرایط کار می کند! - بسیار ظریف است.
واکنش عادی و غریزی ما نسبت به اشکال موجود در تعهد ، تولید a است جدید متعهدی که مشکل را برطرف می کند. این روش کار ، هرچند که شهودی به نظر برسد ، باعث می شود خیلی زود سابقه متعهد بودن شما بسیار آشفته به نظر برسد. شما مرتکب “اصلی” شده اید و سپس این کمیته “باند-کمک” کوچک که اشتباهات اولیه را برطرف می کند. تاریخچه شما مملو از تعهدات کمکی باند و بی معنی است که درک آنچه در پایگاه کد شما اتفاق افتاده را دشوار می کند.

اینجاست که fixup
وارد می شود. به شما این امکان را می دهد که همچنان این باند-کمک را اصلاح کنید. اما در اینجا جادو می شود: سپس آن را در مورد عمل اصلی و شکسته اعمال می کند (آن را به این ترتیب ترمیم می کند) و سپس مرتکب کمک باند زشت را به طور کامل کنار می گذارد!

ما می توانیم یک مثال عملی را با هم مرور کنیم! بگذارید بگوییم که تعهد انتخاب شده در اینجا شکسته است

بیا همچنین بگویید که من تغییراتی را در پرونده ای به نام آماده کرده ام error.html
این مسئله را حل خواهد کرد. در اینجا اولین مرحله ای است که باید انجام دهیم:
$ git add error.html
$ git commit --fixup 2b504bee
ما در حال ایجاد یک تعهد جدید هستیم ، اما به Git می گوییم این یک تعهد ویژه است: این یک رفع مشکل برای یک تعهد قدیمی با هش مشخص شده SHA-1 است (2b504bee
در این مورد).
مرحله دوم ، اکنون شروع یک جلسه Interactive Rebase است – زیرا fixup
متعلق به مجموعه ابزارهای بزرگ Interactive Rebase است.
$ git rebase -i --autosquash 0023cddd
در مورد این دستور دو نکته قابل توضیح است. اول ، چرا تهیه کردم 0023cddd
به عنوان هش تجدید نظر در اینجا؟ زیرا ما باید جلسه Interactive Rebase خود را در تعهد والدین همکار شکسته خود شروع کنیم.
دوم ، چه چیزی است --autosquash
گزینه برای؟ کار زیادی از روی شانه های ما می گیرد! در پنجره ویرایشگر که اکنون باز می شود ، همه چیز از قبل برای ما آماده شده است:

با تشکر از --autosquash
گزینه ، Git قبلاً کار سنگین را برای ما انجام داده است:
- این تعهد کمربند کمکی ما را با
fixup
کلمه کلیدی اقدام به این ترتیب ، Git آن را مستقیماً با تعهد ترکیب می کند در بالا و سپس آن را دور بریزید. - همچنین خطوط را به ترتیب مرتب کرد ، و تعهد باند کمک ما را مستقیماً زیر تعهدی که می خواهیم برطرف کنیم حرکت می دهد (دوباره:
fixup
با ترکیب تعهد مشخص شده با یکی کار می کند در بالا!)
به طور خلاصه: هیچ کاری برای ما ندارد جز بستن پنجره!
بیایید نگاهی نهایی به نتیجه نهایی بیندازیم.
- تعهد شکسته قبلی ثابت است: اکنون شامل تغییراتی است که ما در تعهد کمک باند خود آماده کرده ایم.
- خود تعهد زشت کمک های باند کنار گذاشته شده است: تاریخچه مرتکب تمیز است و خواندن آن آسان است – گویی که اصلا اشتباهی رخ نداده است.

دانستن اینکه چگونه خطاها را لغو کنید یک ابرقدرت است
تبریک می گویم! اکنون در بسیاری از شرایط دشوار قادر به نجات گردن خود هستید! ما واقعاً نمی توانیم از این شرایط اجتناب کنیم: مهم نیست که ما به عنوان توسعه دهنده با تجربه هستیم ، اشتباهات صرفاً بخشی از کار هستند. اما اکنون که می دانید چگونه با آنها کنار بیایید ، می توانید با ضربان قلب آرام و آرام مواجه شوید. 💚
اگر می خواهید در مورد لغو اشتباهات با Git بیشتر بدانید ، می توانم “جعبه کمک های اولیه برای Git”، یک سری فیلم کوتاه در مورد دقیقاً همین موضوع.
از اشتباهات لذت ببرید – و البته لغو آنها را با سهولت انجام دهید!
