پرش به مطلب اصلی

اصلاح خطاها و نجات (Error Correction)

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

۱. اصلاح آخرین کامیت (--amend)

سناریو: کامیت کردید ولی یادتان رفت یک فایل را اضافه کنید، یا پیام کامیت غلط املایی دارد.

به جای اینکه یک کامیت جدید با پیام "Fix typo" بزنید، می‌توانید کامیت قبلی را اصلاح کنید:

git add forgotten-file.js
git commit --amend

اگر فقط می‌خواهید پیام را عوض کنید:

git commit --amend -m "New correct message"
هشدار

دستور amend شناسه (Hash) کامیت را تغییر می‌دهد. پس هرگز روی کامیت‌هایی که Push کرده‌اید این کار را نکنید (مگر اینکه تنها خودتان روی آن برنچ کار می‌کنید).

۲. لغو تغییرات محلی (قبل از کامیت)

بازگردانی فایل تغییر یافته (restore)

اگر فایلی را تغییر دادید و پشیمان شدید و می‌خواهید به حالت آخرین کامیت برگردد:

git restore <file>

(در نسخه‌های قدیمی: git checkout -- <file>)

خارج کردن از Staging

اگر فایلی را git add کردید ولی نمی‌خواهید کامیت شود (می‌خواهید از حالت Staged به Unstaged برگردد):

git restore --staged <file>

(در نسخه‌های قدیمی: git reset HEAD <file>)

حذف فایل‌های جدید (clean)

برای حذف فایل‌های Untracked (فایل‌های جدیدی که هنوز add نشده‌اند و گیت آن‌ها را دنبال نمی‌کند):

git clean -n   # Dry Run! Run This First to See What Will Be Deleted
git clean -fd # -f: force, -d: include directories

۳. بازگشت به عقب (reset vs revert)

وقتی تغییری کامیت شده است، دو راه برای لغو آن دارید:

روش امن: git revert

این دستور یک کامیت جدید می‌سازد که تغییرات کامیت مورد نظر را خنثی (Undo) می‌کند.

  • تاریخچه دست‌نخورده می‌ماند.
  • برای برنچ‌های عمومی (Public) امن است.
git revert <commit-hash>
نکته جالب

اگر یک کامیت را revert کردید و پشیمان شدید، می‌توانید کامیتِ Revert شده را دوباره revert کنید تا تغییرات اصلی برگردد! (Revertِ Revert = بازگشت تغییرات اصلی).

روش مخرب: git reset

این دستور تاریخچه را به عقب برمی‌گرداند و کامیت‌ها را حذف می‌کند. سه حالت اصلی دارد:

حالتدستوروضعیت کامیت‌های ریست‌شدهوضعیت فایل‌ها
Softgit reset --soft HEAD~1حذف می‌شونددر Staging می‌مانند (آماده کامیت مجدد)
Mixedgit reset HEAD~1حذف می‌شونددر Working Directory می‌مانند (Unstaged)
Hardgit reset --hard HEAD~1حذف می‌شوندپاک می‌شوند (خطرناک!)
نکته

از --soft زمانی استفاده کنید که می‌خواهید چند کامیت آخر را یکی کنید یا پیام‌شان را عوض کنید. از --mixed (پیش‌فرض) زمانی استفاده کنید که می‌خواهید تغییرات را نگه دارید ولی کامیت را بیخیال شوید. از --hard زمانی استفاده کنید که می‌خواهید کلاً به عقب برگردید و همه چیز را دور بریزید.

۴. حذف فایل (git rm)

حذف کامل

برای حذف فایل از پروژه و گیت:

git rm <file>
اطلاع

حذف فقط از گیت (Keep Local)

گاهی اشتباهی فایل‌های تنظیمات (مثل .env) یا پوشه node_modules را کامیت کرده‌اید. می‌خواهید گیت دیگر آن‌ها را دنبال نکند، اما فایل از روی سیستم شما پاک نشود:

git rm --cached <file>

(بعد از این کار، فایل را به .gitignore اضافه کنید).

۵. جستجو در تاریخچه (git log)

دستور git log بسیار قدرتمندتر از نمایش ساده لیست کامیت‌هاست.

  • نمایش تغییرات هر کامیت:
git log -p
  • نمایش خلاصه (کدام فایل‌ها تغییر کردند):
git log --stat
  • جستجوی تغییرات کد (Pickaxe): اگر دنبال کامیتی می‌گردید که در آن تابع calculateTax اضافه یا حذف شده است:
git log -S "calculateTax"
  • فیلتر بر اساس نویسنده یا زمان:
git log --author="Ali" --since="2 weeks ago"

۶. ماشین زمان و نجات نهایی (reflog)

آیا اشتباهی git reset --hard زدید و کدهایتان پرید؟ آیا برنچی را حذف کردید که نباید می‌کردید؟ نترسید!

گیت یک دفترچه خاطرات مخفی به نام Reflog دارد که تمام جابجایی‌های HEAD را (حتی آن‌هایی که در تاریخچه اصلی نیستند) ذخیره می‌کند.

git reflog

خروجی چیزی شبیه این است:

ea1b2c3 HEAD@{0}: reset: moving to HEAD~1
9876543 HEAD@{1}: commit: added login feature
a1b2c3d HEAD@{2}: checkout: moving from main to feature

اگر بخواهید به وضعیت قبل از Reset (یعنی جایی که کامیت added login feature بودید) برگردید:

git reset --hard HEAD@{1}
# یا
git reset --hard 9876543
اطلاع

اطلاعات reflog فقط روی سیستم شما ذخیره می‌شود و معمولاً تا ۳۰ یا ۹۰ روز باقی می‌ماند.

۷. سناریوهای متداول (Common Scenarios)

سناریو ۱: روی برنچ اشتباه کامیت کردم!

فرض کنید روی برنچ main هستید و اشتباهی یک کامیت می‌زنید که باید در برنچ feature می‌بود.

راه حل:

  1. یک برنچ جدید از همین نقطه بسازید (تا کامیت شما حفظ شود):
git branch feature
  1. برنچ فعلی (main) را به عقب برگردانید:
git reset --hard HEAD~1
  1. به برنچ جدید بروید:
git switch feature

سناریو ۲: یک برنچ را اشتباهی حذف کردم!

دستور git branch -D را زدید و ناگهان یادتان آمد که آن برنچ را لازم داشتید.

راه حل:

  1. با git reflog آخرین جایی که آن برنچ بود را پیدا کنید (معمولاً پیامی مثل moving from feature to main می‌بینید).
  2. آن کامیت را پیدا کنید (مثلاً a1b2c3d).
  3. برنچ را دوباره بسازید:
git branch feature a1b2c3d