Git 2026

فصل ۸ · Undo در Git

Undo — restore، reset، revert و reflog

Undo در Git یک فرمان نیست — چهار کار مختلف است. قبل از اجرا باید بدانی فایل روی دیسک را برمی‌گردانی، پیش‌نویس را خالی می‌کنی، اشاره‌گر شاخه را حرکت می‌دهی، یا یک کامیت جدیدِ خنثی می‌سازی.

🎯 اهداف یادگیری

  • نقشهٔ Undo را از حفظ بکشی
  • restore را جایگزین checkout فایل کنی
  • سه حالت reset را از هم جدا کنی
  • با reflog کامیت «گمشده» را زنده کنی
نقشه Undo

شکل ۷ — قانون طلایی: تاریخچهٔ عمومی را فقط با revert لمس کن.

🧹 Working Tree و Index

بازگردانی فایل — مدرن
git restore src/auth.ts                 # Working ← Index
git restore --staged src/auth.ts        # Index ← HEAD
git restore --source=HEAD --staged --worktree src/auth.ts
# هر دو درخت فایل = HEAD  (معادل checkout -- file)
git restore --source=main~3 README.md   # نسخهٔ قدیمی را بیاور
🖥️ VS Code Git
  • Changes → آیکون ↩ Discard Changes = restore
  • Staged → - Unstage = restore --staged
  • منوی ... → Commit → Undo Last Commit = reset --soft
  • Timeline فایل را بعد از Discard هم گاهی نجات می‌دهد
  • Discard All خطرناک است
⌨️ Terminal

git restore file git restore --staged file git reset --soft HEAD~1 git reflog برای نجات

🧱 سه چهرهٔ reset

فرض: A--B--C (HEAD) و می‌خواهی به B برگردی.

فرمان HEAD Index Working استفاده
--soft B B محتوای C محتوای C کامیت را بشکن، تغییرات بماند staged
--mixed B (پیش‌فرض) B B محتوای C کامیت را بشکن، تغییرات unstaged
--hard B B B B همه‌چیز برود
مثال‌های امن
git reset --soft HEAD~1        # پیام/فایل‌ها را دوباره بچین
git reset HEAD~1               # همان، اما unstaged
# git reset --hard HEAD~1     # فقط اگر مطمئنی

در VS Code منوی ... در Source Control: Commit → Undo Last Commit معمولاً --soft.

هرگز reset --hard روی main مشترک

اگر push شده، تاریخچهٔ دیگران را تکه‌پاره می‌کنی. به‌جایش git revert.

↩️ revert — Undo عمومی

کامیت معکوس بساز
git revert HEAD                # آخرین را خنثی کن
git revert -m 1 <merge-sha>    # خنثی‌کردن merge (والد ۱ = شاخهٔ هدف)

Revert یک کامیت جدید می‌سازد که تغییرات را برعکس اعمال می‌کند. تاریخچه دروغ نمی‌گوید.

در GitHub: روی PR دگمهٔ Revert همین کار را تمیزتر انجام می‌دهد.

🛟 reflog — ماشین زمان اشاره‌گرها

هر حرکت HEAD در reflog ثبت می‌شود (معمولاً ۹۰ روز).

زنده کردن کامیت گمشده
git reflog
# e3a1... HEAD@{0}: reset: moving to HEAD~1
# 9f3a... HEAD@{1}: commit: feat(auth): ...

git switch -c rescue HEAD@{1}
# یا
git reset --hard 9f3a1c
چه چیزی را reflog نجات نمی‌دهد؟

فایلی که هرگز add/commit نشده و Discard شده. Git آن را ندیده. از Local History خود VS Code (Timeline) کمک بگیر.

در VS Code: Timeline گاهی نسخه‌های محلی ذخیره می‌کند حتی بدون Git — آخرین تور ایمنی برای Untracked.

سؤالات مصاحبه (با پاسخ)

Junior — تفاوت restore و reset؟ restore فایل‌محور است؛ reset اشاره‌گر شاخه را حرکت می‌دهد.

Mid — soft در برابر mixed؟ هر دو HEAD را حرکت می‌دهند؛ soft ایندکس را نگه می‌دارد.

Senior — revert یک merge چرا -m 1 می‌خواهد؟ چون merge دو والد دارد. باید بگویی «خط اصلی کدام است» تا diff معکوس معنا داشته باشد.

✅ چک‌لیست فهم

  • نقشهٔ Undo را بلدی
  • restore را به‌جای checkout فایل می‌زنی
  • --hard را برای کار عمومی ممنوع می‌دانی
  • یک‌بار با reflog نجات داده‌ای

فصل بعد: gitignore، attributes و LFS.

فصل ۸ از ۳۶ · مرجع جامع و حرفه‌ای Git و GitHub · ویرایش 1.0.0