توی این درس یاد میگیری چطور جلوی ورود فایلهای اضافی و حساس به مخزن را بگیری: فایل .gitignore و الگوهایش (*.log، node_modules/، /build، !استثنا)، چرا node_modules و فایلهای .env هرگز نباید commit شوند، چطور با git check-ignore -v بفهمی کدام قاعده یک فایل را نادیده گرفته، چطور فایلی را که قبلاً commit شده با git rm --cached از دنبالشدن دربیاوری، و ignore محلی و سراسری. تمرین: یک .gitignore کامل برای یک پروژهی Node بنویس.
مسئله: چیزهایی که نباید وارد تاریخچه شوند
Section titled “مسئله: چیزهایی که نباید وارد تاریخچه شوند”وقتی git add . میزنی، Git هر چه در پوشه هست را میبیند: پوشهی node_modules با دهها هزار فایل، خروجی build، فایلهای لاگ، فایلهای موقت ویرایشگر (.DS_Store، .idea/)، و بدتر از همه فایلهای رمز (.env). اینها سه دردسر دارند:
- حجم و شلوغی: مخزنی که صدها مگابایت چیزِ قابلبازسازی دارد، کند و پر از diff بیمعنی میشود.
- تداخل: فایلهای ماشینمحور (مثل مسیرهای شخصی در تنظیمات ویرایشگر) برای هر همکار فرق دارند و دائماً conflict میسازند.
- امنیت: هر چه commit شود برای همیشه در تاریخچه میماند. اگر رمز دیتابیس در یک commit رفت، پاککردن فایل در commit بعدی کافی نیست.
تشبیه: فهرست «در چمدان نگذار»
Section titled “تشبیه: فهرست «در چمدان نگذار»”قبل از سفر یک فهرست ممنوعهها داری (مایعات زیاد، چاقو…) که اسکنر فرودگاه رد میکند. .gitignore همان فهرست است: به Git میگوید «اینها را حتی اگر در پوشه هستند، نبین و addشان نکن». فهرست را در خود مخزن نگه میداری و commit میکنی، تا همهی همتیمیها همان قوانین را داشته باشند.
مثالهای عملی
Section titled “مثالهای عملی”یک «پروژهی Node» ساختگی میسازم که همهی انواع فایل را دارد: کد، وابستگیها، خروجی build، لاگ و رمز:
mkdir -p ~/gitlab/webapp && cd ~/gitlab/webapp && git init -qmkdir -p src node_modules/express dist logsecho "console.log('app')" > src/app.jsecho '{"name":"webapp"}' > package.jsonecho "module.exports = {}" > node_modules/express/index.jsecho "bundle" > dist/app.min.jsecho "request failed" > logs/error.logecho "DB_PASSWORD=super-secret-123" > .envecho "mac junk" > .DS_Storegit status -s?? .DS_Store?? .env?? dist/?? logs/?? node_modules/?? package.json?? src/مثال ۱: بدون .gitignore، همهچیز در خطر است
Section titled “مثال ۱: بدون .gitignore، همهچیز در خطر است”وضعیت بالا را ببین: .env، node_modules/، dist/، logs/ و .DS_Store همه ?? (untracked) هستند و با اولین git add . وارد میشوند. حالا .gitignore را مینویسم:
cd ~/gitlab/webappcat > .gitignore <<'EOF'# وابستگیهاnode_modules/
# خروجی builddist/
# لاگها*.log
# رمزها و تنظیمات محلی.env
# فایلهای سیستمعامل.DS_StoreEOFecho "--- وضعیت بعد از .gitignore:"git status -secho "--- فایلهای نادیدهگرفتهشده (--ignored):"git status -s --ignored--- وضعیت بعد از .gitignore:?? .gitignore?? package.json?? src/--- فایلهای نادیدهگرفتهشده (--ignored):?? .gitignore?? package.json?? src/!! .DS_Store!! .env!! dist/!! logs/!! node_modules/حالا فقط .gitignore، package.json و src/ دیده میشوند. git status -s --ignored فهرست «نادیدهها» را با !! نشان میدهد؛ برای اطمینان از اینکه قاعده کار میکند عالی است. (خطی که با # شروع شود توضیح است و خط خالی نادیده گرفته میشود.) .gitignore را هم commit میکنم تا همه آن را داشته باشند:
cd ~/gitlab/webappgit add .gitignore package.json srcgit commit -qm "Add app source and .gitignore"git status -s --ignoredgit log --stat --format='%h %s'!! .DS_Store!! .env!! dist/!! logs/!! node_modules/fa0678e Add app source and .gitignore
.gitignore | 14 ++++++++++++++ package.json | 1 + src/app.js | 1 + 3 files changed, 16 insertions(+)مثال ۲: الگوها
Section titled “مثال ۲: الگوها”قاعدهها را از ساده به پیچیده ببین. هر خط یک الگو (pattern) است:
| الگو | معنی | نمونههایی که نادیده میگیرد |
|---|---|---|
*.log |
هر فایل با پسوند .log در هر عمقی |
error.log، logs/a/b.log |
node_modules/ |
پوشهای با این نام (/ آخر = فقط پوشه) |
node_modules/…، packages/x/node_modules/… |
/build |
فقط build در ریشهی مخزن (/ اول = لنگر) |
build/؛ ولی src/build/ نه |
build |
هر فایل یا پوشهای با این نام در هر عمقی | build، src/build |
doc/*.pdf |
.pdf های مستقیم داخل doc |
doc/a.pdf؛ ولی doc/x/b.pdf نه |
doc/**/*.pdf |
.pdf در هر عمقِ زیر doc |
doc/a.pdf، doc/x/y/b.pdf |
temp? |
? = دقیقاً یک نویسه |
temp1، tempX |
*.[oa] |
یکی از نویسههای داخل کروشه | x.o، x.a |
!خاص.log |
استثنا: این را نادیده نگیر | |
\#file |
\ نویسهی ویژه را عادی میکند |
فایلی به نام #file |
برای دیدن اینکه کدام قاعده کدام فایل را گرفته، git check-ignore -v (v = verbose) را بزن. خروجی: فایل-قاعده:شمارهی-خط:الگو مسیر:
cd ~/gitlab/webappgit check-ignore -v node_modules/express/index.js logs/error.log .env dist/app.min.js .DS_Storeecho "--- فایلی که نادیده گرفته نمیشود (کد 1 یعنی هیچ قاعدهای نگرفتش):"git check-ignore -v src/app.js; echo "exit code: $?".gitignore:2:node_modules/ node_modules/express/index.js.gitignore:8:*.log logs/error.log.gitignore:11:.env .env.gitignore:5:dist/ dist/app.min.js.gitignore:14:.DS_Store .DS_Store--- فایلی که نادیده گرفته نمیشود (کد 1 یعنی هیچ قاعدهای نگرفتش):exit code: 1سه جزء دارد: فایل قاعده (.gitignore)، شمارهی خط (:2:) و الگوی منطبق، و آخر مسیر. هر وقت یک فایل «ناگهان» نادیده گرفته میشود یا نمیشود، check-ignore -v اولین دستوری است که باید بزنی.
مثال ۳: استثنا با ! و دام «پوشهی ignoreشده»
Section titled “مثال ۳: استثنا با ! و دام «پوشهی ignoreشده»”گاهی میخواهی یک پوشه را نادیده بگیری ولی یک فایل خاصش را نگه داری. با ! استثنا میدهی. ولی یک دام معروف هست. اول شکل غلط:
mkdir -p ~/gitlab/trap && cd ~/gitlab/trap && git init -qmkdir build && echo a > build/out.js && echo "keep me" > build/README.mdprintf 'build/\n!build/README.md\n' > .gitignoreecho "--- شکل غلط (build/ و بعد !build/README.md):"git status -s -uallgit check-ignore -v build/README.md--- شکل غلط (build/ و بعد !build/README.md):?? .gitignore.gitignore:1:build/ build/README.mdاستثنا کار نکرد: README.md هنوز نادیده گرفته میشود. دلیل: وقتی خود پوشه ignore باشد، Git اصلاً داخلش را نمیخواند، پس به استثنا نمیرسد. شکل درست این است که محتوای پوشه را ignore کنی، نه خود پوشه را:
cd ~/gitlab/trapprintf 'build/*\n!build/README.md\n' > .gitignoreecho "--- شکل درست (build/* و بعد !build/README.md):"git status -s -uall--- شکل درست (build/* و بعد !build/README.md):?? .gitignore?? build/README.mdحالا build/README.md دیده میشود و build/out.js هنوز نادیده است. قاعده: نمیشود فایلی را از پوشهی ignoreشده بازگرداند؛ بهجای پوشه، محتوایش را با * ignore کن.
مثال ۴: فایلی که از قبل commit شده بود
Section titled “مثال ۴: فایلی که از قبل commit شده بود”.gitignore فقط روی فایلهای untracked اثر دارد. اگر فایلی را قبلاً commit کردهای، بعداً هم که در .gitignore بنویسی، Git هنوز دنبالش میکند:
mkdir -p ~/gitlab/late && cd ~/gitlab/late && git init -qecho "API_KEY=abc123" > config.localecho "code" > app.jsgit add . && git commit -qm "Initial commit (oops, config.local is in)"echo "config.local" > .gitignoreecho "API_KEY=changed" > config.localecho "--- config.local را به .gitignore اضافه کردم، ولی:"git status -secho "--- هنوز دنبال میشود؟"git ls-files--- config.local را به .gitignore اضافه کردم، ولی: M config.local?? .gitignore--- هنوز دنبال میشود؟app.jsconfig.localconfig.local با اینکه در .gitignore است، هنوز tracked است ( M یعنی ویرایششده و Git تغییرش را میبیند). راهحل: git rm --cached فایل را فقط از ردیابی Git درمیآورد و روی دیسک نگه میدارد:
cd ~/gitlab/lategit rm --cached config.localgit add .gitignoregit commit -qm "Stop tracking config.local"echo "--- بعد:"git status -sgit ls-filesecho "--- فایل روی دیسک هست؟"cat config.localrm 'config.local'--- بعد:.gitignoreapp.js--- فایل روی دیسک هست؟API_KEY=changedrm --cached فقط ردیابی را برمیدارد (بدون --cached، فایل را از دیسک هم پاک میکرد). ولی هشدار بزرگ: نسخهی قدیمی فایل (با API_KEY=abc123) هنوز در تاریخچهی commit اول هست. اگر آن یک رمز واقعی بود، rm --cached کافی نیست: باید رمز را عوض کنی (مثال ۸).
مثال ۵: ignore محلی و سراسری
Section titled “مثال ۵: ignore محلی و سراسری”سه جا برای قاعدهها هست. هر کدام برای یک هدف:
cd ~/gitlab/webappecho "scratch-notes.txt" >> .git/info/excludemkdir -p ~/.config/gitprintf '.DS_Store\n*.swp\n.idea/\n' > ~/.config/git/ignoreecho "یادداشت شخصی" > scratch-notes.txtecho "tmp" > .file.swpecho "--- فایلهای جدید ← نادیدهاند؟ و توسط کدام فایل قاعده؟"git check-ignore -v scratch-notes.txt .file.swp .DS_Storeecho "--- وضعیت (چیزی نمیماند):"git status -s--- فایلهای جدید ← نادیدهاند؟ و توسط کدام فایل قاعده؟.git/info/exclude:7:scratch-notes.txt scratch-notes.txt/home/ali/.config/git/ignore:2:*.swp .file.swp.gitignore:14:.DS_Store .DS_Store--- وضعیت (چیزی نمیماند):.gitignore: قاعدههای پروژه (node_modules/،dist/،.env): همهی تیم لازم دارند، پس commit میشود..git/info/exclude: قاعدههای شخصی برای همین مخزن (مثلاً یادداشتهای خودت)؛ commit نمیشود و مثل.gitignoreکار میکند.- فایل سراسری (
~/.config/git/ignore، یا هر مسیری که باgit config --global core.excludesFile مسیربدهی): فایلهای ابزار و سیستمعامل تو (.DS_Storeمک،*.swpویم،.idea/). بهجای اینکه هر پروژه اینها را بنویسد، یک بار برای همیشه.
قاعدهی خوب: چیزی که به پروژه مربوط است (dist/) در .gitignore؛ چیزی که به ماشین یا ابزار تو مربوط است (.DS_Store) در فایل سراسری.
مثال ۶: پوشهی خالی و .gitkeep
Section titled “مثال ۶: پوشهی خالی و .gitkeep”Git فقط فایل نگه میدارد، نه پوشه. پوشهی خالی اصلاً وارد مخزن نمیشود:
mkdir -p ~/gitlab/empty && cd ~/gitlab/empty && git init -qmkdir uploadsecho "--- پوشهی خالی uploads:"git status -s; echo "(خالی: Git آن را نمیبیند)"touch uploads/.gitkeepecho "--- با یک فایل .gitkeep داخلش:"git status -s -uall--- پوشهی خالی uploads:(خالی: Git آن را نمیبیند)--- با یک فایل .gitkeep داخلش:?? uploads/.gitkeepقرارداد این است که یک فایل خالی با اسم .gitkeep داخل پوشه میگذارند (اسم خاصی ندارد؛ هر فایلی کار میکند). حالت رایج دیگر: پوشهای که محتوایش ignore است ولی خودش باید در مخزن باشد (uploads/* و !uploads/.gitkeep، همان الگوی مثال ۳).
مثال ۷: یک .gitignore کامل برای پروژهی Node
Section titled “مثال ۷: یک .gitignore کامل برای پروژهی Node”حالا تمرین اصلی: فایلی برای یک پروژهی Node واقعی. هر بخش دلیلش را دارد:
mkdir -p ~/gitlab/nodeapp && cd ~/gitlab/nodeapp && git init -qcat > .gitignore <<'EOF'# وابستگیها (با npm install بازسازی میشوند)node_modules/
# خروجی build و کشdist/build/.cache/coverage/
# لاگها*.lognpm-debug.log*yarn-error.log*
# رمزها و تنظیمات محلی (ولی نمونهاش را نگه دار).env.env.*!.env.example
# ابزارهای ویرایشگر و سیستمعامل (بهتر است در ignore سراسری باشند).idea/.vscode/.DS_StoreThumbs.dbEOFmkdir -p src node_modules/x dist coverage logs .ideaecho a > src/index.js; echo '{}' > package.json; echo '{}' > package-lock.jsonecho a > node_modules/x/i.js; echo a > dist/b.js; echo a > coverage/c.htmlecho "a" > logs/app.log; echo "npm-debug.log" > npm-debug.log.1echo "DB_PASSWORD=x" > .env; echo "DB_PASSWORD=" > .env.example; echo "T=1" > .env.localecho a > .idea/w.xml; echo a > .DS_Storeecho "--- فایلهایی که Git میبیند:"git status -s -uallecho "--- و آنچه نادیده میگیرد:"git status -s --ignored | grep '^!!'--- فایلهایی که Git میبیند:?? .env.example?? .gitignore?? package-lock.json?? package.json?? src/index.js--- و آنچه نادیده میگیرد:!! .DS_Store!! .env!! .env.local!! .idea/!! coverage/!! dist/!! logs/!! node_modules/!! npm-debug.log.1دقت کن .env.example دیده میشود (استثنا با !) و .env و .env.local نادیدهاند. این الگوی معروفی است: یک فایل نمونه که کلیدها را بدون مقدار نشان میدهد در مخزن میماند تا همکارت بداند چه چیزهایی را باید تنظیم کند، و مقدارهای واقعی هیچوقت وارد نمیشوند. دو نکتهی دیگر: package-lock.json را commit کن (نسخهی دقیق وابستگیها را قفل میکند)؛ و node_modules/ را هرگز (با npm install بازسازی میشود). برای زبانهای دیگر، GitHub یک مخزن رسمی از قالبهای آماده دارد (github/gitignore) که برای شروع خوب است.
مثال ۸: رمز لو رفت، حالا چه؟
Section titled “مثال ۸: رمز لو رفت، حالا چه؟”اگر رمز یا کلیدی را commit و push کردی، اول باید فرض کنی لو رفته است: همان لحظه رمز/کلید را در سرویس مربوطه عوض (rotate) یا باطل کن. بعد، برای اینکه از تاریخچهی مخزن هم برود، باید تاریخچه را بازنویسی کنی، که یک عملیات سنگین و پرخطر است (کار همهی همکارها را تغییر میدهد). ابزارهای رسمی آن git filter-repo و BFG Repo-Cleaner هستند. اینها را من اجرا نکردهام (نصب خارجی دارند و روی تاریخچهی مشترک خطرناکاند)؛ فقط بدان که راه امن همان اول عوضکردن رمز است، نه پنهانکردنش:
# ۱) همین الآن رمز را در سرویس مربوطه عوض کن (rotate)# ۲) بعد، فایل را از تمام commit ها حذف کن (ابزار git-filter-repo باید نصب باشد):git filter-repo --invert-paths --path .env# ۳) و تاریخچهی بازنویسیشده را به سرور بفرست (همهی همکاران باید دوباره clone کنند):git push --force-with-leaseپشت پرده: Git قاعدهها را چطور میخواند؟
Section titled “پشت پرده: Git قاعدهها را چطور میخواند؟”Git قاعدهها را از چند جا میخواند و برای هر فایل آخرین الگوی منطبق برنده است. ترتیب اولویت (از بالا به پایین ضعیفتر میشود): ۱) قاعدههای خط فرمان، ۲) .gitignore در همان پوشهی فایل (و پوشههای بالاتر؛ نزدیکتر برنده است)، ۳) .git/info/exclude، ۴) فایل سراسری (core.excludesFile). هر فایل میتواند قاعدهی خودش را بر قاعدهی پوشهی بالاتر ببرد:
mkdir -p ~/gitlab/nested && cd ~/gitlab/nested && git init -qmkdir -p docs/draftsprintf '*.tmp\n' > .gitignoreprintf '!keep.tmp\n' > docs/.gitignoretouch a.tmp keep.tmp docs/a.tmp docs/keep.tmpecho "--- قاعدهی هر فایل (آخرین منطبق برنده است):"git check-ignore -v a.tmp keep.tmp docs/a.tmp docs/keep.tmpecho "--- فایلهایی که نادیده نیستند:"git status -s -uall | grep -v gitignore--- قاعدهی هر فایل (آخرین منطبق برنده است):.gitignore:1:*.tmp a.tmp.gitignore:1:*.tmp keep.tmp.gitignore:1:*.tmp docs/a.tmpdocs/.gitignore:1:!keep.tmp docs/keep.tmp--- فایلهایی که نادیده نیستند:?? docs/keep.tmpdocs/.gitignore فقط برای فایلهای داخل docs/ قاعدهی نزدیکتر دارد: docs/keep.tmp استثنا میشود ولی keep.tmp در ریشه نه. دو نکتهی دیگر: (۱) قاعدهها فقط روی فایلهای untracked اثر دارند (مثال ۴)، و (۲) git add -f فایل میتواند عمداً یک فایل ignoreشده را اضافه کند (کمپیش میآید).
جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | کار |
|---|---|
git status --ignored / -s --ignored |
فایلهای نادیدهگرفتهشده را هم نشان بده (!!) |
git check-ignore -v مسیر… |
کدام قاعده این مسیر را نادیده میگیرد؟ |
git rm --cached فایل |
فایل را از ردیابی دربیاور، روی دیسک بماند |
git rm -r --cached پوشه |
همان برای پوشه |
git ls-files |
فایلهایی که Git دنبال میکند |
git add -f فایل |
افزودن اجباری فایل ignoreشده |
git clean -ndX |
فهرست فایلهای ignoreشدهای که clean پاک میکرد (-X = فقط ignoreشدهها) |
git config --global core.excludesFile مسیر |
فایل ignore سراسری |
| جای قاعده | commit میشود؟ | برای |
|---|---|---|
.gitignore |
بله | قاعدههای پروژه (مشترک) |
.git/info/exclude |
نه | قاعدهی شخصی همین مخزن |
~/.config/git/ignore |
نه | فایلهای ابزار و سیستمعامل خودت |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) نوشتن در .gitignore بعد از commit شدن فایل
Section titled “۱) نوشتن در .gitignore بعد از commit شدن فایل”مثال ۴: اثر ندارد. راهحل: git rm --cached؛ و اگر رمز بود، عوضکردنش.
۲) فراموشکردن commit کردن .gitignore
Section titled “۲) فراموشکردن commit کردن .gitignore”اگر .gitignore را commit نکنی، فقط روی کامپیوتر خودت کار میکند و همکارت دوباره node_modules را add میکند. راهحل: .gitignore را زود (قبل از بقیهی فایلها) commit کن.
۳) الگوی خیلی گسترده
Section titled “۳) الگوی خیلی گسترده”mkdir -p ~/gitlab/broad && cd ~/gitlab/broad && git init -qprintf 'build\n*.js\n' > .gitignoremkdir -p src/build && echo a > src/build/x.txt && echo a > app.js && echo a > README.mdecho "--- چه چیزی دیده میشود؟"git status -s -uall--- چه چیزی دیده میشود؟?? .gitignore?? README.md*.js همهی فایلهای جاوااسکریپت را از جمله app.js (کد اصلی!) نادیده گرفت، و build بدون / اول، پوشهی src/build را هم گرفت. راهحل: الگوها را دقیق بنویس (/dist/ بهجای dist، *.min.js بهجای *.js) و بعد از هر تغییر git status و check-ignore -v را بزن.
۴) توضیح در انتهای همان خط
Section titled “۴) توضیح در انتهای همان خط”mkdir -p ~/gitlab/comment && cd ~/gitlab/comment && git init -qprintf '*.log # فایلهای لاگ\n' > .gitignoreecho x > a.logecho "--- a.log نادیده گرفته میشود؟"git status -sgit check-ignore -v a.log; echo "exit code: $?"--- a.log نادیده گرفته میشود؟?? .gitignore?? a.logexit code: 1# فقط وقتی اول خط باشد توضیح است. اگر بعد از الگو بیاید، همهی آن خط (با فاصلهها و توضیح) جزو الگو حساب میشود و دیگر با هیچ فایلی نمیخواند؛ پس a.log اصلاً ignore نشد (و check-ignore کد خروج ۱ داد). راهحل: توضیح را در خط جدا بنویس.
۵) فکر اینکه .gitignore امنیت است
Section titled “۵) فکر اینکه .gitignore امنیت است”.gitignore فقط ورود تصادفی را میگیرد؛ حفاظت واقعی از رمز نیست (git add -f یا یک cp اشتباه آن را دور میزند). رمزها را باید از کد جدا نگه داری (متغیر محیطی یا یک مدیر رمز) و ابزارهای اسکن رمز (مثل pre-commit hook) در تیم بهکار ببری.
فایلهای لاگ (*.log) را نادیده بگیر و با git check-ignore -v ثابت کن کدام قاعده یک فایل app.log را گرفته.
دیدن جواب
mkdir -p ~/gitlab/ex1 && cd ~/gitlab/ex1 && git init -qecho "*.log" > .gitignoreecho x > app.log && echo y > main.pygit status -sgit check-ignore -v app.log?? .gitignore?? main.py.gitignore:1:*.log app.logتمرین اصلی: یک .gitignore کامل برای یک پروژهی Node بنویس (وابستگیها، خروجی build، لاگها، .env با استثنای .env.example، فایلهای ویرایشگر). یک پروژهی ساختگی با همهی این فایلها بساز، git add -A و commit بزن و با git ls-files ثابت کن فقط فایلهای «واقعی» وارد شدند.
دیدن جواب
mkdir -p ~/gitlab/ex2 && cd ~/gitlab/ex2 && git init -qcat > .gitignore <<'EOF'node_modules/dist/coverage/*.log.env.env.*!.env.example.idea/.DS_StoreEOFmkdir -p src node_modules/a dist coverage .ideaecho a > src/main.js; echo '{}' > package.json; echo '{}' > package-lock.jsonecho a > node_modules/a/i.js; echo a > dist/o.js; echo a > coverage/c.html; echo a > .idea/wecho x > debug.log; echo S=1 > .env; echo S= > .env.example; echo a > .DS_Storegit add -A && git commit -qm "Add project"echo "--- فایلهای واردشده به مخزن:"git ls-files--- فایلهای واردشده به مخزن:.env.example.gitignorepackage-lock.jsonpackage.jsonsrc/main.jsدر پروژهای settings.local از اول commit شده و میخواهی دیگر دنبال نشود، بدون پاکشدن از کامپیوتر خودت. بعد ثابت کن نسخهی قدیمی همچنان در تاریخچه هست (و توضیح بده چرا این برای رمز خطرناک است).
دیدن جواب
mkdir -p ~/gitlab/ex3 && cd ~/gitlab/ex3 && git init -qecho "TOKEN=old-secret" > settings.local && echo code > app.pygit add . && git commit -qm "Initial"echo "settings.local" > .gitignoregit rm -q --cached settings.localgit add .gitignore && git commit -qm "Stop tracking settings.local"echo "--- فایل هنوز روی دیسک است:"; cat settings.localecho "--- ولی دیگر tracked نیست:"; git ls-filesecho "--- و نسخهی قدیمی در commit اول هنوز هست:"git show HEAD~1:settings.local--- فایل هنوز روی دیسک است:TOKEN=old-secret--- ولی دیگر tracked نیست:.gitignoreapp.py--- و نسخهی قدیمی در commit اول هنوز هست:TOKEN=old-secretآزمونک
Section titled “آزمونک”فایل .env را بعد از commit شدن به .gitignore اضافه کردی. چه میشود؟
.gitignore فقط روی فایلهای untracked اثر دارد. برای فایل tracked باید با git rm --cached از ردیابی درش بیاوری؛ و اگر رمز بود، تاریخچه هنوز آن را دارد و باید رمز را عوض کنی.
الگوی «node_modules/» چه چیزی را نادیده میگیرد؟
برای لنگرکردن به ریشه از /node_modules/ استفاده میشود.
کدام دستور نشان میدهد چرا یک فایل ignore شده است؟
-v فایل قاعده، شمارهی خط و الگوی منطبق را نشان میدهد.
چرا «build/» و بعد «!build/README.md» کار نمیکند؟
نمیشود فایلی را از پوشهی ignoreشده بازگرداند.
git rm --cached فایل چه میکند؟
بعد از آن commit بزن؛ و اگر رمز بود، رمز را عوض کن.
چرا .DS_Store یا .idea/ را بهتر است در ignore سراسری بگذاری؟
قاعدهی پروژه در .gitignore، قاعدهی ماشین تو در ~/.config/git/ignore.
جمعبندی
Section titled “جمعبندی”.gitignoreبه Git میگوید کدام فایلهای untracked را نبیند:node_modules/،dist/،*.log،.env. آن را commit کن و زود بنویس.- الگوها:
*.log،dir/(فقط پوشه)،/build(فقط ریشه)،doc/**/*.pdf،!استثنا.#توضیح است. git check-ignore -v مسیرکدام قاعده را نشان میدهد؛git status -s --ignoredفهرست نادیدهها (!!).- پوشهی ignoreشده را نمیشود با
!باز کرد؛ ازbuild/*و!build/README.mdاستفاده کن. - فایل قبلاً commit شده را با
git rm --cached فایل(و commit) از ردیابی دربیاور. ولی نسخهی قدیمی در تاریخچه میماند؛ برای رمز، اول عوضکردن رمز. - سه جا:
.gitignore(مشترک)،.git/info/exclude(شخصی)،~/.config/git/ignore(ابزار و سیستمعامل تو). - Git پوشهی خالی نگه نمیدارد:
.gitkeep..env.exampleرا نگه دار و.envرا ignore کن.
| دستور | کاری که میکند |
|---|---|
echo "node_modules/" >> .gitignore | یک الگو اضافه کن |
git check-ignore -v مسیر | کدام قاعده این را نادیده میگیرد؟ |
git status -s --ignored | نادیدهها را هم نشان بده |
git rm --cached فایل | از ردیابی دربیاور، روی دیسک بماند |
git rm -r --cached پوشه | همان برای پوشه |
build/* و !build/README.md | استثنا داخل پوشهی ignoreشده |
.env و !.env.example | رمز ignore، نمونهاش tracked |
touch پوشه/.gitkeep | نگهداشتن پوشهی خالی |
git config --global core.excludesFile ~/.gitignore_global | ignore سراسری |
git add -f فایل | افزودن اجباری فایل ignoreشده |