Working Tree، Staging و Repository: سه لایهٔ روزمرهٔ Git
تفاوت Working tree، Index/Staging و تاریخچهٔ Repository؛ چرا git add وجود دارد و status چه میگوید — با Pro Git Reset Demystified و git-scm.
Founder & product engineer

بیشتر سردرگمیهای تازهواردها از یک جمله میآید: «تغییر دادم ولی Commit نشده.» در Git سه لایهٔ جدا وجود دارد. Pro Git در فصل Reset Demystified آنها را گاهی Three Trees مینامد: Working Directory (یا Working Tree)، Index (Staging Area)، و HEAD (آخرین Commit روی Branch جاری بهعنوان نمایندهٔ تاریخچهٔ ثبتشده). تا این سه تا را جدا نکنید، git status مثل پیام خطای تصادفی بهنظر میرسد.
زاویهٔ این مقاله مشکلمحور است: چرا Git عمداً Staging دارد؟ چه زمانی تغییراتتان فقط روی دیسکاند، چه زمانی برای Commit بعدی آمادهاند، و چه زمانی بخشی از تاریخچهاند. مقالهٔ ۰۷۰ این لایهها را نام برد؛ اینجا عمق عملی و اشتباههای پرهزینه است.

پاسخ کوتاه
Working tree جایی است که فایلها را ویرایش میکنید. Staging (Index) پیشنهاد شما برای محتویات Commit بعدی است — با git add پر میشود. Repository در معنای روزمرهٔ این بحث، تاریخچهٔ Commitهای ثبتشده است که با git commit از روی Index ساخته میشود و HEAD به نوک آن اشاره میکند. میتوانید فقط بخشی از تغییرات را Stage کنید؛ بقیه modified میمانند.
Staging کنترل است نه بوروکراسی: اجازه میدهد یک Commit تمیز بسازید وقتی روی دیسک هنوز کار ناتمام دارید.
لایه ۱: Working Tree
Sandbox قابل ویرایش. Clone یا checkout فایلها را اینجا باز میکند. وضعیت فایلها از دید Git:
- Tracked: Git از قبل آنها را میشناسد (در Commit قبلی یا Stage).
- Untracked: فایل جدید که هنوز add نشده.
- Modified: tracked که نسبت به Index یا HEAD فرق دارد.
- Ignored: مطابق .gitignore؛ معمولاً در status دیده نمیشود.
تغییر در Working tree بهتنهایی تاریخچه را عوض نمیکند. خاموش کردن لپتاپ تغییرات ذخیرهنشدهٔ ادیتور را از بین میبرد؛ تغییرات ذخیرهشده روی دیسک میمانند ولی هنوز Commit نیستند.
لایه ۲: Staging Area (Index)
Index یک فایل ساختاریافته در .git است که Pro Git آن را «پیشنهاد Commit بعدی» مینامد. git add محتوا را از Working tree به Index کپی مفهومی میکند. git commit از Index snapshot میسازد، نه لزوماً از تمام Working tree.
bash
git status git add src/auth.py git restore --staged src/auth.py # unstage git diff # working vs index git diff --cached # index vs HEAD
این جداسازی اجازه میدهد دو موضوع قاطیشده روی دیسک را در دو Commit جدا ثبت کنید (با add -p یا Stage انتخابی). میانبر git commit -a فقط فایلهای tracked را Stage میکند؛ untracked را نمیگیرد.
لایه ۳: تاریخچهٔ Repository (HEAD / Commits)
وقتی commit میزنید، Git از Index یک tree میسازد، شیء Commit با پیام و والد ایجاد میکند، و Branch جاری را جلو میبرد. از این لحظه تغییر بخشی از تاریخچه است (تا وقتی بازنویسی تاریخچه نکنید). HEAD معمولاً به Branch جاری اشاره میکند؛ detached HEAD حالت پیشرفتهتری است برای بازرسی.
Restore/checkout و reset هر کدام روی لایههای متفاوت اثر میگذارند؛ جزئیات مخرب را در ۲۱۳ همین سری میخوانید. اینجا فقط بدانید: «برگرداندن» مبهم است مگر بگویید کدام لایه.
جدول: هر فرمان کدام لایه را لمس میکند؟
| فرمان رایج | Working tree | Index | تاریخچه/HEAD |
|---|---|---|---|
| ویرایش در ادیتور | بله | خیر | خیر |
| git add | خواندن | بهروز | خیر |
| git commit | خیر* | مبنای snapshot | Commit جدید |
| git diff | در برابر Index | — | — |
| git diff --cached | — | در برابر HEAD | — |
| git restore --staged | خیر | برمیگرداند | خیر |
* مگر hook یا گزینهٔ خاص؛ مدل پایه بدون دست زدن به Working tree Commit میسازد.
چرا Staging وجود دارد؟ مسئلهای که حل میکند
بدون Staging، هر Commit مجبور بود «همهٔ تغییرات کثیف روی دیسک» را بگیرد یا ابزار بیرونی فایلها را جدا کند. با Index میتوانید:
- Fix فوری را Commit کنید و WIP را موقتاً کنار بگذارید (یا بعداً stash — ۲۱۲).
- Review شخصی قبل از ثبت: diff --cached همان چیزی است که وارد تاریخچه میشود.
- از Commit تصادفی Secret در فایل مجاور جلوگیری نسبی کنید (باز هم مسئولیت با شماست).
تیمهایی که همیشه commit -a میزنند، عملاً Staging را دور میزنند؛ برای پروژههای کوچک ممکن است قابل قبول باشد، ولی کنترل ریز را از دست میدهید.
خواندن git status مثل نقشه
خروجی status معمولاً سه ناحیه دارد: changes to be committed (در Index)، changes not staged for commit (Working tree کثیف نسبت به Index)، و untracked files. اگر چیزی «هم Stage شده هم دوباره modify شده»، یعنی بعد از add دوباره ویرایش کردهاید — برای Commit نهایی باید دوباره add کنید.
bash
git status -sb git add -p # stage تکهتکه
اشتباههای رایج
- فرض اینکه ذخیره در ادیتور = Commit.
- add کردن کل پروژه با git add . بدون نگاه به untracked (خطر Secret و node_modules).
- ترس از Staging و استفادهٔ دائم از commit -a روی تغییرهای درهم.
- گیج شدن بین git diff و git diff --cached.
- پاک کردن فایل از Working tree و فکر کردن که از Index/تاریخچه هم رفته.
مسیر تمرین ۱۵ دقیقهای
- یک مخزن آزمایشی init کنید و یک فایل Commit کنید.
- دو فایل را عوض کنید؛ فقط یکی را add کنید؛ status را بخوانید.
- diff و diff --cached را مقایسه کنید.
- Commit بزنید؛ ببینید فایل دوم هنوز modified است.
- فایل دوم را Stage و Commit کنید.
سناریوی واقعی: دو موضوع روی یک دیسک
در حال Fix کردن باگ ورود هستید که ناگهان باید یک typo در README را هم برای Release امروز Commit کنید. بدون Staging مجبورید یا همه را با هم Commit کنید یا تغییر باگ را دور بریزید/Stash کنید. با Index: فقط README را add و Commit میکنید؛ Fix ورود modified میماند برای Commit بعدی. این همان مسئلهٔ روزمرهای است که Staging حل میکند.
bash
git add README.md git commit -m "Fix typo in install section of README" git status # auth fix still modified
سه diff که باید حفظ باشید
- git diff: Working tree در برابر Index — چه چیزی هنوز Stage نشده.
- git diff --cached / --staged: Index در برابر HEAD — چه چیزی وارد Commit بعدی میشود.
- git diff HEAD: Working tree در برابر آخرین Commit — تصویر کلی کثیفی نسبت به تاریخچه.
بسیاری از باگهای «فکر کردم Commit شد» از نخواندن همین سه نما میآید. قبل از Push، --cached را یکبار بخوانید انگار Reviewer هستید.
پیوند با Reset و Restore بدون ورود به خطر
وقتی میگویید «برش گردان»، باید بگویید کدام لایه: فقط Unstage؟ فقط فایل روی دیسک؟ یا حرکت Branch در تاریخچه؟ Pro Git Reset Demystified دقیقاً برای همین سه لایه نوشته شده است. در این سری، جزئیات پرریسک در ۲۱۳ است؛ اینجا فقط قرارداد زبانی را ثابت کنید تا فرمان اشتباه نزنید.
Partial stage با add -p
وقتی یک فایل دو موضوع قاطی دارد، git add -p تکهها را جدا Stage میکند. این مهارت مستقیماً به Commit اتمی ۲۰۴ وصل است. اگر hunkها بد شکسته شدند، ادیتور را تمیزتر کنید یا تغییر را دو نوبت جدا انجام دهید.
bash
git add -p src/service.py git diff --cached git commit -m "One concern only"
فایل Untracked و دام add .
git add . همهٔ untracked غیرignore را Stage میکند: .env، dump دیتابیس، کلید. عادت امنتر: add مسیرهای مشخص، یا اول status، یا templateهای gitignore زبان/فریمورک. Staging قدرت است؛ قدرت بدون نگاه به status خطر است.
وضعیتهای ترکیبی که تازهواردها را میترساند
فایلی که هم staged است هم بعداً دوباره modify شده، در status دو بار ظاهر میشود: نسخهٔ Stage برای Commit بعدی و نسخهٔ کثیف روی دیسک. اگر الآن commit بزنید، فقط نسخهٔ Stage میرود؛ تغییرات بعدی روی دیسک میمانند. این رفتار درست است، نه باگ. دوباره add کنید اگر میخواهید آخرین ویرایش هم داخل همان Commit باشد.
حالت دیگر: rename که Git گاهی بهصورت delete+add تشخیص میدهد. برای تاریخچه مهم است ولی برای مدل سه لایه همان قواعد Stage اعمال میشود.
تمرین تشخیص لایه با سؤال
- اگر لپتاپ خاموش شود و فایل ذخیره شده باشد، کدام لایه مانده؟ Working tree.
- اگر add کرده باشید ولی commit نه؟ Index هم همان snapshot را دارد.
- اگر commit کرده ولی push نه؟ تاریخچهٔ محلی؛ Remote نه.
- اگر push کرده باشید؟ Remote هم همان Commit را دارد (با فرض موفق بودن).
هر بار که کسی میگوید «کدم پرید»، با این چهار سؤال لایه را پیدا کنید؛ بعد فرمان مناسب معنی پیدا میکند.
سوالات متداول
آیا میتوان Staging را نادیده گرفت؟
از نظر فنی با -a یا ابزارهای GUI بله؛ از نظر مهارتی بهتر است مدل را بفهمید بعد تصمیم بگیرید کجا میانبر بزنید.
Index همان stash است؟
خیر. Stash انبار موقت جداگانه است؛ Index صف Commit بعدی.
چرا بعد از merge conflict هم پای Index وسط است؟
Conflict یعنی Git نتوانسته Index را کامل از ادغام پر کند؛ بعد از حل، add فایلها Index را کامل میکند و commit ادغام را میبندد (۲۰۷).
خلاصه
Working tree محل ویرایش، Staging محل انتخاب محتوای Commit بعدی، و تاریخچهٔ Repository محل ثبت ماندگار است. git add و دو نوع diff ابزار خواندن این لایهها هستند. وقتی status را لایه لایه بخوانید، Git قابل پیشبینی میشود.
قدم بعد: Commit را بهعنوان شیء تاریخچه بشناسید (۲۰۴)، بعد Branch بهعنوان اشارهگر متحرک (۲۰۵).
منابع و مراجع
- Pro Git — Git Tools Reset Demystified — https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
- Pro Git — Recording Changes to the Repository — https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository
- git-status documentation — https://git-scm.com/docs/git-status
- git-add documentation — https://git-scm.com/docs/git-add
- git-commit documentation — https://git-scm.com/docs/git-commit
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




