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

سه ناحیه:
working tree، staging و مخزن

Three areas:
working tree, staging, and repository

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

Chapter 01 introduced the three areas, and Chapter 02 connected the index to Git trees. Now we will deliberately keep one file in three versions so you can predict which version each command sees—and which one a commit records.

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

یک فایل، سه نسخهٔ هم‌زمانOne file, three versions at once

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

You are refining an error message. The last committed version says “Invalid request.” You staged a newer version saying “Invalid ID,” then edited the file again to say “Invalid user ID.”

حالا git status یک نام فایل را هم در «آمادهٔ ثبت» نشان می‌دهد و هم در «تغییرهای آماده‌نشده». سؤال اینجاست: «چطور یک نام فایل می‌تواند هر دو وضعیت را داشته باشد؟» تناقض نیست؛ وضعیت اختلاف دو جفت از سه نسخه را جداگانه گزارش می‌کند.

git status now lists one filename under both “to be committed” and “not staged.” The question is: “How can one filename have both statuses?” It is not a contradiction; status reports two different comparisons involving three versions.

One file has different committed, staged, and working-tree versions HEAD / repositoryInvalid requestcommitted version index / stagingInvalid IDstaged version working treeInvalid user IDfile on disk git add edit file status compares HEAD ↔ index and index ↔ working tree

نمودار ۱ — فلش git add محتوای همان لحظه را از فایل به ناحیه‌ آماده‌سازی می‌برد؛ ویرایش بعدی فقط فایل روی دیسک را عوض می‌کند.

Diagram 1 — git add copies the content as it exists at that moment into the index; a later edit changes only the file on disk.

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

To keep this model from being just a drawing, we will test it in a separate folder. Do not run the following sequence in a real work repository: the experiment deliberately changes files and creates several states.

bash · disposable three-area-lab
mkdir three-area-lab && cd three-area-lab
git init -q
git config user.name 'Ada Example'
git config user.email 'ada@example.test'
printf 'Invalid request\n' > message.txt
git add message.txt && git commit -m 'Add initial message'

حدس بزن: حالا هر سه ناحیه چه محتوایی دارند؟ چون همین الان commit کرده‌ایم و فایل را بعدش دست نزده‌ایم، هر سه برابرند. وضعیت باید تمیز باشد و هر دو diff خالی.

Predict first: what does each area contain now? We just committed and have not edited the file since, so all three match. Status should be clean and both diffs empty.

هر diff فقط یک جفت را مقایسه می‌کندEach diff compares one pair

اگر سه نسخه داریم، برای پیدا کردن اختلاف باید بپرسیم «کدام دو نسخه؟» اسم دستورها همین جواب را می‌دهند: git diff پوشه‌ کاری را با ناحیه‌ آماده‌سازی می‌سنجد؛ git diff --staged یا --cached، ناحیه‌ آماده‌سازی را با HEAD.

With three versions, every comparison must answer “which two?” The commands encode that answer: git diff compares the working tree with the index; git diff --staged (or --cached) compares the index with HEAD.

فرمانCommandمقایسهComparisonپرسش روزمرهPractical question
git diffپوشه‌ کاری در برابر ناحیه‌ آماده‌سازیworking tree vs indexچه چیزی را هنوز ناحیه‌ آماده‌سازی نکرده‌ام؟What have I not staged yet?
git diff --stagedناحیه‌ آماده‌سازی در برابر HEADindex vs HEADاگر الان commit کنم، چه چیزی ثبت می‌شود؟What will be recorded if I commit now?
git diff HEADپوشه‌ کاری در برابر HEADworking tree vs HEADاز آخرین commit تا فایل روی دیسک چه فرق دارد؟What differs from the last commit to the file on disk?

حالا وضعیت پایه را ثبت کن. خروجی نمونه ثابت نیست؛ نام شاخه و پیام commit با مخزن تو فرق می‌کند. نکتهٔ مهم این است که وضعیت تمیز است، و هیچ‌یک از دو مقایسه تغییری برای نشان دادن ندارد.

Record the baseline. The sample output is illustrative: your branch name and commit message may differ. What matters is the clean status and the absence of changes in either comparison.

bash · predict, then inspect
git status --short
git diff
git diff --staged
(no output from status or either diff)

حالا فقط فایل را ویرایش می‌کنیم؛ هنوز add نه. حدس بزن کدام diff متن جدید را نشان می‌دهد.

Now edit only the file; do not add it yet. Predict which diff will show the new text.

bash · working-tree-only change
printf 'Invalid ID\n' > message.txt
git status --short
git diff
git diff --staged
 M message.txt
diff shows: -Invalid request / +Invalid ID
git diff --staged is empty

فاصلهٔ قبل از M یعنی ستون اول، یعنی ناحیه‌ آماده‌سازی، تغییر نکرده؛ ستون دوم یعنی پوشه‌ کاری تغییر کرده. در این لحظه فایل روی دیسک «Invalid شناسه» است، اما ناحیه‌ آماده‌سازی و HEAD هنوز «Invalid request» را دارند.

The leading blank before M means column one—the index—did not change; column two—the working tree—did. The file says “Invalid ID,” while the index and HEAD still say “Invalid request.”

بعد از git add همان فایل، اول حدس بزن: آیا این دستور نسخهٔ بعدی را در commit می‌گذارد یا فقط وضعیت فایل را ثبت می‌کند؟

After git add on this file, predict: does it put the new version in the next commit, or merely mark the file's state?

bash · staged change
git add message.txt
git status --short
git diff
git diff --staged
M  message.txt
git diff is empty
staged diff shows: -Invalid request / +Invalid ID

این بار ستون اول M است و ستون دوم خالی. اختلاف در جفت HEAD ↔ ناحیه‌ آماده‌سازی است؛ پس diff --staged آن را می‌بیند. پوشه‌ کاری و ناحیه‌ آماده‌سازی فعلاً یکسان‌اند، برای همین git diff خالی است.

Now the first column is M and the second is blank. The difference is between HEAD and the index, so diff --staged shows it. The working tree and index currently match, so git diff is empty.

حالا متن را یک‌بار دیگر تغییر بده. از وضعیت MM نترس؛ دو حرف یعنی دو اختلاف مستقل، نه دو فایل.

Edit the text once more. Do not be alarmed by MM; the two letters mean two separate differences, not two files.

bash · staged and edited again
printf 'Invalid user ID\n' > message.txt
git status --short
git diff --staged
git diff
MM message.txt
staged:   Invalid request → Invalid ID
unstaged: Invalid ID → Invalid user ID

حالا هر دو نسخه را می‌بینی: diff ناحیه‌ آماده‌سازیشده از HEAD تا ناحیه‌ آماده‌سازی است و diff معمولی از ناحیه‌ آماده‌سازی تا پوشه‌ کاری. نام فایل یکی است چون هر دو تغییر در همان مسیرند.

You can now see both versions: the staged diff runs from HEAD to the index, and plain diff runs from the index to the working tree. The filename is the same because both changes affect that path.

Status reports a staged version and a newer working-tree version for one file HEADInvalid requestunchanged indexInvalid IDM = staged working treeInvalid user IDM = unstaged staged diff plain diff git status --short: MM message.txt left column = index; right column = working tree

نمودار ۲ — MM یعنی همان مسیر هم نسبت به HEAD در ناحیه‌ آماده‌سازی تغییر کرده و هم نسبت به ناحیه‌ آماده‌سازی روی دیسک تغییر تازه‌تری دارد.

Diagram 2 — MM means the path differs from HEAD in the index and has a newer difference on disk relative to the index.

ناحیه‌ آماده‌سازی اتاق انتظار نیست؛ پیش‌نویس tree بعدی استThe index is not a waiting room; it is the next tree draft

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

“Staging area” can sound like a shelf where whole files wait for commit. More precisely, the index is a table of paths and the content version proposed for each path in the next snapshot. As Chapter 02 showed, entries point to blobs and modes; a commit turns this list into trees.

Partial staging selects hunk A for the index while hunk B stays only in the working tree working-tree diffhunk A: bug fixhunk B: debug printboth exist on disk git add -preview each hunky for A · n for B proposed indexhunk A: bug fixdebug stays unstaged only the selected patch is applied to the index staged diff shows A · plain diff still shows B

نمودار ۳ — git add -p به‌جای انتخاب کل فایل، تکه‌های تغییر را برای ناحیه‌ آماده‌سازی انتخاب می‌کند؛ قبل از پاسخ y یا n متن هر hunk را بخوان.

Diagram 3 — git add -p selects change hunks for the index instead of selecting the whole file; read each hunk before answering y or n.

این همان چیزی است که یک commit اتمی را ممکن می‌کند: اصلاح باگ را جدا ثبت می‌کنی و چاپ عیب‌یابی را نگه می‌داری تا بعداً تصمیم بگیری. «اتمی» یعنی یک commit دلیل روشن و تغییرهای مرتبط دارد، نه اینکه Git فایل را به شکل فیزیکی تکه‌تکه ذخیره کند.

This is what makes an atomic commit possible: record the bug fix separately and leave the debug print for a later decision. “Atomic” means one commit has a clear purpose and related changes; it does not mean Git physically stores the file in pieces.

برای دیدن ناحیه‌ آماده‌سازی، git ls-files --stage مدخل‌هایش را نشان می‌دهد. شناسه ستون دوم شناسهٔ blob است و ناحیه‌ آماده‌سازی number در حالت عادی صفر است. در تعارض merge ممکن است چند مدخل ناحیه‌ آماده‌سازی برای یک مسیر ببینی؛ آن موضوع را فصل merge باز می‌کند.

git ls-files --stage displays index entries. The second column is the blob ID; the stage number is normally zero. During a merge conflict, one path can have multiple stage entries—a topic the merge chapter will cover.

bash · inspect the proposed snapshot
git ls-files --stage
100644 8a7b6c5... 0	message.txt
git diff --staged --stat
 message.txt | 2 +-

این شاهد می‌گوید ناحیه‌ آماده‌سازی برای message.txt یک مدخل دارد و diff --staged اندازهٔ تغییرِ پیشنهادی را نشان می‌دهد. اما یک blob شناسه ثابت نمی‌کند متن از نظر محصول درست است؛ باز هم خود diff را بخوان.

This evidence says the index has an entry for message.txt and diff --staged summarizes the proposed change. A blob ID does not prove the wording is correct for the product; still read the diff itself.

ناحیهAreaچه چیزی را نشان می‌دهدWhat it representsدستور شاهدInspection command
HEADعکس فوری آخرین commit شاخهٔ جاریThe current branch's latest committed snapshotgit show HEAD:message.txt
indexپیشنهاد تو برای عکس فوری بعدیYour proposal for the next snapshotgit ls-files --stage
working treeفایل‌های روی دیسک، شامل ویرایش‌های هنوز ناحیه‌ آماده‌سازینشدهFiles on disk, including edits not yet stagedgit diff / editor

commit از ناحیه‌ آماده‌سازی ساخته می‌شود، نه از هرچه روی دیسک ماندهA commit comes from the index, not everything left on disk

نسخهٔ سوم را می‌سازیم: بعد از ناحیه‌ آماده‌سازی کردن «Invalid شناسه»، فایل را به «Invalid user شناسه» تغییر می‌دهیم. قبل از commit حدس بزن: کدام متن در عکس فوری بعدی خواهد بود؟

Create a third version: after staging “Invalid ID,” edit the file to say “Invalid user ID.” Before committing, predict which text the next snapshot will contain.

bash · one tracked file, two differences
printf 'Invalid ID\n' > message.txt
git add message.txt
printf 'Invalid user ID\n' > message.txt
git status --short
git diff --staged
git diff
MM message.txt
staged:   Invalid request → Invalid ID
unstaged: Invalid ID → Invalid user ID

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

MM means both comparisons contain changes. Review the staged diff before committing: the disk file has a newer version, but it does not enter the index automatically.

Git builds a commit tree from the index and leaves unstaged changes out HEAD snapshotInvalid request indexInvalid ID file on diskInvalid user ID new commit treerecords “Invalid ID” unstaged edit stays outside

نمودار ۴ — commit از مدخل‌های ناحیه‌ آماده‌سازی یک tree می‌سازد. تغییر تازه‌تر روی دیسک بیرون آن می‌ماند تا دوباره ناحیه‌ آماده‌سازی شود.

Diagram 4 — A commit builds a tree from index entries. The newer disk edit remains outside until staged again.

پیش‌بینی را با ثبت commit و خواندن فایل از خود commit امتحان کن. این بار عمداً از git show HEAD:message.txt استفاده می‌کنیم، نه از ویرایشگر؛ پس عکس فوری ثبت‌شده را می‌خوانیم.

Test your prediction by committing and reading the file from the commit itself. We use git show HEAD:message.txt, not the editor, so we inspect the recorded snapshot.

bash · prove which copy was committed
git diff --staged
git commit -m 'Clarify invalid ID message'
git show HEAD:message.txt
git status --short
git diff
git diff --staged
Invalid ID
 M message.txt
git diff shows: -Invalid ID / +Invalid user ID
git diff --staged is empty

commit نسخهٔ ناحیه‌ آماده‌سازی یعنی «Invalid شناسه» را ثبت کرد و فایل روی دیسک هنوز «Invalid user شناسه» است؛ بنابراین وضعیت تغییر آماده‌نشده نشان می‌دهد. برای گنجاندن متن آخر باید دوباره git add message.txt بزنی و diff را دوباره بخوانی.

The commit recorded the index version, “Invalid ID,” while the disk file still says “Invalid user ID,” so status reports an unstaged edit. To include the latest text, run git add message.txt again and review the diff.

add یعنی انتخاب نسخه و مسیر، نه زدن تیک کل فایلadd selects content and paths; it does not tick a whole file

یک فایل handler.js را تصور کن: هم شرطی که باگ را حل می‌کند عوض شده، هم یک چاپ عیب‌یابی اضافه کرده‌ای. می‌خواهی اصلاح باگ را همین حالا ثبت کنی و عیب‌یابی را بعد از بررسی حذف کنی. git add handler.js هر دو تغییر را ناحیه‌ آماده‌سازی می‌کند؛ برای جدا کردنشان، git add -p را به کار ببر.

Imagine handler.js contains both a bug fix and a temporary debug print. You want to commit the fix now and remove the print after inspection. git add handler.js stages both changes; use git add -p to separate them.

bash · interactive patch selection
git diff -- handler.js
git add -p handler.js
Stage this hunk [y,n,q,a,d,s,e,?]? y
Stage this hunk [y,n,q,a,d,s,e,?]? n
git diff --staged -- handler.js
git diff -- handler.js

در نمونه، برای hunk اصلاح باگ y و برای چاپ عیب‌یابی n می‌زنی. prompt واقعی گزینه‌های بیشتری دارد؛ s اگر بتواند hunk را خرد می‌کند و ? راهنمای همان نسخه را نشان می‌دهد. خروجی را فرض نکن—بعدش هر دو diff را بخوان تا مطمئن شوی انتخاب درست بوده.

In this example, answer y for the bug-fix hunk and n for the debug print. The real prompt offers more choices: s may split a hunk, and ? explains the options for your version. Inspect both diffs afterwards to verify the selection.

فرمانCommandچه چیزی وارد ناحیه‌ آماده‌سازی می‌شود؟What enters the index?محدوده‌ای که باید حواست باشدScope to watch
git add FILEوضعیت فعلی مسیر مشخص‌شده؛ اگر پاک شده باشد، حذف را هم ناحیه‌ آماده‌سازی می‌کند.The current state of that path; if removed, it stages the deletion too.فایل کامل، نه فقط بخشی که قصدش را داشتی.The whole file, not necessarily only the part you intended.
git add -phunkهایی که تعاملی انتخاب می‌کنی.The hunks you select interactively.هر hunk را بخوان؛ گاهی باید آن را خرد کنی.Read each hunk; sometimes you must split it.
git add -uتغییر و حذف مسیرهای از قبل ردیابی‌شده؛ فایل تازه را اضافه نمی‌کند.Changes and deletions to tracked paths; it does not add new files.به pathspec و نسخهٔ Git دقت کن.Mind the pathspec and Git version.
git add -Aاضافه، تغییر و حذف را در محدودهٔ داده‌شده هماهنگ می‌کند.Adds, changes, and removals within the given scope.بدون مسیر، کل پوشه‌ کاری؛ اول وضعیت و diff را ببین.Without a path, the whole working tree; inspect status and diffs first.

در Git امروزی، git add -A بدون مسیر کل پوشه‌ کاری را می‌گیرد؛ با pathspec فقط همان محدوده را هماهنگ می‌کند. git add . هم pathspec نقطه را دارد، یعنی پوشهٔ فعلی و زیرشاخه‌هایش؛ در نسخه‌های امروزی حذف‌ها را هم در این محدوده می‌بیند. رفتار تاریخی نسخه‌های خیلی قدیمی فرق داشت، پس راهنمای قدیمی را بی‌بررسی کپی نکن. برای commit دقیق، مسیر یا hunk را انتخاب کن و قبل از commit git diff --staged بخوان.

In current Git, pathless git add -A covers the whole working tree; with a pathspec, it updates only that scope. git add . uses the dot pathspec, meaning the current directory and its descendants; current versions also notice removals there. Very old versions behaved differently, so do not copy old guidance without checking. For a precise commit, choose paths or hunks and review git diff --staged.

قبل از add گسترده، یک مکثPause before a broad add

git add . یا git add -A ممکن است فایل تولیدشده، تنظیم محلی یا دادهٔ ناخواسته را هم وارد ناحیه‌ آماده‌سازی کند. .gitignore به فایل‌های از قبل ردیابی‌شده کمک نمی‌کند. اول git status --short را ببین؛ بعد مسیرهای موردنیاز را انتخاب کن. رمز واقعی را اگر ناحیه‌ آماده‌سازی شد، صرفاً با بیرون‌آوردنش از ناحیه‌ آماده‌سازی امن فرض نکن.

git add . or git add -A can stage generated output, local configuration, or other unwanted files. .gitignore does not protect files already tracked. Check status first, then choose paths. If a real secret was staged, removing it from the index alone does not make it safe.

حذف و تغییرنام را هم با همین مدل بخوانRead deletions and renames through the same model

اگر فایل ردیابی‌شده را از دیسک پاک کنی، ناحیه‌ آماده‌سازی هنوز نسخهٔ قبلی را دارد؛ پس وضعیت حذفِ آماده‌نشده نشان می‌دهد. git add FILE برای همان مسیر حذف‌شده یا git add -A حذف را در ناحیه‌ آماده‌سازی ثبت می‌کند. در تغییرنام هم Git یک شیء ویژهٔ تغییرنام ذخیره نمی‌کند: مسیر قدیمی حذف و مسیر تازه اضافه می‌شود؛ هنگام نمایش diff، Git ممکن است شباهت محتوا را تشخیص دهد و آن را تغییرنام نشان دهد.

If you remove a tracked file from disk, the index still contains its old version, so status reports an unstaged deletion. git add FILE for that removed path, or git add -A, stages the removal. A rename is not stored as a special object: the old path is removed and a new path added; Git may infer a rename from content similarity when showing a diff.

bash · deletion and path change
rm message.txt
git status --short
 D message.txt
git add message.txt
git status --short
D  message.txt
git diff --staged --summary

در خروجی کوتاه، D یعنی فایل روی دیسک حذف شده ولی هنوز ناحیه‌ آماده‌سازی نشده؛ D یعنی حذف در ناحیه‌ آماده‌سازی آمادهٔ commit است. کد تغییرنام نمایش‌داده‌شده نتیجهٔ تشخیص هنگام مقایسه است، نه مدخل ذخیره‌شدهٔ جداگانه.

In short status, D means the file is deleted on disk but not staged; D means the deletion is staged. A displayed rename code is inferred during comparison, not a separate stored index entry.

restore در این فصل: کدام کپی را نگه می‌داری؟restore in this chapter: which copy do you keep?

فرض کن متن را ناحیه‌ آماده‌سازی کرده‌ای، اما هنوز در پوشه‌ کاری یک اصلاح ناخواسته مانده. می‌خواهی فقط فایل روی دیسک را با نسخهٔ ناحیه‌ آماده‌سازی عوض کنی. این کار محتوای ناحیه‌ آماده‌سازیشده را نگه می‌دارد، ولی ویرایش آماده‌نشده را کنار می‌گذارد—پس فقط وقتی بزن که آن ویرایش را نمی‌خواهی.

Suppose you staged a version, then left an unwanted edit in the working tree. You want to replace only the disk file with the index version. This keeps the staged content but discards the unstaged edit—so use it only if you no longer want that edit.

bash · restore disk from index
git diff -- message.txt
-Invalid ID
+Invalid user ID
git restore -- message.txt
git diff -- message.txt
(no output: working tree now matches index)

بدون --staged، منبع پیش‌فرض پوشه‌ کاری، ناحیه‌ آماده‌سازی است. در مقابل، اگر چیزی را ناحیه‌ آماده‌سازی کرده‌ای و می‌خواهی ناحیه‌ آماده‌سازی را به HEAD برگردانی، git restore --staged FILE را بزن. نسخهٔ روی دیسک دست‌نخورده می‌ماند؛ تغییر فقط از ناحیه‌ آماده‌سازی بیرون می‌رود.

Without --staged, the default source for the working tree is the index. In contrast, to restore a staged path in the index to HEAD, run git restore --staged FILE. The disk copy stays untouched; only the index changes.

bash · restore index from HEAD
git diff --staged -- message.txt
(shows staged change)
git restore --staged -- message.txt
git status --short
 M message.txt
git diff -- message.txt
(change remains on disk, now unstaged)
فرمانCommandکجا را عوض می‌کند؟What does it change?منبع پیش‌فرضDefault source
git restore -- FILEپوشه‌ کاریworking treeناحیه‌ آماده‌سازیindex
git restore --staged -- FILEناحیه‌ آماده‌سازیindexHEADHEAD

اگر فایل تازه‌ای را ناحیه‌ آماده‌سازی کرده‌ای، restore --staged مدخل تازه را از ناحیه‌ آماده‌سازی برمی‌دارد و فایل روی دیسک را به حالت ردیابی‌نشده برمی‌گرداند. اگر فایل ردیابی‌شده را حذف و حذف را ناحیه‌ آماده‌سازی کرده‌ای، restore کردن ناحیه‌ آماده‌سازی نسخهٔ HEAD را به ناحیه‌ آماده‌سازی برمی‌گرداند، اما فایل ممکن است همچنان روی دیسک غایب باشد؛ آن وقت حذف، آماده‌نشده است. راه‌های دیگر برگشت، موضوع فصل ۹ هستند.

If you staged a new file, restore --staged removes its new index entry and leaves the disk file untracked. If you deleted a tracked file and staged the deletion, restoring the index brings the HEAD version back into the index, but the disk file may still be absent; the deletion is then unstaged. Other ways to undo work belong to Chapter 09.

اسم restore را کافی ندانDo not trust the word “restore” alone

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

Before running it, ask: which area is the destination? Which version is the source? Have I saved the version I am about to discard somewhere else? Restoring the working tree can remove an unsaved edit; do not guess.

وضعیت نقشهٔ تشخیصی استstatus is a diagnostic map

به‌جای حفظ کردن متن کامل وضعیت، خروجی کوتاه را مثل دو ستون بخوان. ستون چپ وضعیت ناحیه‌ آماده‌سازی نسبت به HEAD است؛ ستون راست وضعیت پوشه‌ کاری نسبت به index. پس یک حرف می‌تواند برای یک فایل دو بار ظاهر شود و هر بار دربارهٔ مقایسه‌ای جدا حرف بزند.

Rather than memorising every status sentence, read short status as two columns. The left column is the index relative to HEAD; the right is the working tree relative to the index. One path can show two letters, each describing a different comparison.

نمونهٔ کوتاهShort statusناحیه‌ آماده‌سازیIndexپوشه‌ کاریWorking treeبرداشتInterpretation
?? new.txt—untrackedGit هنوز مسیر را در ناحیه‌ آماده‌سازی ندارد.The path is not in the index yet.
M fileهمان HEADsame as HEADmodifiedفقط نسخهٔ روی دیسک فرق دارد.Only the disk copy differs.
M filemodifiedهمان ناحیه‌ آماده‌سازیsame as indexتغییر ناحیه‌ آماده‌سازی شده و فایل با ناحیه‌ آماده‌سازی برابر است.A staged change; disk matches the index.
MM filemodifiedmodified againنسخهٔ ناحیه‌ آماده‌سازیشده و فایل روی دیسک فرق دارند.The staged copy and disk file differ.
D filedeletedهمان ناحیه‌ آماده‌سازیsame as indexحذف برای commit آماده است.The deletion is staged for commit.
D fileنسخهٔ قدیمی هنوز هستold entry remainsdeletedحذف هنوز ناحیه‌ آماده‌سازی نشده.The deletion is not staged yet.
A fileaddedهمان ناحیه‌ آماده‌سازیsame as indexفایل تازه در عکس فوری بعدی پیشنهاد شده.A new file is proposed for the next snapshot.

اگر تغییر مورد انتظار را نمی‌بینی، از همان‌جا حدس نزن که Git خراب است. git status --ignored کمک می‌کند فایل نادیده‌گرفته‌شده را از ردیابی‌نشده تشخیص بدهی؛ git check-ignore -v FILE هم قاعدهٔ مسئول را نشان می‌دهد. فایلی که هنوز track نشده ممکن است در git diff معمولی نیاید، چون آن دستور تغییر مسیرهای ردیابی‌شده را مقایسه می‌کند.

If an expected change is missing, do not conclude that Git is broken. git status --ignored helps distinguish an ignored file from an untracked one; git check-ignore -v FILE identifies the matching rule. A path never tracked may not appear in ordinary git diff, which compares changes to tracked paths.

bash · distinguish missing from ignored
git status --short --ignored
git check-ignore -v build/report.txt
.gitignore:4:build/    build/report.txt

این خروجی می‌گوید قاعدهٔ خط چهارم باعث نادیده‌گرفتن مسیر شده؛ ثابت نمی‌کند فایل بی‌ارزش است. اگر خروجی خالی بود، شاید مسیر وجود ندارد، از قبل track شده یا قاعدهٔ دیگری در کار است—وضعیت فایل را جدا بررسی کن.

This output says the fourth rule ignored the path; it does not prove the file is disposable. If output is empty, the path may not exist, may already be tracked, or may be governed differently—inspect its status separately.

چند دام رایج، با شاهد درستCommon traps, with the right evidence

“I staged it, then edited it; why is my fix missing?”
علت
Cause
add محتوای همان لحظه را در ناحیه‌ آماده‌سازی ثبت کرد. ویرایش بعدی فقط پوشه‌ کاری را عوض کرد.
add put the content as it existed at that moment into the index. A later edit changed only the working tree.
بررسی
Check
git diff --staged را با git diff مقایسه کن؛ اولی محتویات commit بعدی را نشان می‌دهد.
Compare git diff --staged with git diff; the former shows the proposed commit content.
“git diff is empty, so there are no changes.”
علت
Cause
شاید همهٔ تغییرها ناحیه‌ آماده‌سازی شده‌اند؛ یا فایل تازه است و هنوز ردیابی نمی‌شود.
Perhaps all changes are staged, or the file is new and not tracked yet.
بررسی
Check
git status --short و git diff --staged را هم ببین؛ برای فایل نادیده، git check-ignore -v.
Also inspect git status --short and git diff --staged; use git check-ignore -v for ignored files.
“I moved the file, but Git shows delete and untracked.”
علت
Cause
این دو مسیر هنوز برای ناحیه‌ آماده‌سازی جدا هستند. Git تغییرنام را به‌صورت یک شیء مستقل ذخیره نمی‌کند و ممکن است هنوز شباهت را تشخیص نداده باشد.
The index sees two separate paths. Git does not store a rename as a distinct object and may not have inferred similarity yet.
بررسی
Check
هر دو مسیر را ناحیه‌ آماده‌سازی کن و بعد git diff --staged --summary را بخوان.
Stage both paths, then inspect git diff --staged --summary.
“I ran git restore and the edit disappeared.”
علت
Cause
بدون --staged، فرمان فایل روی دیسک را از ناحیه‌ آماده‌سازی برمی‌گرداند؛ تغییر آماده‌نشده قبلی جایگزین می‌شود.
Without --staged, it restores the disk file from the index, replacing the previous unstaged edit.
بررسی
Check
قبل از restore، هر دو diff را بخوان؛ اگر نسخه لازم است، جدا ذخیره‌اش کن. برای کار از دست‌رفته تضمین بازیابی نده.
Before restoring, inspect both diffs and save any needed version elsewhere. Do not promise recovery without a copy.

تمرین‌هاExercises

در تمرین‌ها مهم‌تر از اسم دستور این است که بتوانی قبل از اجرا بگویی «این دستور کدام دو نسخه را مقایسه می‌کند یا کدام نسخه را جابه‌جا می‌کند؟» اگر این جمله را درست بگویی، شکل دستور را بعداً هم می‌توانی از راهنما پیدا کنی.

For each question, first predict the version in every area, then choose a command. Most can be tested in the disposable lab; stay away from repositories with valuable work.

تمرین‌های حل‌شدهSolved۰ / ۱۸
تمرین ۳٫۱Exercise 3.1مبتدیBeginner۳ دقیقه3 min

فایل ردیابی‌شده را ویرایش کرده‌ای، اما git add نزده‌ای. کدام فرمان تغییر را نشان می‌دهد؟

You edited a tracked file but have not run git add. Which diff shows the change?

راهنماییHint

فایل روی دیسک را با ناحیه‌ آماده‌سازی مقایسه کن.

Compare the disk file with the index.

پاسخ و دلیلSolution

git diff. این تغییر هنوز در پوشه‌ کاری است. git diff --staged اختلاف ناحیه‌ آماده‌سازی با HEAD را می‌سنجد و اینجا خالی می‌ماند.

git diff. The edit is only in the working tree. git diff --staged compares the index with HEAD, so it is empty here.

تمرین ۳٫۲Exercise 3.2مبتدیBeginner۳ دقیقه3 min

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

You staged a change and have not edited the file since. What will short status most likely show?

راهنماییHint

ستون اول ناحیه‌ آماده‌سازی است و ستون دوم پوشه‌ کاری.

The first column is the index; the second is the working tree.

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

برای فایل ویرایش‌شده معمولاً M می‌بینی: ناحیه‌ آماده‌سازی نسبت به HEAD تغییر دارد، اما دیسک با ناحیه‌ آماده‌سازی برابر است. برای فایل تازه، حرف اول A است.

For a modified tracked file, expect M : the index differs from HEAD, while disk matches the index. For a new file, the first letter is A.

تمرین ۳٫۳Exercise 3.3مبتدیBeginner۴ دقیقه4 min

git status --short می‌گوید MM notes.txt. دو حرف را تفسیر کن.

git status --short shows MM notes.txt. Interpret both letters.

راهنماییHint

هر حرف یک مقایسهٔ جداست.

Each letter describes a separate comparison.

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

ناحیه‌ آماده‌سازی نسبت به HEAD تغییر دارد و فایل روی دیسک هم نسبت به ناحیه‌ آماده‌سازی دوباره تغییر کرده. git diff --staged نسخهٔ اول و git diff نسخهٔ دوم را نشان می‌دهد.

The index differs from HEAD, and the disk file differs again from the index. git diff --staged shows the first change; git diff shows the second.

تمرین ۳٫۴Exercise 3.4مبتدیBeginner۴ دقیقه4 min

چرا ممکن است git diff خالی باشد، ولی git status بگوید تغییر آمادهٔ commit داری؟

Why can git diff be empty while git status says changes are ready to commit?

راهنماییHint

آیا فایل روی دیسک با ناحیه‌ آماده‌سازی یکی است؟

Does the disk file match the index?

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

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

They may match while the only difference is between the index and HEAD. Read git diff --staged to inspect the proposed commit.

تمرین ۳٫۵Exercise 3.5میانیIntermediate۵ دقیقه5 min

نسخهٔ A را ناحیه‌ آماده‌سازی کردی، بعد روی دیسک نسخهٔ B نوشتی و commit زدی. git show HEAD:file کدام را می‌خواند؟

You staged version A, then wrote version B on disk and committed. Which version does git show HEAD:file read?

راهنماییHint

commit از کدام ناحیه ساخته می‌شود؟

Which area supplies the commit?

بررسی جوابSolution

نسخهٔ A، اگر بعد از نوشتن B دوباره add نکرده باشی. فایل روی دیسک B می‌ماند و وضعیت احتمالاً تغییر آماده‌نشده نشان می‌دهد. git show عکس فوری ثبت‌شده را می‌خواند، نه فایل فعلی.

Version A, unless you staged again after writing B. The disk file remains B and status likely shows an unstaged edit. git show reads the recorded snapshot, not the current file.

تمرین ۳٫۶Exercise 3.6میانیIntermediate۵ دقیقه5 min

فایل ردیابی‌شده را از پوشه‌ کاری پاک کرده‌ای و می‌خواهی حذفش در commit بعدی ثبت شود. چه می‌کنی؟

You removed a tracked file from the working tree and want the deletion recorded next. What do you do?

راهنماییHint

ناحیه‌ آماده‌سازی هنوز نسخهٔ قبلی را دارد؛ آن را با وضعیت مسیر هماهنگ کن.

The index still has the old entry; update it to match the path's state.

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

در مخزن آزمایشی، git add -- FILE یا git add -A -- FILE بزن و git diff --staged را ببین. D در ستون اول یعنی حذف ناحیه‌ آماده‌سازی شده. git rm هم می‌تواند هر دو ناحیه را تغییر دهد، اما این آزمایش روی add است.

In the disposable repository, run git add -- FILE or git add -A -- FILE, then inspect git diff --staged. D in the first column means staged deletion. git rm can affect both areas, but this experiment focuses on add.

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

If the three areas are clear now, the next exercises get harder because one file can show two states at once. Before running anything, write down the three versions of that file.

تمرین ۳٫۷Exercise 3.7میانیIntermediate۵ دقیقه5 min

پس از git add -p فقط اصلاح باگ را ناحیه‌ آماده‌سازی کردی و عیب‌یابی print روی دیسک ماند. کدام diff هرکدام را نشان می‌دهد؟

After git add -p, only the bug fix is staged and the debug print stays on disk. Which diff shows each?

راهنماییHint

دو مقایسهٔ متفاوت داریم.

There are two different comparisons.

پاسخ و دلیلSolution

git diff --staged باید اصلاح باگ را نشان دهد؛ git diff باید تغییر عیب‌یابی را نشان دهد. بعد از انتخاب تعاملی هر دو را بخوان تا مطمئن شوی hunkها درست جدا شده‌اند.

git diff --staged should show the fix; git diff should show the debug change. Inspect both after selection to verify the hunks were separated as intended.

تمرین ۳٫۸Exercise 3.8میانیIntermediate۵ دقیقه5 min

می‌خواهی فقط تغییرهای مسیرهای از قبل ردیابی‌شده را ناحیه‌ آماده‌سازی کنی و فایل‌های تازه را نه. کدام گزینه مناسب‌تر است؟

You want to stage changes to tracked paths but not new files. Which option fits?

راهنماییHint

گزینه‌ای را پیدا کن که ناحیه‌ آماده‌سازی موجود را به‌روز می‌کند.

Look for the option that updates existing index entries.

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

git add -u برای مسیرهای trackشده تغییرها و حذف‌ها را ناحیه‌ آماده‌سازی می‌کند، نه مسیر تازه را. pathspec بده تا محدوده مشخص باشد؛ بعد وضعیت و آماده‌شده diff را بررسی کن.

git add -u stages changes and removals to tracked paths, not new paths. Supply a pathspec for a precise scope, then inspect status and the staged diff.

تمرین ۳٫۹Exercise 3.9میانیIntermediate۶ دقیقه6 min

git add -A را از ریشهٔ مخزن بدون مسیر اجرا کردی. محدوده‌اش چیست و چرا باید قبلش وضعیت را ببینی؟

You ran pathless git add -A from the repository root. What is its scope, and why check status first?

راهنماییHint

فایل تازه، تغییر و حذف را در نظر بگیر.

Think about new files, edits, and removals.

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

در Git امروزی، کل پوشه‌ کاری را برای افزودن فایل تازه، ناحیه‌ آماده‌سازی کردن تغییر و ثبت حذف هماهنگ می‌کند. فایل ناخواسته هم ممکن است وارد ناحیه‌ آماده‌سازی شود؛ پیش و بعد از آن git status --short و git diff --staged را بخوان.

In current Git, it updates the whole working tree by adding new files, staging modifications, and recording removals. Unwanted files may enter the index too; inspect short status and the staged diff before and after.

تمرین ۳٫۱۰Exercise 3.10میانیIntermediate۶ دقیقه6 min

فایل تازه‌ای را ناحیه‌ آماده‌سازی کردی. بعد git restore --staged new.txt زدی. چه رخ می‌دهد؟

You staged a new file, then ran git restore --staged new.txt. What happens?

راهنماییHint

در HEAD نسخه‌ای از این مسیر نیست.

There is no version of this path in HEAD.

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

مدخل تازه از ناحیه‌ آماده‌سازی برداشته می‌شود و فایل روی دیسک حذف نمی‌شود؛ دوباره ردیابی‌نشده است. وضعیت معمولاً ?? new.txt نشان می‌دهد. این با پاک کردن فایل فرق دارد.

The new index entry is removed but the disk file remains; it becomes untracked again. Status usually shows ?? new.txt. That is different from deleting the file.

تمرین ۳٫۱۱Exercise 3.11میانیIntermediate۶ دقیقه6 min

git restore --staged tracked.txt را روی فایلی که هم ناحیه‌ آماده‌سازی شده و هم روی دیسک تغییر دارد اجرا می‌کنی. کدام نسخه باقی می‌ماند؟

You run git restore --staged tracked.txt on a file changed both in the index and on disk. Which version remains?

راهنماییHint

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

The option targets the index, not the working tree.

بررسی جوابSolution

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

The index is restored from HEAD; the disk file stays untouched. The staged change is removed, and the disk/index difference appears as unstaged. Save the staged version first if you need it.

تمرین ۳٫۱۲Exercise 3.12میانیIntermediate۶ دقیقه6 min

مسیر قدیمی را حذف و فایل را با نام تازه ساخته‌ای، اما وضعیت حذف + ردیابی‌نشده نشان می‌دهد. آیا محتوا از دست رفته؟

You removed the old path and created a new filename, but status shows deleted plus untracked. Is the content lost?

راهنماییHint

Git مسیرها را جداگانه در ناحیه‌ آماده‌سازی می‌سنجد.

Git compares paths separately in the index.

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

نه لزوماً. فایل تازه روی دیسک هست و مسیر قدیمی هنوز در ناحیه‌ آماده‌سازی یا HEAD دیده می‌شود. هر دو مسیر را ناحیه‌ آماده‌سازی کن؛ Git ممکن است شباهت را تغییرنام نشان دهد، اما این تشخیص هنگام مقایسه است.

Not necessarily. The new disk file exists, while the old path remains in the index or HEAD. Stage both paths; Git may display a rename based on similarity, but that is inferred during comparison.

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

In the final exercises, a good answer is not just a command. You should be able to say which version lives in HEAD, the index, and the working tree afterward.

تمرین ۳٫۱۳Exercise 3.13پیشرفتهAdvanced۷ دقیقه7 min

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

One file is staged; you created a new file in the same directory. Both diff commands are empty. What do you inspect?

راهنماییHint

diff معمولی فایل ردیابی‌نشده را الزاماً نشان نمی‌دهد.

Ordinary diff does not necessarily show an untracked file.

پاسخ و دلیلSolution

اول git status --short --ignored را بخوان. فایل تازه ممکن است ردیابی‌نشده یا ignored باشد. git check-ignore -v path قاعده را مشخص می‌کند. خالی بودن diff فقط می‌گوید مقایسه‌های مربوط خروجی ندارند.

Start with git status --short --ignored. The new file may be untracked or ignored. git check-ignore -v path identifies a rule. Empty diffs only say their comparisons produced no output.

تمرین ۳٫۱۴Exercise 3.14پیشرفتهAdvanced۷ دقیقه7 min

دو تغییر بی‌ربط در یک فایل داری، اما Git آن‌ها را یک hunk نشان می‌دهد. چطور فقط یکی را ناحیه‌ آماده‌سازی می‌کنی؟

Two unrelated edits in one file appear as one hunk. How can you stage only one?

راهنماییHint

git add -p گزینهٔ خرد کردن hunk هم دارد.

git add -p can offer a way to split a hunk.

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

با git add -p FILE شروع کن؛ اگر s بتواند hunk را خرد کند، بخش مطلوب را ناحیه‌ آماده‌سازی کن. اگر نتوانست، e patch را ویرایش می‌کند ولی احتمال patch نامعتبر هست. بعد هر دو diff را بخوان؛ هدف اثبات انتخاب است، نه صرفاً اجرای فرمان.

Start with git add -p FILE; if s can split the hunk, stage the desired part. Otherwise e edits the patch but can produce an invalid one. Inspect both diffs: the goal is to prove the selection, not merely run a command.

تمرین ۳٫۱۵Exercise 3.15پیشرفتهAdvanced۸ دقیقه8 min

فایل ردیابی‌شده را پاک کرده‌ای، بعد git restore --staged file می‌زنی. آیا فایل حتماً روی دیسک برمی‌گردد؟

You deleted a tracked file, then run git restore --staged file. Does it necessarily return to disk?

راهنماییHint

این فرمان کدام مقصد را تغییر می‌دهد؟

Which destination does this command change?

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

نه. فقط ناحیه‌ آماده‌سازی از HEAD بازسازی می‌شود؛ فایل روی دیسک همچنان غایب است و حذف نسبت به ناحیه‌ آماده‌سازی آماده‌نشده می‌ماند. git restore -- file آن را از ناحیه‌ آماده‌سازی به دیسک می‌آورد، اما فقط اگر نسخهٔ حذف‌شده را دیگر لازم نداری.

No. Only the index is restored from HEAD; the disk file may remain absent, leaving an unstaged deletion. git restore -- file brings it from the index to disk, but only if you no longer need the removed version.

تمرین ۳٫۱۶Exercise 3.16پیشرفتهAdvanced۸ دقیقه8 min

git add . را زدی و فایل generated هم ناحیه‌ آماده‌سازی شد. چه چیزی را نباید فرض کنی و قبل از commit چه مدرکی می‌گیری؟

You ran git add . and generated output was staged too. What must you not assume, and what evidence do you collect before committing?

راهنماییHint

اول محتوای ناحیه‌ آماده‌سازی را ببین؛ ignore فایل ردیابی‌شده را حذف نمی‌کند.

Inspect the index first; ignore rules do not remove tracked entries.

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

فرض نکن .gitignore آن را خودکار بیرون می‌آورد یا commit فقط کد اصلی را دارد. git status --short و git diff --staged را بخوان؛ در مخزن آزمایشی با git restore --staged -- path بیرونش بیاور و قاعدهٔ ignore را برای آینده اضافه کن. رمز واقعی نیاز به اقدام جدا دارد.

Do not assume .gitignore removes it or that the commit contains only source. Inspect status and the staged diff; in a disposable repository, use git restore --staged -- path and add an ignore rule for the future. A real secret needs separate remediation.

تمرین ۳٫۱۷Exercise 3.17پیشرفتهAdvanced۹ دقیقه9 min

خروجی کوتاه D old.txt و ?? new.txt است. چه چیزی برای نتیجه‌گیری دربارهٔ تغییرنام کم داری؟

Short status shows D old.txt and ?? new.txt. What is missing before concluding this is a rename?

راهنماییHint

مسیر تازه هنوز ناحیه‌ آماده‌سازی نشده است.

The new path is not staged yet.

بررسی جوابSolution

تا مسیر تازه ردیابی‌نشده است، آماده‌شده diff ممکن است آن را با حذف قدیمی کنار هم نگذارد. هر دو مسیر را ناحیه‌ آماده‌سازی و git diff --staged --summary را بررسی کن؛ باز هم تغییرنام تشخیص شباهت است، نه عمل ذخیره‌شده در index.

While the new path is untracked, the staged diff may not pair it with the deletion. Stage both and inspect git diff --staged --summary; rename remains a similarity inference, not a recorded index operation.

تمرین ۳٫۱۸Exercise 3.18پیشرفتهAdvanced۱۰ دقیقه10 min

تیمی دو تغییر را جدا می‌خواهد: اصلاح باگ و به‌روزرسانی README. باگ باید در commit اول باشد؛ README هنوز ناحیه‌ آماده‌سازی نشود. ترتیب امن و شاهد قبولی را توضیح بده.

A team wants two changes separated: a bug fix and a README update. The fix belongs in the first commit; README must remain unstaged. Describe a safe sequence and proof.

راهنماییHint

اگر فایل‌ها جدا هستند، نیازی به انتخاب patch نیست.

If the edits are in separate files, patch selection is unnecessary.

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

فقط فایل باگ را ناحیه‌ آماده‌سازی کن، git diff --staged را بخوان و تأیید کن README در آن نیست؛ سپس commit کن. بعد وضعیت باید README را آماده‌نشده نشان دهد؛ آن را جدا ناحیه‌ آماده‌سازی و commit کن. اگر هر دو در یک فایل بودند، git add -p انتخاب دقیق‌تری می‌دهد.

Stage only the bug-fix file, inspect git diff --staged and confirm README is absent, then commit. Status should leave README unstaged; stage and commit it separately. If both edits were in one file, git add -p gives finer control.

پروژهٔ کوچک: دو commit از یک پوشهٔ شلوغMini project: two commits from one messy working tree

مخزن آزمایشی · حدود ۲۵ دقیقهDisposable repository · about 25 minutes

اصلاح باگ را از تغییرهای کناری جدا کن

Separate the bug fix from everything around it

این پروژه یک پوشهٔ عمداً شلوغ به تو می‌دهد. قرار نیست همه‌چیز را یکجا add کنی و خلاص. باید دو commit بسازی که هرکدام یک دلیل روشن داشته باشند؛ یعنی از ناحیهٔ آماده‌سازی واقعاً برای طراحی تاریخچه استفاده کنی.

A teammate hands you four unfinished changes: a bug fix, a documentation typo, a debug print, and generated output. Build two clear commits; lose nothing by accident, and keep generated output out of history.

ساخت وضعیت در مخزن جدا

Create the state in a separate repository

تمام مرحله‌ها را در همین پوشهٔ disposable انجام بده. اگر نام شاخهٔ پیش‌فرض یا شکل خروجی در سیستم تو فرق کرد، به وضعیت دو ناحیه تکیه کن، نه متن دقیق پیام.

Run every step in this disposable folder. If your default branch name or output formatting differs, reason from the two-area status, not exact wording.

bash · starter repository
mkdir two-commits-lab && cd two-commits-lab
git init -q
git config user.name 'Ada Example'
git config user.email 'ada@example.test'
printf 'function findUser(id) {\n  return users[id] || null;\n}\n' > handler.js
printf '# راهنما\nدرخواست کاربر را برسی کن.\n' > README.md
printf 'build-output\n' > generated.txt
printf 'handler.js\ngenerated.txt\n' > .gitignore
git add handler.js README.md .gitignore
git commit -m 'Add user lookup and usage note'

ماموریت

Mission

  1. چهار تغییر را بسازCreate four changes

    در شرط lookup باگ null را رفع کن، غلط «برسی» را «بررسی» کن و یک چاپ عیب‌یابی به handler اضافه کن. generated.txt را تغییر بده یا دوباره بساز.

    Fix null handling in the lookup, correct “برسی” to “بررسی,” and add a debug print to handler. Change or regenerate generated.txt.

  2. قبل از انتخاب، نقشه بگیرMap the state before selecting

    git status --short --ignored، git diff و git check-ignore -v generated.txt را اجرا کن. مشخص کن کدام تغییر دیده می‌شود و کدام قاعده خروجی را کنار گذاشته.

    Run git status --short --ignored, git diff, and git check-ignore -v generated.txt. Identify visible edits and the rule excluding generated output.

  3. commit اول را طراحی کنDesign the first commit

    فقط اصلاح باگ را ناحیه‌ آماده‌سازی کن؛ اگر عیب‌یابی در همان فایل است، از git add -p handler.js استفاده کن. معیار: آماده‌شده diff اصلاح باگ را دارد، ولی عیب‌یابی و README را ندارد.

    Stage only the bug fix; if debug is in the same file, use git add -p handler.js. Acceptance: staged diff contains the fix but neither debug nor README.

  4. commit دوم و باقی‌ماندهMake the second commit and inspect leftovers

    اصلاح را commit کن. بعد README را جدا ناحیه‌ آماده‌سازی و commit کن. در پایان عیب‌یابی باید در پوشه‌ کاری بماند و generated.txt نادیده گرفته شود؛ برای هر دو دلیل بیاور.

    Commit the fix, then stage and commit README separately. At the end, debug should remain in the working tree and generated.txt should be ignored; explain why.

مدرک قبولی: خروجی git status --short --ignored، هر دو diff قبل از commitهای مربوط، و git log --stat -2. دو commit باید هدف جدا داشته باشند، عیب‌یابی در آن‌ها نباشد و generated ثبت نشده باشد.

Acceptance evidence: git status --short --ignored, both diffs before their commits, and git log --stat -2. The commits need separate purposes; debug and generated output must not be recorded.

راهنمایی پلکانیProgressive hints

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

If everything was staged together, do not rush into a commit. Read both diffs and stage only the intended file or hunk in this disposable repository. If patch selection gets confusing, quit with q and inspect status again.

مسیر بررسی نمونهReference investigation
bash · proof checkpoints
git status --short --ignored
git diff -- handler.js README.md
git check-ignore -v generated.txt
# choose only the fix (or its hunk)
git add -p handler.js
git diff --staged
git diff
git commit -m 'Handle missing user in lookup'
# stage only README after verifying the first commit
git add README.md
git diff --staged
git commit -m 'Correct lookup instructions'
git status --short --ignored
git diff
git diff --staged
git log --stat -2

ترتیب انتخاب مهم‌تر از شکل دقیق شناسههاست. قبل از هر commit، git diff --staged باید فقط تغییر همان هدف را نشان بدهد. بعد از دومی، git diff چاپ عیب‌یابی را نشان می‌دهد؛ git check-ignore -v هم دلیل نادیده‌گرفتن generated را روشن می‌کند. اگر عیب‌یابی ناخواسته وارد commit شد، همین آزمایش موقت را از نو بساز؛ دستورهای بازنویسی تاریخچه موضوع این فصل نیستند.

The selection order matters more than exact IDs. Before each commit, git diff --staged should show only that purpose. After the second, git diff should still show debug, while git check-ignore -v explains why generated output is ignored. If debug accidentally entered a commit, rebuild this temporary lab; history-rewriting commands are outside this chapter.

نقشهٔ سریع سه ناحیهQuick map of the three areas

اگر می‌پرسی…If you are asking…این را اجرا کنRun thisاین را می‌سنجدIt compares
چه چیزی هنوز ناحیه‌ آماده‌سازی نشده؟What is not staged yet?git diffworking tree ↔ index
چه چیزی commit می‌شود؟What will be committed?git diff --stagedindex ↔ HEAD
چرا یک مسیر دو بار آمده؟Why is one path listed twice?git status --shortناحیه‌ آماده‌سازی و پوشه‌ کاری جداگانهindex and working tree separately
ناحیه‌ آماده‌سازی برای هر مسیر چه blobی دارد؟Which blob does the index have for each path?git ls-files --stageمدخل‌های واقعی ناحیه‌ آماده‌سازیActual index entries
فایل چرا دیده نمی‌شود؟Why is a file missing from status?git status --ignored
git check-ignore -v FILE
ردیابی‌نشده، ignored یا ردیابی‌شدهUntracked, ignored, or tracked
بعد از این فصل باید بتوانیBy the end of this chapter, you can
  • یک مسیر را هم‌زمان در دو وضعیت وضعیت توضیح بدهی.
  • Explain why one path can appear in two status states at once.
  • پیش از اجرا بگویی هر شکل git diff کدام دو نسخه را مقایسه می‌کند.
  • Predict which two versions each form of git diff compares.
  • با git add -p یک commit هدفمند بسازی و نتیجه را با diff ثابت کنی.
  • Use git add -p to shape a focused commit and prove it with diffs.
  • فرق restore کردن پوشه‌ کاری و ناحیه‌ آماده‌سازی را بدون حدس بگویی.
  • Distinguish restoring the working tree from restoring the index.

اگر فقط یک نقشه از این فصل همراهت بماند، همین باشد: Git برای یک فایل می‌تواند هم‌زمان سه نسخه داشته باشد. هر بار گیج شدی، اول مشخص کن کدام نسخه را داری می‌بینی.

You can now locate changes and know which version a commit records. The next step is natural: once snapshots are committed, how do we read history as an investigation instead of scrolling through messages at random?