تا حالا دقت کرده اید که یک سری فایل ها و پوشه های اضافی در پوشه پروژه ساخته می شود؟ مثلا vscode برای خودش فایل settings.json می سازد. یا محصولات jetbrains مانند intellij یک پوشه به نام idea می سازند.  حال اگر این پوشه ها و فایل ها به ریپازیتوری گیت اضافه شوند در بیشتر کامیت ها می بینید که در لیست تغییرات (changeset) وجود دارند. این مسئله باعث می شود که کامیت های شما کثیف باشد و کار آزاردهنده باشد.
خب راه حل چیست؟ راه حل معمولی این است که این فایل ها را در فایل .gitignore اضافه کنیم. البته این راه حل خیلی وقت ها کار می کند و مشکل حل می شود.
اما این تنها راه حل نیست. راه های مختلف دیگری هم هست. که این راه ها جاهایی که روشی که گفتیم نتواند کاری از پیش ببرد به کار خواهند آمد. یادگیری آنها باعث می شود که یک سری اضافه کاری ها را انجام ندهید.
در این مطلب خیلی ساده این مشکلات را مطرح می کنیم و از راه حل درست استفاده می کنیم.

قدم صفر: چک کنید که گیت به فایل مورد نظر نظارت می کند یا خیر؟

قبل از این که یک راهی برای نادیده گرفتن یک فایل در نظر بگیریم باید ببینیم که این فایل آیا توسط گیت دنبال می شود و گیت به تغییرات آن نظارت می کند یا خیر. یک فایل توسط گیت دنبال می شود و tracked است به شرطی که حداقل یک بار ایندکس شده باشد و به حالت stage اضافه شده باشد و در غیر این صورت untracked است. برای این که وضعیت ریپازیتوری گیت را ببینید می توانید از دستور استفاده کنید. این دستور اگر لیست فایل هایی را که untracked باشد را به شما نشان می دهد.

git status

اما اگر بخواهید فقط یک فایل مشخص را بررسی کنید که آیا tracked شده است یا خیر از دستور زیر استفاده می کنیم.

git ls-files --error-unmatch path/to/file

اگر خروجی این دستور اسم فایل را چاپ کند فایل tracked است ولی اگر اررور بدهد فایل مورد نظر untracked است. در ادامه از این مبحث استفاده خواهیم کرد.

آموزش gitignore در گیت

فایل .gitignore دقیقا چه کاری می کند و کجا ناتوان است؟

فایل .gitignore فقط روی فایل هایی که untracked هستند کار می کند. یعنی فایل هایی که هیچ وقت به ایندکس و ریپازیتوری add نشده اند. اگر نام آن فایل یا یک rule قرار دهید که متناسب با آن فایل باشد گیت آن فایل را نادیده خواهد گرفت.
اما فایل هایی که قبلا tracked شده اند چه؟ gitignore در مورد آنها نمی تواند کاری کند. مثلا اگر فایلی را که چند وقت پیش کامیت کرده اید حال الان نام آن را به gitignore اضافه کنید عمل ignore توسط گیت ignore خواهد شد. یعنی با توجه به این که آن فایل در gitignore اضافه شده است ولی گیت نمی تواند آن فایل را نادیده بگیرد و آن فایل کماکان در ریپازیتوری خواهد ماند. پس این یک محدودیت استفاده از فایل gitignore است.
علاوه بر مشکل بالا یک محدودیت دیگر نیز وجود دارد و آن این است که فایل gitignore یک فایل کامیت شده است. یعنی هرچه در داخل آن بنویسید همه هم تیمی های شما و همه کسانی که به ریپازیتوری شما دسترسی دارند می توانند آن را بخوانند. البته این برای زمان هایی که باید یک سری فایل یا پوشه همه جا نادیده گرفته شود مثل پوشه node_modules در پروژه های nodejs بسیار عالی است. زیرا که همه اعضای تیم باید این موارد را خارج از ریپازیتوری نگه داری کنند و به ریپازیتوری اضافه نشود. اما حالتی را در نظر بگیرید که مثلا شما برای پروژه از یک ادیتور خاص استفاده می کنید و آن یک سری فایل های اضافی تولید می کند که آن را نادیده میگیرید در حالی که هیچ کدام از اعضای تیم با آن نوع فایل و ادیتور سرو کار ندارد و آن نوع فایل ها مختص خود شما است. در این صورت اضافه کردن چنین فایل هایی به gitignore باعث کثیف شدن این فایل و شلوغی آن می شود و اگر روشی باشد که فقط روی سیستم شمااین نوع فایل ها نادیده در نظر گرفته شود بهتر است. 
اینجاست که راه های دیگری هم برای ignore کردن فایل ها در گیت پیاده سازی شده است.

راه های ignore(نادیده گرفتن) فایل ها غیر از gitignore در گیت.

در ادامه راه های دیگری که می توان با استفاده از آنها یک سری فایل ها را از دید گیت دور کرد را توضیح می دهیم.

فایل .git/info/exclude (فایل gitignore شخصی شما)

اگر پوشه .git را باز کنید و به پوشه info بروید یک فایل به نام exclude در آن وجود دارد که اکثر مردم اصلا این فایل را باز نکرده اند ولی این فایل بسیار کاربردی است. این فایل دقیقا مثل gitignore کار می کند و می توان همان قواعد مربوط به فایل gitignore را در آن نوشت. تفاوت این فایل با gitignore در این است که این فایل فقط در کامپیوتر شما می ماند و اگر شما بخواهید پروژه را پوش کنید این فایل ارسال نخواهد شد و به صورت شخصی برای شما کار می کند. همچنین این فایل هیچ وقت کامیت نمی شود و در ریپازیتوری وجود نخواهد داشت. این فایل بهترین راه حل برای فایل های untrackedی است که مختص کامپیوتر شما است. مثل فایل های ادیتور که قبلا مثال آن زده شد.

مثال واقعی

چند وقت پیش در حال تست کردن یک API کند بودم و آن را دیباگ می کردم به خاطر این که خیلی کدهای تکراری را دوباره ننویسم یک فایل به نام test-timing.js ساخته بودم که یک سری اطلاعات را لاگ بگیرد. یک فایل موقتی بود که قرار بود آن را بعدا حذف کنم و قرار هم نبود به ریپازیتوری اضافه شود. این فایل را نمی توانستم به gitignore اضافه کنم زیرا که ربطی به بقیه اعضای تیم نداشت و لازم نبود که فایل gitignore را به خاطر این فایل تغییر بدهم. پس آن را به فایل .git/info/exclude اضافه کردم و خیلی راحت از دید گیت پنهان شد و مشکل افزودن به ریپازیتوری هم برطرف شد. برخی موارد من یک فایل به نام todo.md هم می سازم و یک سری نوت ها و یادداشت ها در حین انجام پروژه به آن اضافه می کنم ولی لازم نیست که ردپایی از آن داخل ریپازیتوری یا gitignore وجود داشته باشد پس آن را در exclude اضافه می کنم.

آموزش گیت در توسینسو

روش نادیده گرفتن فایل ها با روش --skip-worktree

روش ignore کردن فایل های شخصی را بررسی کردیم. اما اگر فایلی را که قبلا به ریپازیتوری و ایندکس اضافه کرده ایم و یا کامیت کرده ایم چه باید بکنیم؟ برای مثال یک فایل کانفیگ دارید که با تنظیمات خاصی مقداردهی شده است مثلا آدرس دیتابیس و مواردی مشابه این، اما شما روی سیستم خودتان می خواهید که مقادیر آن تنظیمات را عوض کنید. ولی نمی خواهید این تغییر تنظیمات را کامیت کنید. خب با این وضعیت فایل gitignore نمی تواند کاری برای ما انجام دهد زیرا که این فایل قبلا در ریپازیتوری اضافه شده است. پس چطور می توان کاری کرد که گیت این تغییر تنظیمات و کانفیگ شخصی را نادیده بگیرد؟
راه حل --skip-worktree است. برای حل این مشکل از دستور زیر استفاده می کنیم.

git update-index --skip-worktree path/to/configFile


بعد از این دستور گیت تغییرات روی این فایل را بیخیال می شود. وقتی که شما git-status می گیرید تغییرات این فایل در لیست نخواهد بود. 
برای مثال وقتی که روی یک پروژه کار می کردم که شامل یک فایل برای کانفیگ دیتابیس و آدرس دیتابیس بود ولی من می خواستم وقتی که روی پروژه کار کنم برای دیتابیس از دیتابیس محلی در آدرس localhost استفاده کنم. به خاطر همین این فایل را تغییر دادم به شکلی که این تغییرات در ریپازیتوری ذخیره نشوند و فقط برای کار خودم باشد. بنابراین از --skip-worktree استفاده کردم.

خاموش کردن --skip-worktree

حال شاید لازم باشد که تغییری در همان فایل کانفیگ ایجاد کنید و آن تغییر در ریپازیتوری کامیت شود. یعنی skip-worktree را خاموش کنید. در این حالت باید  دستور زیر را اجرا کنید.

git update-index --no-skip-worktree path/to/configFile

این دستور باعث می شود که فایلی را که قرار بود تغییرات آن نادیده گرفته شود به حالت قبلی بازگردد و گیت مثل بقیه فایل ها با آن رفتار کند.
برای این که بدانیم کدام کی از فایل ها را skip-worktree کرده ایم ولیست آنها را ببینیم دستور زیر را اجرا می کنیم.

git ls-files -v | grep '^S'

حرف S بزرگ در دستور بالا برای فایل هایی است که به فلگ skip-worktree خورده اند.

هشدار:

دستور skip دستور قابل اعتمادی است ولی ممکن است وقتی که git pull کردید فایل مورد نظر با تغییرات گیت مرج شده و گیت دستور skip شما را نادیده بگیرد و فایل را دوباره به حالت قبل برگرداند. این حالت نادر است ولی ممکن است که اتفاق بیفتد پس آن را مدنظر داشته باشید.