کدنامهمرجع‌های مهندسی نرم‌افزار، به فارسی
گیت · فصل ۹Git · Chapter 9

برگرداندن: reset، revert، restore

Undoing safely: reset, revert, and restore

«برگرد عقب» در Git جملهٔ ناقصی است. می‌خواهی فایل روی دیسک برگردد؟ ناحیه‌ آماده‌سازی؟ شاخه؟ یا یک تغییر منتشرشده با یک commit تازه خنثی شود؟ این فصل قبل از هر دستور همین سؤال را روشن می‌کند.

Three mistakes get described with the same sentence: “go back.” One edit is not staged; a wrong file is already in the index; and a bad commit may already be in a teammate’s clone. Should one command solve all three? Before running anything, ask: what exactly do you want to change?

۱۵بخشsections
۹۰دقیقهminزمان مطالعهreading time
۱۸تمرین با پاسخsolved exercises
۵نمودارdiagrams

سه دردسر، سه جای متفاوتThree mistakes, three different places

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

Last week you sent a change to Bob, and the whole team now has it. Today you dislike a local edit. Yesterday you staged the wrong file. “Undo” means something different in each case. If you choose a command before locating the change, you may discard the very version you wanted to keep.

فصل ۰۳ سه ناحیه را معرفی کرد: HEAD آخرین commit شاخه، index نسخه‌ای که commit بعدی می‌سازد، و پوشه‌ کاری فایل‌های روی دیسک. فصل ۰۸ هم نشان داد شاخهٔ محلی و تاریخچهٔ مخزن راه دور دو جا هستند. پس سؤال تکراری این فصل همین است: دقیقاً چه چیزی را می‌خواهی عوض کنی؟

Chapter 03 introduced the three areas: HEAD, the tip commit of the current branch; the index, the snapshot the next commit will use; and the working tree, the files on disk. Chapter 08 showed that your local branch and the remote’s history are separate too. So keep asking: what exactly do you want to change?

جایی که اشتباه ماندهWhere the mistake livesسؤال دقیقThe precise questionابزار محتملLikely tool
فقط پوشه‌ کاریWorking tree onlyکدام نسخه باید روی دیسک باشد؟Which version should be on disk?git restore
ناحیه‌ آماده‌سازی یا جای شاخهIndex or branch positionچه چیزی باید ناحیه‌ آماده‌سازی بماند؟ آیا commit محلی را بازنویسی می‌کنم؟What should stay staged? Am I rewriting a local commit?git restore --staged یا git reset
commit به‌اشتراک‌گذاشته‌شدهA shared commitچطور اثرش را بدون جابه‌جایی تاریخچهٔ بقیه خنثی کنم؟How can I undo its effect without moving everyone else’s history?git revert
فرمان برگشت، نسخهٔ جادویی نمی‌سازدUndo does not create a magic copy

Git فقط محتوایی را می‌تواند از شیءهای ذخیره‌شده بازسازی کند. ویرایش تازه‌ای که هیچ‌وقت ناحیه‌ آماده‌سازی یا commit نشده، لزوماً نسخه‌ای در Git ندارد. قبل از هر دستورِ دورریختنی، اگر به نسخه شک داری آن را بیرون از مسیر هدف کپی کن یا ایمنی اشاره‌گر بساز؛ وجود reflog هم تضمین نمی‌کند محتوای ذخیره‌نشده برگردد.

Git can reconstruct only content represented by stored objects. A new edit that was never staged or committed may have no version in Git at all. Before a destructive command, copy uncertain work outside the target path or create a safety ref. The existence of a reflog does not guarantee recovery of content Git never stored.

restore: کپی مقصد را انتخاب کنrestore: choose which copy to change

در فصل ۰۳ دیدی git restore FILE نسخهٔ ناحیه‌ آماده‌سازی را روی فایل پوشه‌ کاری می‌گذارد و git restore --staged FILE مدخل ناحیه‌ آماده‌سازی را از HEAD برمی‌گرداند. حالا یک قدم جلوتر می‌رویم: می‌توانی commit دیگری را منبع بگیری، یا عمداً هر دو مقصد را تغییر بدهی.

Chapter 03 showed that git restore FILE copies the index version into the working-tree file, while git restore --staged FILE resets the index entry from HEAD. Now we go one step further: you can choose another commit as the source, or intentionally change both destinations.

Restore copies a chosen source into the index, working tree, or both sourceindex or commit index--staged working tree--worktree index + working treeboth flags choose sourceand destinationbefore restoring
نمودار ۱ — پیکان‌ها از منبع به یکی از سه مقصد می‌روند: ناحیه‌ آماده‌سازی، پوشه‌ کاری یا هر دو. گزینه‌ها مقصد را انتخاب می‌کنند؛ منبع پیش‌فرض هم بسته به اینکه ناحیه‌ آماده‌سازی را restore می‌کنی یا پوشه‌ کاری فرق دارد.
Diagram 1 — Arrows go from a source to one of three destinations: the index, working tree, or both. The options select the destination; the default source also differs depending on whether you restore the index or working tree.

فرض کن روی profile.txt دو اصلاح داری: نسخهٔ درست را ناحیه‌ آماده‌سازی کرده‌ای، بعد یک ویرایش بدتر روی دیسک مانده. قبل از restore، با git diff -- و git diff --staged ببین هر نسخه کجاست. حالا فقط ویرایش آماده‌نشده را کنار می‌گذاری:

Suppose profile.txt has two edits: you staged the good version, then left a worse edit on disk. Before restoring, inspect git diff -- and git diff --staged to locate each copy. Now discard only the unstaged edit:

disposable undo-lab/ · inspect, then restore disk from index
git status --short
git diff -- profile.txt
git diff --staged -- profile.txt
git restore -- profile.txt
git diff -- profile.txt
git diff --staged -- profile.txt

بعد از فرمان، diff عادی خالی است ولی diff مربوط به ناحیه‌ آماده‌سازی هنوز همان اصلاح ناحیه‌ آماده‌سازیشده را نشان می‌دهد. یعنی فقط پوشهٔ کاری از ناحیه‌ آماده‌سازی نسخه گرفت؛ هیچ commit یا شاخه‌ای حرکت نکرد. این همان رفتاری است که فصل ۰۳ دیدی، با تأکید بیشتر بر اینکه نسخهٔ کنارگذاشته‌شده را باید آگاهانه انتخاب کنی.

Afterward, the ordinary diff is empty, while the staged diff still shows the intended edit. Only the working tree copied from the index; no commit or branch moved. This is the behavior from Chapter 03, with extra emphasis on deliberately choosing which version to discard.

اگر تغییر اشتباهی ناحیه‌ آماده‌سازی شده، اما خود فایل روی دیسک را می‌خواهی نگه داری، مقصد را برعکس کن: git restore --staged -- profile.txt. ناحیه‌ آماده‌سازی از HEAD نسخه می‌گیرد و فایل روی دیسک دست‌نخورده می‌ماند. بعد می‌توانی تغییر را بررسی و درست ناحیه‌ آماده‌سازی کنی. اگر هر دو نسخه را دور می‌خواهی، این تصمیم دوم و جداست: اول ناحیه‌ آماده‌سازی را برگردان، بعد پوشه‌ کاری را هم restore کن.

If the wrong change is staged but you want to keep the disk file, reverse the destination: git restore --staged -- profile.txt. The index takes its version from HEAD, while the file stays untouched. Then inspect and stage the intended content. If you want to discard both copies, that is a separate decision: restore the index first, then restore the working tree too.

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

To take a file from an older commit, specify the source. This command copies only the disk file from the older commit; the index keeps its existing version, so a new diff may appear:

one path · explicit source, working tree destination
git log --oneline -- profile.txt
git restore --source=HEAD~1 --worktree -- profile.txt
git diff -- profile.txt
git diff --staged -- profile.txt

نام HEAD~1 باید واقعاً نسخهٔ آن مسیر را داشته باشد؛ اگر مسیر در منبع وجود نداشته باشد، restore می‌تواند فایل ردیابی‌شده را حذف کند تا با منبع جور شود. قبل از اجرا، git show HEAD~1:profile.txt را امتحان کن. اگر می‌خواهی ناحیه‌ آماده‌سازی و پوشه‌ کاری هر دو دقیقاً نسخهٔ commit را بگیرند، --staged --worktree را با منبع روشن بنویس. این کار محتوای هر دو ناحیه را جایگزین می‌کند؛ تغییرهای لازم را اول بیرون از آن فایل ذخیره کن.

The revision HEAD~1 must actually contain that path; if the path is absent from the source, restore can remove the tracked file to match it. Check with git show HEAD~1:profile.txt first. If both the index and working tree should match the commit, specify --staged --worktree and the source explicitly. That replaces both copies; save any needed edits elsewhere first.

reset: جابه‌جایی شاخه، نه پاک‌کن تاریخreset: move a branch, not an eraser

یک commit اشتباه ساخته‌ای، هنوز push نشده و می‌خواهی آن را دوباره مرتب کنی. در این شکل از reset خودِ اشاره‌گر شاخه به commit دیگری می‌رود. تفاوت --soft، --mixed و --hard این است که با ناحیه‌ آماده‌سازی و فایل‌های روی دیسک چه می‌کنند. سه آزمایش را با یک شروع یکسان ببین؛ هر بار از مخزن دورریختنی جدا استفاده کن.

You made a bad commit that has not been pushed and want to reshape it. In this form of reset, the branch pointer moves to another commit. The difference between --soft, --mixed, and --hard is what happens to the index and files on disk. We will compare all three from the same starting point; use a separate disposable repository for each run.

در هر سه آزمایش این وضعیت را بساز: commit A روی main، بعد فایل را عوض کن و commit B بساز. اکنون HEAD، ناحیه‌ آماده‌سازی و پوشه‌ کاری هر سه نسخهٔ B را دارند. فرمان هدف HEAD~1 است؛ یعنی والد B، همان A. قبل از هر reset، شاخهٔ safety/before-reset را بساز و با git show-ref --verify refs/heads/safety/before-reset وجودش را ثابت کن. آن شاخه مدرک نگهداری commit است، نه نسخهٔ جداگانه از ویرایش‌های unstaged.

For each run, start with commit A on main, edit a file, then create commit B. Now HEAD, the index, and working tree all contain B. The target HEAD~1 is B’s parent, A. Before resetting, create safety/before-reset and verify it with git show-ref --verify refs/heads/safety/before-reset. That branch preserves the commit, not a separate copy of unstaged edits.

شروع ثابت هر سه آزمایشThe same starting point for all three runs
  • HEAD → B و شاخهٔ main → B
  • HEAD → B and branch main → B
  • ناحیه‌ آماده‌سازی = محتوای B
  • index = content of B
  • پوشه‌ کاری = محتوای B
  • working tree = content of B

--soft: شاخه عقب، محتوا سر جایش--soft: move the branch, keep both copies

فرض کن فقط پیام commit بد است یا دو commit را می‌خواهی یکی کنی؛ محتوای آماده‌شده درست است. قبل از reset حدس بزن: بعد از رفتن main از B به A، ناحیه‌ آماده‌سازی و فایل روی دیسک کجا می‌مانند؟

Suppose only the commit message is wrong, or you want to combine two commits; the prepared content is correct. Predict first: after main moves from B to A, where will the index and disk file remain?

Soft reset moves HEAD and main from B to A while the index and working tree remain at B git reset --soft HEAD~1 HEAD / mainB → A indexstill B · staged working treestill B · unchanged commit B is now a staged difference from A
نمودار ۲ — فقط HEAD و main به A برمی‌گردند. محتوای B در ناحیه‌ آماده‌سازی و پوشه‌ کاری می‌ماند و حالا نسبت به A ناحیه‌ آماده‌سازی شده است؛ commit B هنوز یک شیء است و شاخهٔ ایمنی هم به آن اشاره دارد.
Diagram 2 — Only HEAD and main return to A. B remains in the index and working tree, now staged relative to A; commit B is still an object, and the safety branch still points to it.
disposable run · record before, reset, inspect after
git log --oneline --decorate -2
git status --short
git show-ref --verify refs/heads/safety/before-reset
git reset --soft HEAD~1
git log --oneline --decorate -2
git status --short
git diff --staged --stat

در خروجی بعدی، main روی A است، ایمنی روی B؛ status نشان می‌دهد تغییرها ناحیه‌ آماده‌سازی هستند و diff --staged محتوای B را نسبت به A نشان می‌دهد. بعد از بررسی، می‌توانی commit تازه‌ای بسازی؛ اگر فقط پیام را می‌خواستی اصلاح کنی، git commit -m "..." می‌سازد commit تازه با شناسه تازه. reset نکردن محتوا به معنی «هیچ چیز عوض نشد» نیست: شاخه اشاره‌گر و تاریخچهٔ قابل‌دسترسی از main عوض شده‌اند.

Afterward, main points to A while safety points to B. Status shows staged changes, and diff --staged shows B’s content relative to A. After reviewing, create a new commit; if you only meant to fix the message, git commit -m "..." creates a replacement commit with a new ID. Keeping the content does not mean nothing changed: the branch pointer and the history reachable from main moved.

--mixed: شاخه و ناحیه‌ آماده‌سازی عقب، فایل‌ها نه--mixed: reset the index, keep disk files

این حالت پیش‌فرض git reset TARGET است، حتی اگر گزینه‌ای ننویسی. شاخه به A می‌رود؛ ناحیه‌ آماده‌سازی هم با A جور می‌شود؛ پوشه‌ کاری B را نگه می‌دارد. نتیجه این است که ویرایش‌های B دوباره آماده‌نشده می‌شوند تا بتوانی بخش مناسب را ناحیه‌ آماده‌سازی کنی.

This is the default for git reset TARGET when you omit a mode. The branch moves to A, the index is reset to A, and the working tree keeps B. The edits from B become unstaged again so you can stage the parts you want.

Mixed reset moves HEAD and resets the index to A while the working tree keeps Bgit reset --mixed HEAD~1 HEAD / mainB → A indexB → A · clean working treestill B · unstaged disk differs from index; nothing staged
نمودار ۳ — main و ناحیه‌ آماده‌سازی به A می‌رسند، فایل روی دیسک B می‌ماند. git status باید تغییر آماده‌نشده را نشان بدهد. محتوای B هنوز در فایل‌هاست، اما نسخهٔ commitش را ایمنی اشاره‌گر نگه می‌دارد.
Diagram 3 — Main and the index point to A; the disk file stays at B. git status should show an unstaged edit. B’s content remains in the files, while the safety ref preserves the commit object.
same disposable setup · inspect the unstaged diff
git reset --mixed HEAD~1
git status --short
git diff --stat
git diff --staged

پیام Unstaged changes after reset یا حرف M در ستون پوشه‌ کاری نشانهٔ شکست نیست؛ دقیقاً می‌گوید نسخهٔ ناحیه‌ آماده‌سازی با فایل روی دیسک فرق دارد. این نسخه را قبل از ناحیه‌ آماده‌سازی دوباره مرور کن. اگر با گزینهٔ بی‌نام reset می‌کنی، همان رفتار mixed را انتظار داشته باش.

A message such as Unstaged changes after reset or an M in the working-tree column is not a failure; it tells you the index differs from the disk file. Review that version before staging it again. A reset with no mode uses this mixed behavior.

--hard: هر سه را به A برسان--hard: make all three match A

این‌بار commit B، ناحیه‌ آماده‌سازی و فایل روی دیسک هر سه غلط‌اند و مطمئنی هیچ‌کدام را لازم نداری. این اطمینان را با حدس جایگزین نکن: اول وضعیت و diffها را بخوان، شاخهٔ ایمنی را بساز و وجودش را تأیید کن. بعد، فقط در مخزن دورریختنی درس، فرمان hard را اجرا کن.

This time commit B, the index, and the disk file are all wrong, and you are certain you need none of them. Do not substitute a guess for that certainty: inspect status and diffs, create a safety branch, and verify it exists. Then run the hard reset only in the lesson’s disposable repository.

Hard reset moves HEAD and makes the index and tracked working files match Agit reset --hard HEAD~1 HEAD / mainB → A indexB → A working treeB → A tracked edits are overwritten · verify first
نمودار ۴ — HEAD و ناحیه‌ آماده‌سازی به A می‌رسند و فایل‌های ردیابی‌شده هم با A جایگزین می‌شوند. ویرایش‌های ردیابی‌شدهٔ B از پوشه‌ کاری پاک می‌شوند. فایل ردیابی‌نشده هم «نسخهٔ پنهان» نیست؛ reset ممکن است فایل ردیابی‌نشده مزاحم را بازنویسی یا حذف کند.
Diagram 4 — HEAD and the index move to A, and tracked files are replaced with A. Tracked edits from B disappear from the working tree. An untracked file is not a hidden backup; reset may overwrite or remove an untracked file that obstructs the target.
stop if any part of this is not disposable
git status --short
git diff
git diff --staged
git show-ref --verify refs/heads/safety/before-reset
git reset --hard HEAD~1
git status --short
git log --oneline --decorate -2

اگر ایمنی اشاره‌گر را نساخته‌ای یا خروجی نشان نمی‌دهد به B اشاره می‌کند، فرمان hard را اجرا نکن. بعد از reset باید پوشه‌ کاری تمیز و main روی A باشد؛ ایمنی شاخه هنوز B را نگه می‌دارد. این آزمایش ثابت نمی‌کند ویرایش تازه‌ای که هرگز ناحیه‌ آماده‌سازی یا commit نشده، recoverable است. به reflog هم وعدهٔ نجات قطعی نده؛ فصل ۱۰ ابزارهای بررسی اشاره‌گرهای قبلی را توضیح می‌دهد، نه جادوی بازگرداندن محتوای هرگز ذخیره‌نشده.

If you have not created the safety ref, or the output does not show it pointing to B, do not run the hard reset. Afterward, the working tree should be clean and main should point to A; the safety branch still retains B. This does not prove that an edit never staged or committed is recoverable. Do not promise that the reflog will save everything either. Chapter 10 explains how to inspect earlier ref positions, not how to conjure content Git never stored.

سه reset را کنار هم ببینCompare the three reset modes

این جدول را مثل نقشهٔ مقصد بخوان، نه مثل فهرست حفظی. در هر سه، با شکل commitها main از B به A می‌رود؛ ستون آخر می‌گوید نسخهٔ فایل‌ها بعد از فرمان کجاست.

Read this as a map of destinations, not a list to memorise. In all three cases, main moves from B to A in the commit graph; the last columns show where the file versions end up.

فرمانCommandHEAD / شاخهHEAD / branchindexworking treeبعدش چه می‌بینی؟What you see afterward
reset --soft AB ← AB ← Aهمان Bstays Bهمان Bstays Bتغییرها آماده‌شده می‌شوند.Changes are staged.
reset --mixed AB ← AB ← AB ← AB ← Aهمان Bstays Bتغییرها آماده‌نشده می‌شوند؛ حالت پیش‌فرض است.Changes become unstaged; this is the default.
reset --hard AB ← AB ← AB ← AB ← AB ← AB ← Aویرایش‌های ردیابی‌شده کنار گذاشته می‌شوند؛ خطر را جدی بگیر.Tracked edits are discarded; treat this as destructive.

یک مرز مهم: git reset -- FILE شکل path-based است؛ معمولاً ناحیه‌ آماده‌سازی را از HEAD برمی‌گرداند و شاخه اشاره‌گر را جابه‌جا نمی‌کند. برای تازه‌کارها git restore --staged -- FILE همان نیت را واضح‌تر می‌گوید. وقتی reset مقصد commit دارد، داری دربارهٔ موقعیت شاخه حرف می‌زنی؛ وقتی مسیر می‌دهی، دربارهٔ مدخل‌های index.

One important boundary: git reset -- FILE is the path form. It updates the index from HEAD and does not move the branch pointer. For beginners, git restore --staged -- FILE states that intention more clearly. A commit target means you are moving a branch position; a path target means you are changing index entries.

commit بد منتشر شده؟ اثرش را با commit تازه خنثی کنWas the bad commit shared? Reverse its effect with a new commit

فصل ۰۸ commitها را از یک clone به clone دیگر رساند. اگر commit بد را همکاران گرفته‌اند، reset کردن main فقط شاخهٔ تو را عقب می‌برد؛ تاریخچهٔ همکارها را پاک نمی‌کند و ممکن است push را به بازنویسی اجباری بکشاند. git revert راه دیگری دارد: patch معکوس را روی وضعیت فعلی اعمال می‌کند و نتیجه را در commit تازه ثبت می‌کند.

Chapter 08 moved commits between clones. If teammates already have the bad commit, resetting your main only moves your branch back; it does not erase their history and may tempt you into a force push. git revert takes another route: it applies an inverse patch to the current state and records the result in a new commit.

Revert preserves the original commit and adds a new commit that inverses its changes Aknown good Bbad commit Crevert B A → B → C · all three commits remain in history
نمودار ۵ — revert commit B را حذف نمی‌کند و شاخه را به عقب نمی‌برد؛ commit C تغییرهای B را تا جایی که روی وضعیت فعلی اعمال‌پذیر است معکوس می‌کند. نتیجه تاریخچه‌ای تازه و قابل push عادی است.
Diagram 5 — Revert does not delete B or move the branch backward. Commit C reverses B’s changes where they apply to the current state. The result is new history that can be pushed normally.

در مخزن اشتراکی این کار را در شاخهٔ درست و با پوشه‌ کاری تمیز انجام بده. اول commit هدف را با log و show پیدا کن؛ بعد revert را بساز و diff و تست را بررسی کن:

In a shared repository, work on the correct branch with a clean working tree. Find the target commit with log and show, then create the revert and inspect its diff and tests:

shared-branch example · inspect target before reversing it
git status --short
git log --oneline --decorate -5
git show --stat --oneline BAD_COMMIT
git revert BAD_COMMIT
git show --stat --oneline HEAD
git log --oneline --decorate -3

شناسهٔ BAD_COMMIT را با کلید واقعی عوض کن؛ این یک جای‌نگهدار است، نه فرمان آماده. بعد از موفقیت، log باید هم commit بد را نشان دهد و هم commit جدیدی با پیام شبیه Revert "...". محتوای فایل در عکس فوری تازه اصلاح شده؛ تاریخچهٔ قدیمی دست‌نخورده مانده. این روش اثر patch را معکوس می‌کند، نه اینکه حتماً برنامه را درست کند: اگر commitهای بعدی بر همان تغییر تکیه دارند، اثر جانبی و تست را هم بررسی کن.

Replace BAD_COMMIT with the real object ID; it is a placeholder, not a runnable command. On success, the log shows both the bad commit and a new commit with a message like Revert "...". The new snapshot contains the reversed content; old history remains. Revert reverses a patch, not necessarily the application’s behavior: if later commits depend on it, inspect side effects and tests too.

گاهی patch معکوس روی کد تازه با تغییرهای بعدی تداخل دارد. Git متوقف می‌شود و تعارض می‌سازد؛ اول git status را بخوان، فایل را طوری ویرایش کن که قصد نهایی روشن باشد، بعد git add و git revert --continue. اگر هنوز نمی‌دانی نتیجه باید چه باشد، حدس نزن: git revert --abort عملیات نیمه‌تمام را لغو می‌کند. هیچ‌کدام را با reset hard روی کار حل‌نشده قاطی نکن.

Sometimes the inverse patch conflicts with later edits. Git stops with a conflict; inspect status, edit the file to express the intended result, then stage it and run git revert --continue. If you do not yet know the right result, do not guess: git revert --abort cancels the in-progress operation. Do not mix either path with a hard reset over unresolved work.

revert یعنی «اثر را برگردان»، نه «commit را پاک کن»Revert means “reverse the effect,” not “delete the commit”

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

Anyone who has B still sees it in history; C does not erase that historical reference. Teammates can usually fetch the new change without being forced to move their local history backward.

مرز پیشرفته: revert کردن merge commitAdvanced boundary: reverting a merge commit

برای merge commit باید با git revert -m PARENT MERGE_COMMIT مشخص کنی کدام والد mainline است؛ شماره‌گذاری از ۱ شروع می‌شود. این انتخاب می‌گوید اثر merge را نسبت به کدام والد معکوس کن. چنین revertی روی mergeهای آینده اثر می‌گذارد: Git commitهای قبلیِ واردشده از آن merge را دوباره به‌عنوان تغییر تازه نمی‌آورد. قبل از اجرا والدها را با git show --no-patch --pretty=raw MERGE_COMMIT بخوان و با تیم هماهنگ کن. این دستور حدسی برای «پاک‌کردن merge» نیست.

A merge commit requires git revert -m PARENT MERGE_COMMIT to identify the mainline parent; numbering starts at 1. This chooses which parent’s perspective to reverse against. Such a revert affects future merges: Git will not reintroduce the old merged commits as new changes. Inspect the parents with git show --no-patch --pretty=raw MERGE_COMMIT and coordinate with the team first. This is not a guessable “delete the merge” command.

یک commit محلی را اصلاح کن؛ فقط اگر هنوز مشترک نشدهAmend a local commit—only before it is shared

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

You made the latest commit and notice a small file is missing, or the message is wrong. Before publication, git commit --amend can create a replacement version of the tip commit. This is not an invisible edit: the replacement gets a new ID because its content or message changed.

private disposable branch · prove the ID changed
git log -1 --oneline
git status --short
git add forgotten.txt
git commit --amend --no-edit
git log -1 --oneline
git show --stat --oneline HEAD

در این نمونه فایل ناحیه‌ آماده‌سازیشده وارد tree commit جایگزین می‌شود؛ --no-edit پیام قبلی را نگه می‌دارد. شناسه پیش و بعد از amend را مقایسه کن. اگر commit قبلاً push یا به همکار داده شده، amend تاریخچهٔ مشترک را بازنویسی می‌کند؛ پیش‌فرض امن این نیست که force بزنی. هماهنگ کن یا برای اصلاحی که باید در تاریخچهٔ مشترک بماند یک commit تازه بساز.

Here, the staged file enters the replacement commit’s tree; --no-edit keeps the existing message. Compare the IDs before and after. If the commit was pushed or handed to a teammate, amend rewrites shared history; blindly forcing it is not the safe default. Coordinate, or add a new commit when the correction should remain visible in shared history.

درخت تصمیم: قبل از فرمان، مقصد را پیدا کنA decision tree: locate the destination before choosing a command

وقتی همه می‌گویند «برگردانش»، این ترتیب را دنبال کن. اول ببین تغییر commit شده یا نه؛ بعد مشخص کن فقط ناحیه‌ آماده‌سازی اشتباه است یا فایل دیسک هم باید عوض شود؛ اگر commit شده، بپرس آیا کس دیگری آن را دریافت کرده؟

When everyone says “undo it,” follow this order. First determine whether the change is committed. Then decide whether only the staging is wrong or the disk file should change too. If it is committed, ask whether anyone else has received it.

وضعیتSituationچه چیزی را نگه می‌داری؟What do you want to keep?قدم محتاطانهCareful next step
ویرایش فقط روی دیسک استEdit is only on diskمی‌خواهی دورش بیندازیYou want to discard itdiff را بخوان؛ git restore -- FILE از ناحیه‌ آماده‌سازی می‌آورد.Inspect the diff; git restore -- FILE copies from the index.
تغییر اشتباهی ناحیه‌ آماده‌سازی شدهWrong change is stagedفایل روی دیسک را نگه دارKeep the disk filegit restore --staged -- FILE؛ بعد ناحیه‌ آماده‌سازی و diff را بررسی کن.git restore --staged -- FILE; then inspect the index and diff again.
commit خصوصی و تازه استCommit is local and recentمحتوا را نگه دار، commit را جابه‌جا کنKeep content, move the commit boundaryایمنی اشاره‌گر بساز؛ بعد soft یا mixed را بر اساس وضعیت مطلوب انتخاب کن.Create a safety ref; choose soft or mixed based on the desired state.
مطمئنی هیچ نسخه‌ای لازم نیستYou are certain no version is neededهمه‌چیز را به commit هدف برگردانMake everything match the target commitفقط در مخزن دورریختنی یا بعد از نسخه‌ پشتیبان و بررسی، reset --hard.Use reset --hard only in a disposable repo or after backup and inspection.
commit را همکاران گرفته‌اندTeammates already have the commitاثر بد را خنثی کن؛ تاریخچهٔ مشترک را نگه دارReverse the effect; preserve shared historycommit را بررسی کن و git revert بساز؛ سپس تست و push عادی.Inspect the commit, create a git revert, test, then push normally.

اگر پاسخ سؤال «چه چیزی را می‌خواهم نگه دارم؟» روشن نیست، فرمان برگشت را عقب بینداز. اول git status --short، git diff و git diff --staged را بخوان. اگر قرار است commit یا شاخه‌ای را جابه‌جا کنی، در محیط آزمایشی یک اشاره‌گر مثل safety/before-undo بساز و نشان بده به کدام commit اشاره می‌کند. در تاریخچهٔ مشترک، هماهنگی بخشی از راه‌حل فنی است.

If you cannot yet answer “what do I want to keep?”, postpone the undo command. First inspect status and both diffs. Before moving a commit or branch, create a ref such as safety/before-undo in a test environment and verify which commit it names. In shared history, coordination is part of the technical solution.

وقتی «برگرداندن» خودش دردسر می‌سازدWhen undo creates another problem

بیشتر فاجعه‌های «undo» از خود reset یا restore شروع نمی‌شوند؛ از این شروع می‌شوند که هنوز نمی‌دانیم چه چیزی باید بماند. قبل از هر دستور مخرب، یک بار واضح بگو: «می‌خواهم شاخه جابه‌جا شود؟ ناحیهٔ آماده‌سازی؟ فایل روی دیسک؟ یا فقط اثر یک commit مشترک خنثی شود؟»

Undo failures rarely begin with an obscure command; they begin with an unchecked destination. Read the message, record the three-area state, and only then repair.

قبل از نسخه‌ پشتیبان، reset --hard زدی

You ran reset --hard before saving work

اول توقف کن؛ دستور دیگری نزن که فایل‌ها را بیشتر تغییر دهد. git status، git reflog و فایل‌های باقی‌مانده را بررسی کن، اما reflog فقط اشاره‌گرها را ثبت می‌کند و ویرایش تازهٔ ذخیره‌نشده را تضمین نمی‌کند. اگر نسخهٔ B در ایمنی شاخه است، از همان commit محتوا را استخراج کن. اگر هیچ‌وقت ذخیره نشده و کپی دیگری نیست، ممکن است از دست رفته باشد.

Stop before running commands that change more files. Inspect status, reflog, and remaining files, but remember that reflog records ref movements; it does not guarantee an unsaved edit. If B is on a safety branch, recover content from that commit. If it was never stored and no other copy exists, it may be gone.

روی شاخه اشتباه بودی

You were on the wrong branch

پیش از هر جابه‌جایی، git branch --show-current و git log --oneline --decorate -3 را بخوان. اگر reset انجام شده، شاخهٔ ایمنی و اشاره‌گرهای مرتبط را بررسی کن؛ روی شاخه دیگر reset دوم نزن تا «به نظر درست» شود. مسیر بازیابی را اول در clone دورریختنی امتحان کن.

Before moving anything, inspect the current branch and recent decorated log. If reset already happened, check the safety branch and related refs; do not issue another reset on a different branch just to make the graph look right. Test a recovery path in a disposable clone first.

revert به تعارض خورد

Revert conflicted

این یعنی patch معکوس روی tree فعلی بی‌ابهام اعمال نمی‌شود، نه اینکه commit خراب شده. git status و بخش تعارض را بخوان؛ نتیجهٔ نهایی را دستی بساز، git add کن و git revert --continue بزن. اگر تصمیم ندارید یا هدف اشتباه بوده، git revert --abort کن و با تیم روشنش کن.

The inverse patch does not apply cleanly to the current tree; it does not mean the commit is corrupt. Inspect status and the conflicts, edit the intended result, stage it, then continue. If the goal is unclear or the target was wrong, abort and clarify with the team.

commit مشترک را amend کردی

You amended a shared commit

commit تازه شناسه متفاوت دارد و cloneهای دیگر هنوز نسخهٔ قبلی را دارند. قبل از push، گراف و شاخهٔ مخزن راه دور را fetch و بررسی کن؛ اگر دیگران commit قدیمی را گرفته‌اند، هماهنگ شو و معمولاً یک commit اصلاحی تازه بساز. --force خودبه‌خود commitهای دیگران را ادغام نمی‌کند.

The replacement has a different ID, while other clones still have the old one. Before pushing, fetch and inspect the graph and remote branch. If others have the old commit, coordinate and usually add a corrective commit instead. Force does not integrate teammates’ commits.

فکر کردی revert، commit قدیمی را پاک می‌کند

You expected revert to delete the old commit

با git log --oneline هر دو commit را ببین: قبلی با اثر اصلی و تازه با اثر معکوس. این تاریخچهٔ افزایشی همان چیزی است که در مخزن راه دور به هم‌تیمی می‌رسد.

Use git log --oneline to see both commits: the old one with its original change and the new one reversing it. This additive history is what teammates receive from the remote.

از منبع اشتباه restore گرفتی

You restored from the wrong source

فرمان بعدی را حدس نزن. git diff و git diff --staged را بخوان و ببین کدام ناحیه تغییر کرده. اگر منبع commit بوده، git show REV:FILE نسخه‌های ذخیره‌شده را نشان می‌دهد؛ اگر نسخهٔ اشتباه هیچ‌وقت در Git ذخیره نشده، این فرمان آن را نمی‌سازد.

Do not guess the next command. Inspect both diffs to see which area changed. If the source was a commit, git show REV:FILE shows stored versions; if the wrong version was never stored in Git, this command cannot create it.

تمرین‌ها: اول پیدا کن چه چیزی باید بماندExercises: first decide what must remain

این تمرین‌ها عمداً شبیه هم به نظر می‌رسند، چون در کار واقعی هم همه با جملهٔ «می‌خوام برگردم عقب» شروع می‌شوند. تفاوت را از محل تغییر پیدا کن؛ بعد ابزار را انتخاب کن. اگر محل را اشتباه تشخیص بدهی، دستور درست هم می‌تواند نتیجهٔ بد بدهد.

Start each answer by naming the destination: working tree, index, branch, or shared history. Sometimes the safe answer is “no command yet—create a safety ref.”

۱۸ تمرین حل‌شده · از تشخیص نسخه تا رخداد تیمی18 solved exercises · from version selection to team incidents
۰۱ویرایش روی دیسک / Disk-only edit

فایل ردیابی‌شده را تغییر داده‌ای ولی git add نزده‌ای. فقط می‌خواهی فایل به نسخهٔ ناحیه‌ آماده‌سازی برگردد. مقصد و منبع git restore FILE چیست؟

You edited a tracked file but have not staged it. You want it back at the index version. What are the destination and source of git restore FILE?

راهنماییHint

این شکل restore به --staged نیاز ندارد.

This form of restore does not use --staged.

پاسخ و دلیلExplanation

مقصد پوشه‌ کاری و منبع ناحیه‌ آماده‌سازی است. git restore -- FILE ویرایش آماده‌نشده را با نسخهٔ ناحیه‌ آماده‌سازیشده جایگزین می‌کند؛ اگر آن ویرایش را نگه می‌داری، اول آن را جای دیگری ذخیره کن.

The destination is the working tree and the source is the index. git restore -- FILE replaces the unstaged edit with the staged version. Save the edit elsewhere first if you may need it.

۰۲فایل stageشده / A staged file

تغییر روی دیسک درست است اما اشتباهی ناحیه‌ آماده‌سازی شده. می‌خواهی از ناحیه‌ آماده‌سازی بیرون برود و روی دیسک بماند. چه می‌زنی؟

The disk edit is good, but it was staged by mistake. You want it out of the index and still on disk. What do you run?

راهنماییHint

فقط ناحیه‌ آماده‌سازی مقصد restore است.

Only the index is the restore destination.

بیا بازش کنیمAnswer

git restore --staged -- FILE. این ناحیه‌ آماده‌سازی را از HEAD می‌گیرد و پوشه‌ کاری را تغییر نمی‌دهد. بعد git status --short باید تغییر آماده‌نشده را نشان دهد.

git restore --staged -- FILE. It takes the index version from HEAD and leaves the working tree untouched. Then status should show the edit as unstaged.

۰۳نسخهٔ قدیمی / An older source

می‌خواهی فقط settings.ini را از دو commit قبل روی دیسک ببینی؛ ناحیه‌ آماده‌سازی باید همان قبلی بماند. فرمان را کامل کن.

You want only settings.ini on disk to match two commits ago; the index must stay as it is. Complete the command.

راهنماییHint

منبع و destination دو انتخاب جدا هستند.

Source and destination are separate choices.

راه‌حل و توضیحCommand and caution

git show HEAD~2:settings.ini را اول برای تأیید منبع ببین، بعد git restore --source=HEAD~2 --worktree -- settings.ini. ناحیه‌ آماده‌سازی دست‌نخورده می‌ماند و ممکن است اکنون فایل با ناحیه‌ آماده‌سازی اختلاف داشته باشد.

First inspect the source with git show HEAD~2:settings.ini, then run git restore --source=HEAD~2 --worktree -- settings.ini. The index stays unchanged, so the file may now differ from it.

۰۴سه نسخه / Three copies

پیش از فرمان، HEAD برابر A، ناحیه‌ آماده‌سازی برابر B و پوشه‌ کاری برابر C است. git restore --staged -- file چه چیزهایی را تغییر می‌دهد؟

Before the command, HEAD is A, the index is B, and the working tree is C. What changes after git restore --staged -- file?

راهنماییHint

منبع پیش‌فرض با --staged فرق می‌کند.

The default source changes when --staged is present.

چرا این جواب درست استInterpretation

ناحیه‌ آماده‌سازی از A، یعنی HEAD، می‌شود؛ پوشه‌ کاری همچنان C می‌ماند. پس اکنون هم فایل روی دیسک و هم ناحیه‌ آماده‌سازی ممکن است از HEAD متفاوت باشند، اما شاخه حرکت نکرده.

The index becomes A, from HEAD; the working tree stays C. Both may now differ from HEAD, but the branch did not move.

۰۵soft پیش‌بینی / Predict soft

main روی B است. ناحیه‌ آماده‌سازی و پوشه‌ کاری هم B هستند. بعد git reset --soft HEAD~1 می‌زنی. سه ناحیه کجا می‌روند؟

Main points to B; the index and working tree also contain B. You run git reset --soft HEAD~1. Where do the three areas end up?

راهنماییHint

soft فقط یکی از سه جایگاه را جابه‌جا می‌کند.

Soft moves only one of the three positions.

بررسی جوابAnswer

HEAD و main به والد B یعنی A می‌روند؛ ناحیه‌ آماده‌سازی و پوشه‌ کاری روی B می‌مانند. تفاوت B با A در ناحیه‌ آماده‌سازی آماده‌شده دیده می‌شود. وضعیتها را قبل و بعد بنویس تا نتیجه روشن شود.

HEAD and main move to B’s parent A; the index and working tree remain at B. The difference between B and A appears staged. Write down the states before and after to make the result clear.

۰۶mixed پیش‌بینی / Predict mixed

همان شروع B را داری، اما این بار reset بدون گزینه اجرا می‌شود. ناحیه‌ آماده‌سازی و پوشه‌ کاری چه می‌شوند؟

You have the same starting point at B, but run reset without a mode. What happens to the index and working tree?

راهنماییHint

حالت پیش‌فرض reset را به یاد بیاور.

Recall reset’s default mode.

پاسخ پیشنهادیExplanation

بی‌گزینه یعنی --mixed: شاخه و ناحیه‌ آماده‌سازی به A می‌روند، فایل‌ها B می‌مانند. بنابراین B در پوشه‌ کاری آماده‌نشده است. این رفتار نشان می‌دهد «reset معمولی» به معنی پاک‌کردن همه‌چیز نیست.

No mode means --mixed: the branch and index move to A while the disk files remain B. The B edit is unstaged. This shows that a “normal reset” does not erase everything.

تا اینجا هر اشتباه را در یک جای مشخص دیدی. از اینجا تمرین‌ها عمداً مرزها را قاطی می‌کنند: ممکن است هم چیزی آماده‌شده باشد، هم commit محلی داشته باشی. قبل از انتخاب دستور، بگو کدام لایه باید تغییر کند و کدام باید سالم بماند.

So far each mistake lived in one clear place. From here the exercises deliberately mix the layers: you may have staged work and local commits together. Before choosing a command, state which layer must change and which must remain intact.

۰۷hard و untracked / Hard reset and untracked files

پس از reset --hard A، فایل ردیابی‌شده با نسخهٔ A جایگزین شده. یک فایل ردیابی‌نشده دیگر که در A نیست، قطعاً پاک شده؟

After reset --hard A, a tracked file matches A. Is a separate untracked file absent from A definitely deleted?

راهنماییHint

بین فایل ردیابی‌نشده معمولی و فایلی که جلوی نوشتن مسیر ردیابی‌شده را می‌گیرد فرق بگذار.

Distinguish an unrelated untracked file from one obstructing a tracked path.

پاسخ و دلیلPrecise answer

نه، «قطعاً» نه. hard همهٔ فایل‌های ردیابی‌شده را با target جور می‌کند و ممکن است ردیابی‌نشدههایی را که سر راه مسیرهای ردیابی‌شده هستند overwrite یا حذف کند؛ ردیابی‌نشده نامرتبط معمولاً می‌ماند. روی هیچ‌کدام شرط نبند: قبل از فرمان فایل ناشناخته را بررسی و از آن نسخه بگیر.

No—not definitely. Hard reset makes tracked files match the target and may overwrite or remove untracked files that obstruct tracked paths; unrelated untracked files usually remain. Do not gamble on either behavior: inspect and save unknown files before the command.

۰۸تفاوت دو reset / Two reset forms

آیا git reset HEAD -- report.txt شاخه را عقب می‌برد؟ تفاوتش با git reset --mixed HEAD~1 چیست؟

Does git reset HEAD -- report.txt move the branch backward? How does it differ from git reset --mixed HEAD~1?

راهنماییHint

دیدن مسیر بعد از -- شکل فرمان را عوض می‌کند.

A path after -- selects a different form.

بیا بازش کنیمComparison

فرم path-based فقط مدخل ناحیه‌ آماده‌سازی فایل را از HEAD برمی‌گرداند؛ شاخه جابه‌جا نمی‌شود. فرم دوم target commit دارد و main را عقب می‌برد و ناحیه‌ آماده‌سازی را هم به آن می‌رساند. برای unstage فایل، git restore --staged -- report.txt نیت را واضح‌تر می‌گوید.

The path form resets only that file’s index entry from HEAD; the branch does not move. The second form has a commit target, moves main backward, and resets the index to it. For unstaging, git restore --staged -- report.txt states the intent more clearly.

۰۹commit خصوصی / Private commit

یک commit خصوصی را اشتباهی ساخته‌ای. محتوای آن درست است و می‌خواهی همهٔ تغییرها ناحیه‌ آماده‌سازی بمانند تا دوباره commit کنی. قدم امن قبل از reset و گزینهٔ مناسب چیست؟

You made a mistaken local commit. Its content is correct, and you want all changes staged for a new commit. What safe step comes before reset, and which mode fits?

راهنماییHint

کدام مجوز ناحیه‌ آماده‌سازی را حفظ می‌کند؟

Which mode preserves the index?

راه‌حل و توضیحAnswer with evidence

اول پوشه‌ کاری و ناحیه‌ آماده‌سازی را بازبینی کن، بعد در محیط آزمایشی git branch safety/before-reset بساز و با git show-ref --verify refs/heads/safety/before-reset ثابت کن به commit فعلی می‌رسد. سپس git reset --soft HEAD~1. وضعیت باید commit را از main بردارد ولی تغییرها را آماده‌شده نگه دارد.

Inspect the working tree and index, then create git branch safety/before-reset in a test environment and verify it points to the current commit. Run git reset --soft HEAD~1. The commit leaves main while its changes remain staged.

۱۰مطمئن نیستی / Not sure yet

نمی‌دانی در فایل تنظیمات چه چیزهایی ناحیه‌ آماده‌سازی شده و آیا commit قبلی اشتراکی بوده. همکارت می‌گوید «یک hard reset بزن». پاسخ امن چیست؟

You do not know what is staged in the config file or whether the previous commit was shared. A teammate says “just hard reset.” What is the safe response?

راهنماییHint

گاهی بهترین فرمان فعلاً هیچ‌کدام است.

Sometimes the best command is none yet.

چرا این جواب درست استDecision

فعلاً reset نزن. git status --short، git diff، git diff --staged و git log --oneline --decorate -5 را ثبت کن؛ از هم‌تیمی بپرس commit را گرفته یا نه. اگر شاخه قرار است جابه‌جا شود، ایمنی اشاره‌گر بساز و تأیید کن. تا مقصد و نسخهٔ محفوظ روشن نشده، hard مناسب نیست.

Do not reset yet. Record status, both diffs, and the recent decorated log; ask whether the teammate has the commit. Create and verify a safety ref before moving the branch. Until the target and preserved version are clear, hard reset is not appropriate.

۱۱اصلاح پیام / Fix a message

پیام commit آخر غلط تایپی دارد، tree درست است و هنوز push نشده. بعد از amend چه چیزی تغییر می‌کند؟

The latest commit message has a typo, its tree is correct, and it has not been pushed. What changes after amend?

راهنماییHint

پیام بخشی از محتوای commit است.

The message is part of the commit object.

بررسی جوابExplanation

با git commit --amend -m "پیام درست" commit جایگزین با شناسه تازه ساخته می‌شود و شاخه به آن اشاره می‌کند. tree می‌تواند همان باشد ولی commit شیء عوض شده. چون خصوصی است، جایگزینی معمولاً دردسر مخزن راه دور ندارد؛ قبل از amend هر تغییر ناحیه‌ آماده‌سازیشدهٔ ناخواسته را هم بررسی کن.

git commit --amend -m "correct message" creates a replacement commit with a new ID and moves the branch to it. The tree can stay the same while the commit object changes. Since it is private, replacement usually avoids remote trouble; inspect staged changes first so you do not include anything unintended.

۱۲commit بدِ مشترک / A shared bad commit

commit بد روی main منتشر شده و باب هم آن را fetch کرده. تیم می‌خواهد نتیجهٔ آن برگردد ولی تاریخچهٔ دو clone واگرا نشود. چه روشی و چه مدرکی می‌خواهی؟

A bad commit is on shared main, and Bob has fetched it. The team wants its effect reversed without making the clones diverge. Which method and evidence do you need?

راهنماییHint

شاخه را عقب نبر؛ یک تغییر تازه بساز.

Do not move the branch backward; add a new change.

پاسخ پیشنهادیMethod

با git show BAD هدف را بررسی و git revert BAD را اجرا کن. git log باید commit اصلی و commit معکوس را هر دو نشان دهد؛ diff نهایی و تست هم باید اثر مورد انتظار را ثابت کنند. بعد push عادی و fetch باب، نه push اجباری.

Inspect the target with git show BAD and run git revert BAD. The log should retain both the original and inverse commits; the final diff and tests should prove the intended result. Then use a normal push and Bob fetches—no force push.

تمرین‌های آخر پای تاریخچهٔ مشترک را وسط می‌کشند. اینجا «می‌توانم؟» کافی نیست؛ باید بپرسی «اگر این تاریخ را بازنویسی کنم چه کسی دیگر به نسخهٔ قبلی تکیه کرده؟»

The final exercises involve shared history. “Can I?” is not enough; ask “who else may already depend on the history I am about to rewrite?”

۱۳revert و commit قدیمی / Revert and the old commit

بعد از revert، git log هنوز commit بد را نشان می‌دهد. آیا revert شکست خورده؟

After a revert, the log still shows the bad commit. Did revert fail?

راهنماییHint

به دنبال commit تازهٔ معکوس هم بگرد.

Look for the new inverse commit too.

پاسخ و دلیلInterpretation

نه لزوماً؛ این رفتار مورد انتظار است. revert commit قدیمی را حذف نمی‌کند؛ commit جدیدی می‌سازد که اثر patch را برمی‌گرداند. log باید هر دو را نشان دهد و tree فعلی را با git show HEAD یا تست بررسی کن.

Not necessarily; this is expected. Revert does not delete the old commit; it adds a new commit that reverses the patch. The log should show both. Inspect the current tree or tests to verify the result.

۱۴تعارض revert / Revert conflict

یک revert وسط کار متوقف شده و git status مسیر تعارض را نشان می‌دهد. هنوز نمی‌دانی کدام محتوا درست است. اول ادامه بدهی یا abort؟

A revert stopped with a conflicted path in status. You do not know which content is correct yet. Continue or abort first?

راهنماییHint

ادامه نیازمند تصمیم دربارهٔ محتوای نهایی است.

Continuing requires a decision about the final content.

بیا بازش کنیمCareful decision

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

If the goal is unclear, run git revert --abort, then review the commit and later changes with the team. Once the intended result is clear, retry, resolve the conflict, stage it, and continue. Do not erase an in-progress operation with a hard reset.

۱۵restore از commit / Restore from a commit

با git restore --source=HEAD~1 --worktree -- file فایل دیسک عوض شد، اما git diff --staged خالی است. آیا ناحیه‌ آماده‌سازی هم نسخهٔ قدیمی شد؟

The disk file changed after git restore --source=HEAD~1 --worktree -- file, but staged diff is empty. Did the index also become the older version?

راهنماییHint

گزینهٔ worktree مقصد را محدود کرده بود.

The worktree option limited the destination.

راه‌حل و توضیحAnswer

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

No. Only the working tree copied from the older commit; the index stayed as it was. If that index matched HEAD, staged diff stays empty while the ordinary diff shows the disk-file difference. Inspect them separately.

۱۶revert merge / Reverting a merge

می‌خواهی یک merge commit را برگردانی، ولی نمی‌دانی والد اول کدام شاخه بوده و چه اثر آینده‌ای دارد. فرمان آماده‌ای که همین حالا بزنی چیست؟

You want to revert a merge commit but do not know which branch was its first parent or what future effect it has. What ready-made command should you run right now?

راهنماییHint

اینجا «فعلاً هیچ‌کدام» پاسخ حرفه‌ای است.

“None yet” is the professional answer here.

چرا این جواب درست استSafe decision

هیچ‌کدام. اول git show --no-patch --pretty=raw MERGE را بخوان تا والدها و ترتیبشان را ببینی، سپس با تیم مشخص کن mainline کدام والد است و بعدی‌ها به چه شاخههایی merge خواهند شد. تنها بعد از این بررسی، git revert -m PARENT MERGE را در محیط درست اجرا کن؛ این تصمیم روی mergeهای آینده اثر دارد.

None yet. Inspect the merge’s parents and their order, then agree with the team on the mainline parent and future merge path. Only after that should you run git revert -m PARENT MERGE in the right environment; the choice affects future merges.

۱۷ویرایش ذخیره‌نشده / Never-stored edit

فایل تازه‌ای را ویرایش کردی، هرگز ناحیه‌ آماده‌سازی نکردی، و بعد restore کردی. همکار می‌گوید «reflog حتماً متن را برمی‌گرداند». چه چیزی را باید روشن کنی؟

You edited a new file, never staged it, then restored it. A teammate says “the reflog will definitely bring the text back.” What do you need to clarify?

راهنماییHint

reflog چه چیزی را ثبت می‌کند؟

What does the reflog record?

بررسی جوابRecovery boundary

reflog جابه‌جایی اشاره‌گرها را ثبت می‌کند، نه هر بایت ویرایش تازه. اگر فایل هرگز ناحیه‌ آماده‌سازی یا commit نشده و نسخه‌ پشتیبان یا نسخهٔ دیگری وجود ندارد، Git ممکن است اصلاً شیءی برای متن آن نداشته باشد. قول بازیابی نده؛ نسخه‌های ویرایشگر، نسخه‌ پشتیبان یا سیستم فایل را جدا بررسی کن.

The reflog records ref movements, not every byte of a fresh edit. If the file was never staged or committed and no backup or other copy exists, Git may have no object containing its text. Do not promise recovery; check editor history, backups, or filesystem copies separately.

۱۸پروندهٔ تیم / Team incident

تغییر ناحیه‌ آماده‌سازیشده است، commit هنوز push نشده، اما مطمئن نیستی باید محتوا بماند یا نه. قبل از انتخاب بین restore و reset، چه بررسی‌هایی انجام می‌دهی و چه چیزی را حفظ می‌کنی؟

A change is staged but not pushed, and you are unsure whether its content should remain. Before choosing restore or reset, what do you inspect and preserve?

راهنماییHint

تصمیم را عقب بینداز، اما وضعیت فعلی را ثبت کن.

Delay the decision, but record the current state.

پاسخ پیشنهادیSafe plan

فعلاً هیچ فرمان تغییردهنده‌ای نزن. خروجی git status --short و هر دو diff را ذخیره کن؛ اگر commit وجود دارد، شناسه آن را ثبت و ایمنی شاخه بساز و تأیید کن. تغییر ناحیه‌ آماده‌سازیشده را بخوان، مالک تصمیم را پیدا کن، بعد اگر فقط unstage لازم است restore آماده‌شده؛ اگر commit باید بازچینی شود soft/mixed؛ و اگر محتوا قطعاً باید دور برود، hard فقط بعد از backup. هر repair را با همان status/diff و تست دوباره ثابت کن.

Run no mutating command yet. Save status and both diffs; if a commit exists, record its ID, create a safety branch, and verify it. Review the staged patch and find the decision owner. Then choose staged restore to unstage, soft/mixed to reshape a commit, or hard only after a backup if the content is certainly disposable. Prove the repair with the same status/diffs and tests afterward.

درمانگاه برگرداندن: چهار پرونده، چهار تصمیمUndo clinic: four cases, four decisions

چهار پرونده داریم و قرار نیست برای همه reset بزنیم. هر بار اول وضعیت را ثبت می‌کنی، بعد تصمیم می‌گیری چه چیزی باید حفظ شود و فقط همان بخش را تغییر می‌دهی. هدف پروژه این است که «undo» از یک واکنش عصبی تبدیل شود به یک تصمیم قابل توضیح.

A small team hears “undo this” four times in one afternoon. You are responsible for preserving the right version and showing evidence that nothing else was lost. Run this clinic in a fresh disposable repository—not in your working project or on a shared branch.

مخزن undo-clinic بساز و یک فایل notes.txt را در commit پایه قرار بده. برای هر پرونده، قبل از تغییر git status --short، git diff و git diff --staged را ثبت کن. بعد از اصلاح همان سه بررسی را دوباره اجرا و نتیجه را کنار هم بگذار.

Create undo-clinic and commit a base notes.txt. For every case, record status and both diffs before changing anything. After the repair, run the same checks again and compare the results.

start with a repository that can be thrown away
mkdir undo-clinic
cd undo-clinic
git init -b main
git config user.name "Clinic Learner"
git config user.email clinic@example.test
printf 'نسخهٔ پایه\n' > notes.txt
git add notes.txt
git commit -m "Add baseline note"

برای پروندهٔ چهارم، یک مخزن راه دور محلی و clone همکار بساز. از پوشهٔ undo-clinic به پوشهٔ والد برو و این آماده‌سازی را انجام بده؛ بعد دوباره به clone اصلی برگرد. حالا هر دو clone همان commit پایه را دارند.

For case four, create a local remote and a teammate clone. Run this setup from the parent directory of undo-clinic; it returns you to the original clone. Both clones now share the baseline commit.

prepare a bare remote and a second clone
cd ..
git init --bare clinic-remote.git
cd undo-clinic
git remote add origin ../clinic-remote.git
git push -u origin main
cd ..
git clone clinic-remote.git clinic-bob
  1. ویرایش ناخواسته، ناحیه‌ آماده‌سازی نشدهUnwanted unstaged edit

    یک خط اشتباه روی دیسک اضافه کن اما ناحیه‌ آماده‌سازی نکن. نسخهٔ ناحیه‌ آماده‌سازی را نگه دار و فقط پوشه‌ کاری را اصلاح کن. مدرک: diff قبل از restore خط اضافه را دارد؛ بعد از restore diff خالی است و فایل پایه سر جایش.

    Add a wrong line on disk but do not stage it. Keep the index version and repair only the working tree. Proof: the pre-restore diff contains the line; afterward the diff is empty and the base file remains.

  2. فایل اشتباه ناحیه‌ آماده‌سازی شده، محتوا باید بماندWrong file staged, content must remain

    یک فایل تازه بساز و ناحیه‌ آماده‌سازی کن، اما تصمیم بگیر فعلاً commit نشود. آن را از ناحیه‌ آماده‌سازی بیرون بیاور و روی دیسک نگه دار. مدرک: آماده‌شده diff دیگر آن فایل را نشان نمی‌دهد، فایل هنوز هست و در وضعیت ردیابی‌نشده دیده می‌شود.

    Create and stage a new file, then decide not to commit it yet. Remove it from the index but keep it on disk. Proof: staged diff no longer contains it, the file still exists, and status shows it as untracked.

  3. commit خصوصی را دوباره بازچینی کنReshape a private commit

    یک تغییر درست را commit کن، ایمنی اشاره‌گر را بساز و تأیید کن، بعد با mixed آن را به تغییر آماده‌نشده برگردان تا فقط بخشی از آن را ناحیه‌ آماده‌سازی و commit کنی. مدرک: ایمنی و log قبل/بعد، diffهای دو ناحیه و محتوای نهایی فایل.

    Commit a valid change, create and verify a safety ref, then use mixed reset to make the change unstaged so you can stage and recommit only one part. Proof: the safety ref, before/after logs, both diffs, and final file content.

  4. commit بد را همکار هم گرفتهA teammate already has the bad commit

    در undo-clinic یک commit بد بساز و push کن؛ بعد در clinic-bob آن را fetch کن تا واقعاً در دید همکار باشد. به clone اصلی برگرد، با revert اصلاحش کن و push کن؛ سپس در clone همکار fetch بزن. مدرک: log هر دو commit اصلی و معکوس را دارد، عکس فوری نهایی درست است و تاریخچهٔ clone همکار با fetch عادی پیش می‌رود، بی‌آنکه reset شود.

    Create and push a bad commit from undo-clinic, then fetch it in clinic-bob so the teammate really has it. Return to the original clone, revert the change, and push; then fetch in the teammate clone. Proof: the log retains both original and inverse commits, the final snapshot is correct, and the teammate advances with a normal fetch rather than a reset.

راهنمایی مرحله‌ایProgressive hint

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

If you are unsure which version is right, preserve both and compare them before choosing an undo command. Case three changes private history; case four preserves shared history.

درمانگاه وقتی تمام است که مدرک داشته باشیThe clinic is complete only with evidence
  • برای هر پرونده بگو تغییر پیش از کار در کدام ناحیه بود.
  • For each case, state where the change lived before the repair.
  • برای reset، ایمنی اشاره‌گر را با show-ref و commit هدف را با show ثابت کن.
  • For reset, prove the safety ref with show-ref and inspect its target commit.
  • برای revert، log باید commit اصلی و معکوس را هر دو نگه دارد.
  • For revert, the log must retain both the original and inverse commits.
  • در پایان هر فایل، هر دو diff و پوشه‌ کاری را بررسی کن؛ پاک‌کاری سراسری نکن.
  • Finish by checking files, both diffs, and the working tree; do not run broad cleanup.

وقتی log عادی دیگر commit را نشان نمی‌دهد چه؟What if the normal log no longer shows the commit?

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

You can now identify which area each undo command changes, why a shared commit is usually corrected with revert, and why none can recover content Git never stored. But suppose reset moved the branch and ordinary git log no longer shows the earlier commit. Chapter 10 opens Git’s local journal of ref movements: the reflog—a useful clue, not a promise to recover every bit of data.

مرور کوتاهQuick reference

پیش از هر برگشت، این پرسش‌ها را بپرسAsk these questions before every undo
  • تغییر روی پوشه‌ کاری است، در ناحیه‌ آماده‌سازی است، داخل commit است یا از قبل به اشتراک گذاشته شده؟
  • Is the change in the working tree, the index, a commit, or already shared?
  • restore نسخه‌ای را در مقصد انتخاب‌شده کپی می‌کند؛ منبع پیش‌فرض را فراموش نکن.
  • restore copies a source into a chosen destination; check the default source.
  • reset --soft فقط شاخه را جابه‌جا می‌کند؛ --mixed ناحیه‌ آماده‌سازی را هم؛ --hard پوشه‌ کاری ردیابی‌شده را هم.
  • reset --soft moves the branch; --mixed also resets the index; --hard also replaces tracked working files.
  • revert commit قبلی را نگه می‌دارد و commit معکوس تازه می‌سازد.
  • revert keeps the old commit and adds a new inverse commit.
  • قبل از بازنویسی commit خصوصی ایمنی اشاره‌گر و برای کار ذخیره‌نشده نسخه‌ پشتیبان داشته باش؛ برای کار مشترک هماهنگ شو.
  • Before rewriting a private commit, create a safety ref; back up unsaved work and coordinate on shared history.
بعد از این فصل باید بتوانیBy the end of this chapter, you can
  • نسخه‌های HEAD، ناحیه‌ آماده‌سازی و پوشه‌ کاری را از هم تشخیص بدهی و مقصد restore را روشن انتخاب کنی.
  • Distinguish HEAD, index, and working-tree versions and choose a restore destination deliberately.
  • رفتار soft، mixed و hard را قبل از اجرا برای هر سه ناحیه پیش‌بینی کنی.
  • Predict all three areas after soft, mixed, or hard reset.
  • بین بازنویسی commit خصوصی و revert کردن تغییر مشترک تصمیم بگیری.
  • Choose between rewriting a private commit and reverting a shared change.
  • محدودیت ایمنی اشاره‌گر و reflog را توضیح بدهی و برای دادهٔ هرگز ذخیره‌نشده وعدهٔ بازیابی ندهی.
  • Explain the limits of safety refs and reflog and never promise recovery for never-stored data.

برای جزئیات گزینه‌ها، راهنمای رسمی restore، reset، revert و commit را ببین. فرمان را با نسخهٔ نصب‌شده‌ات و در مخزن آزمایشی بررسی کن، به‌خصوص پیش از تغییر تاریخچه.

For option details, see the official manuals for git restore, git reset, git revert, and git commit --amend. Check commands against your installed version in a disposable repository, especially before rewriting history.