Git
Chapters ▾ 2nd Edition

2.4 مقدمات گیت - بازگردانی کارها

بازگردانی کارها

در هر مرحله، شاید بخواهید که چیزی را یا کاری را بازگردانی یا برگشت دهید. اینجا برخی ابزار پایه‌ای برای بازگردانی تغییرات و کارهایی که انجام داده‌اید را بررسی خواهیم کرد. توجه کنید، چرا که همیشه نمی‌توانید همهٔ همین بازگردانی‌ها را بازگردانی کنید. اینجا یکی از معدود حیطه‌های گیت است که اگر اشتباه انجامش دهید امکان دارد مقداری از کارتان از دست برود.

یکی از متداول‌ترین بازگشت‌ها زمانی است که شما خیلی زود کامیت می‌گیرید و احتمالاً فراموش می‌کنید چند فایی اضافه کنید یا یا پیام کامیت‌تان را خراب کرده‌اید. اگر می‌خواهید دوباره آن کامیت را بگیرید، تغییرات اضافه فراموش شده را اعمال کنید، آنها را استیج کنید و دوباره با استفاده از آپشن --amend کامیت کنید:

$ git commit --amend

این دستور استیج شما را دریافت می‌کند و از آن برای کامیت استفاده می‌کند. اگر از آخرین کامیتتان تغییری ایجاد نکرده باشید (برای مثال، دستور را به محض انجام کامیت قبلی اجرا کنید)، اسنپ‌شات شما دقیقاً به همان شکل خواهد بود و تمام چیزی که تغییر می‌کند فقط پیام کامیت شما است.

همان ویرایشگر پیام کامیت بالا می‌آید، اما از پیش حاوی پیام کامیت قبلی شما است. مثل همیشه می‌توانید پیام را مانند همیشه اصلاح کنید، اما این عمل کامیت قبلی را بازنویسی می‌شود.

برای مثال، اگر کامیت کنید و سپس متوجه شوید فراموش کرده‌اید که تغییراتی در فایل را که می‌خواستید به این کامیت اضافه کنید استیج کنید، می‌توانید چنین کاری کنید:

$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend

در نهایت کار شما با یک کامیت به پایان می‌رسد — کامیت دوم جایگزین نتایج کامیت اول می‌شود.

یادداشت

خیلی مهم است که بدانید که وقتی درحال امند کردن آخرین کامیت خود هستید، درواقع شما آن را آنچنان تعمیر نمی‌کنید چراکه آنرا با یک ورودی کاملاً جدید و بهبودیافته جایگزین می‌سازید که کامیت قدیمی را کنار می‌زند و در جای آن می‌نشیند. در نتیجه، انگار کامیت قبلی هرگز بوجود نیامده است و در تاریخچهٔ مخزن شما نمایش داده نمی‌شود.

فایده مشخص امند کردن کامیت‌هااین است که بدون ایجاد درهم ریختگی در تاریخچهٔ مخزن با پیغام کامیت‌های مثل «اوه، اضافه کردن یک فایل فراموش شده بود‍‍» یا «اصلاح یک غلط املایی در کامیت آخر»، یک تغییر خیلی جزئی برای آخرین کامیت می‌سازید.

آن‌استیج کردن یک فایل استیج‌شده

دو قسمت بعدی نشان می‌دهند که چگونه با استیج خود و تغییرات پوشه کاری کار کنید. قسمت قشنگ آن این است که دستوری که برای تعیین وضعیت آن دو بخش به کار می‌رود همچنین یاد‌آوری می‌کند که چگونه تغییرات به عقب برگردانید. برای مثال، فرض کنیم شما دو فایل را تغییر داده‌اید و می‌خواهید آن‌ها را جدا از هم کامیت کنید، اما به اتفاقاً دستور git add * را وارد می‌کنید و هر دوی آن‌ها را استیج می‌کنید. چطور می‌توانید یکی از آنها را آن‌استیج کنید؟ دستور git status به شما یادآوری می‌کند:

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

دقیقاً زیر متن «Changes to be comitted»، به شما می‌گوید از git reset HEAD <file> ... برای آن‌استیج استفاده کنید. پس بایید به توصیه گیت گوش کنیم و فایل CONTRIBURING.md را آن‌استیج کنیم:

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

دستور مقداری عجیب به نظر می‌رسد،‌ اما کار می‌کند. فایل CONTRIBUTING.md تغییر کرده است اما دوباره به حال آن‌استیج درآمده است.

یادداشت

درست است که دستور git reset می‌تواند خطرناک باشد، مخصوصاً اگر از فلگ --hard را به آن بدهید. با این حال، در این سناریو که بالا توضیح داده شد، فایلی که در پوشه کاری شما قرار دارد تغییر نیافته، پس نسبتاً ایمن است.

در حال حاضر این توضیحات جادویی تمام چیزی بود که لازم بود درباره دستور git reset بدانید. بعدتر در بخش Reset Demystified با جزئیات بیشتری وارد بحث reset می‌شویم که چه کاری می‌کند و چطور می‌توان در آن خبره شد تا کارهای جالب‌تری انجام داد.

بازگردانی تغییرات یک فایل تغییریافته

اگر ببینید که دیگر نمی‌خواهید تغییرات فایل COUNTRIBUTING.md را حفظ کنید چطور؟ چطور می‌شود تغییرات را به حالت قبل برگرداند — آن را به همان شکل که در آخرین کامیت شما (یا کلون اولیه، یا همانگونه که وارد پوشه کاری شما شده بود) بازگرداند؟ خوشبختانه، git status این را نیز به شما می‌گوید که چگونه آن را انجام دهید. در خروجی آخرین مثال، بخش آن‌استیج چیزی شبیه به این بود:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

این به صراحت تمام به شما می‌گوید که تغییرات انجام شده را چگونه از بین ببریم. بیایید کاری که می‌گوید را انجام دهیم:

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

شما می‌‌توانید ببینید که تغییرات به حالت اول بازگشتند.

مهم

مهم است که بدانید دستور git checkout -- <file> دستور خطرناکی است. هر تغییر محلی که به آن فایل اعمال شده بود از بین رفته است — گیت تغییرات فایل‌ها را با آخرین نسخه کامیت‌ شده جایگزین می‌کند. هرگز از این دستور استفاده نکنید مگر اینکه کاملاً می‌دانید که نمی‌خواهید آن تغییرات ذخیره نشده محلی از بین برود.

اگر مایل هستید تا تغییراتی که ایجاد کرده بودید را حفظ کنید اما باز هم لازم است که موقتاً آنها را از سر راهتان بردارید، در شاخه‌سازی در گیت به بررسی استش و شاخه‌سازی خواهیم پرداخت؛ به طور کل این‌ها راه‌های بهتری برای انجام این کار هستند.

یادتان باشد، هرچیزی که در گیت کامیت‌ شده باشد تقریباً همیشه می‌تواند بازگردانی شود. حتی کامیت‌هایی که بر روی شاخه‌هایی که حذف شده‌اند وجود داشتند یا کامیت‌هایی که با فلگ --amend بازنویسی شده‌ بودند می‌توانند بازگردانی شوند (بخش Data Recovery را برای بازیابی داده ببینید). با این حال، هر چیزی را که از دست می‌دهید که هرگز کامیت نشده، قریب به یقین دیگر نخواهید دید.