برنامه‌نویسی

دستورات ضروری Git

مطمعنا هنگام استفاده از گیت، مشکلی برایتان پیش آمده. در این‌مقاله دستوراتی را موردبررسی قرا می‌دهیم که به رفع مشکل شما کمک می‌کنند.

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

اگر کسی می‌گوید در استفاده از گیت، مشکلی برایش رخ نداده است، به او اعتماد نکنید. مگر اینکه آن‌فرد، لینوس توروالدز (Linus Torvalds) یا جف‌دین (Jeff Dean) باشد.

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

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

دو نکته فوق باعث می‌شود، همه قبل از انجام هرگونه Commit و push به ریموت، عصبی شوند. اما این مراقبت‌ها به ما کمک نمی‌کنند و باعث می‌شوند زودتر یک‌کار احمقانه انجام‌دهیم. پس بدیهی است که ما، جستجو در گوگل را آغازکنیم.

در واقع این مقاله دو قسمت از کل دستورات را پوشش می‌دهد زیرا نمی‌خواهیم با اطلاعات زیاد شما را خسته‌کنیم. در قسمت اول تمرکز خود را برروی دستورات مفیدی که در پوشه کاری local می‌گذاریم و در قسمت دوم مسائل مربوط به ریمورت ریپازیتوری‌ها مانند reverting, deleting, ویرایش Commit و … می‌پردازیم. پس خوب دقت کنید و در ادامه مقاله با ما همراه باشید.

در این قسمت می‌پردازیم به:

  • فایل‌هایی که به صورت اتفاقی در حالت staged قرار گرفته‌اند.
  • دنبال‌نکردن فایل‌هایی که نمی‌خواهیم دیگر track شوند.
  • چگونگیِ پاک کردن فایل‌های un-tracked و ignored.
  • revert کردن تغییراتی که هنوز commit نشده‌اند.

پس بیاید به مواردی (دستورات) که، کار ما را به خطر می‌اندازند، نگاهی بیندازیم.

فایل‌هایی که به صورت اتفاقی در حالت staged قرار گرفته‌اند

آیا تاکنون دستور زیر را اجرا کرده‌اید و می‌خواهید آن‌ها را بی‌اثر کنید؟

git add .
git add *
git add -A
git add -u

با این لینک می‌توانید همه‌چیز را درمورد دستورات بالا یادبگیرید.

دستوراتی که در این زمان می‌توانند به شما کمک کنند:

  • git reset <filename> یا git reset HEAD <filename>
  • git rm --cached <filename>
  • git restore --staged <filename> — در v2.23 (اوت 2019) به گیت اضافه‌شده است.

این سه دستور هنگام اضافه کردن فایل‌ها به حالت stage، توسط خود گیت به شما توصیه می‌شود. اگر شما از گیت ورژن 2.23 (اتصال به semantic versioning) استفاده‌کنید،

git restore --staged <filename>

بجای

git reset HEAD <filename>

به شما توصیه می‌شود.

دستور

git restore --staged <filename>

به طور شفافی کاراییش معلوم است. پس بیاید دو دستور دیگر را بررسی‌کنیم.

:git reset HEAD <filename>

این دستور برای بازنشانی INDEX یا STAGING AREA مورد استفاده قرار می‌گیرد.

git rm --cached <filename>:

این دستور کاملا فایل را از حالت INDEX یا STAGING AREA خارج می‌کند، همچنین اگر شما یک فایل موجود در ریپازیتوری را پاک کنید، با اجرای این دستور، آن‌فایل از INDEX ، STAGING AREA و همچنین از commit های دیگر پاک خواهدشد. اما هنگامی که از این‌ دستور بر روی فایل جدید استفاده کنید، فقط آن را از حالت staged بیرون می‌آورد.

چرا گیت دو دستور مختلف را برای اینکار توصیه می‌کند؟

برای اجرای موفقیت‌آمیز دستور

git reset HEAD <filename>

یا

git restore --staged <filename>

باید حداقل یک commit وجود داشته‌باشد. به این‌دلیل که دستور

git reset HEAD

فایل درون HEAD را بازگردانی می‌کند ولی قبل از انجام اولین commit هیچ‌گونه HEAD ی موجود نیست (به این‌دلیل که HEAD در زمان اولین commit ساخته می‌شود.).

به این‌دلیل که HEAD در زمان اولین commit ساخته می‌شود.

راه‌حل این مشکل هم اجرای آنT به استثنای HEAD است، به مثال زیر توجه کنید:

git-reset
اکنون شما خطایی ندارید.

یادداشت: من از git revert بجای git revert Head استفاده می‌کنم. در لینک های زیر می‌توانید در این‌مورد بیشتر بخوانید.

دفعه بعد که از گیت استفاده می‌کنید، هنگامی که هنوز commit ی موجود نباشد، گیت دستور

git rm --cached <filename>

را به شما پیشنهاد می‌کند در غیر این‌صورت

git reset Head و git restore --staged

را مشاهده خواهیدکرد.

در ادامه با نحوه استفاده از این‌دستورات هنگامی که یک مشکل بوجود می‌آید، آشنا می‌شویم.

git reset

git reset HEAD <filename>:

اگر شما فرد تنبلی باشید، تمام commit های خود را در پایان روز انجام می‌دهید.

دستور git add

در تمام‌روز به اضافه‌کردن و ویرایش فایل‌هایتان مشغول بوده‌اید، حال شما می‌خواهید همگی آن‌ها با هم‌دیگر در یک commit به گیت بیفزایید و به صورت اتفاقی از دستور git add . استفاده می‌کنید.

دستور git add .

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

دستور git rm --cached

با توجه به تصویر بالا، حال شما می‌توانید این‌کار را انجام دهید.

git rm –cached

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

دوباره تکرار می‌کنم، دستورات

git rm --cached و git reset

تا زمانی یکسان عمل می‌کنند که commit ی انجام نشده‌باشد. در قدم اول خروجی دستور

git rm --cached

را هنگامی که commit انجام شده، بررسی می‌کنیم.

دستور git rm --cached <filename>

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

این دستور فایل‌ها را از INDEX و STAGING AREA پاک می‌کند، ولی این فایل‌ها با تمام اطلاعاتشان هنوز در سیستم شما موجود هستند اما گیت آن‌فایل را به حالت un-tracked درآورده‌است. ساده‌تر بگوییم، با اجرای دستور git rm --cached به نظر می‌رسد شما، تازه یک فایل را در پوشه‌تان کپی کرده‌اید.

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

git rm --cached <file> && git push

را اجرا کنید، <file> از گیت پاک می‌شود، زیرا این فایل فقط در سیستم شما موجود است و به حالت un-tracked در آمده.

برای رویارویی با زمانی که شما تمام فایل‌هایتان را در ریموت‌سرور push کرده‌اید، مثلا شما همراه پروژه node خود پوشه node_modules را به ریمورت فرستاده‌اید، می‌توانید:

  • فایلی با پسوند .gitignore در کنار فایل‌هایتان اضاف کنید و بعد از آن دستور rm -r node_modules && git add . && git commit && git push && npm start را اجرا کنید.
  • یا .gitignore را بسازید سپس دستورات git rm --cached -r node_modules && git commit && git push را اجرا کنید.

گزینه دوم بهتر و کوتاه‌تر است. هنگامی که شما از

git rm --cached -r

استفاده می‌کنید (-r مخفف بازگشی – recursive)، این دستور پوشه node_modules را از INDEX یا STAGING AREA پاک می‌کند و همچنین آن‌پوشه به حالت un-tracked در می‌آید. ولی به این نکته توجه داشته باشید از فایل‌های سیستمی شما پاک نمی‌شود.

هنگامی که شما دستور git add . را اجرا می‌کنید، اول فایل .gitignore چک می‌شود و دیگر شما پوشه node_modules را در git status نمی‌بینید زیرا به یک پوشه un-tracked در آمده‌است.

خلاصه:

همیشه از دستورات git reset <filename> برای unstage کردن یک فایل بخصوص یا از git reset . برای unstage کردن تمام فایل‌ها استفاده کنید. این دستورات حتی اگر commit هم رخ نداده باشد کار می‌کنند.

از دستور git rm --cached هم زمانی که می‌خواهید فایلی را از ریپازیتوری حذف و آن را در سیستم خود نگهدارید، استفاده کنید. کارایی این دستور را با git reset اشتباه نکنید.

اگر می‌خواهید بیشتر بدانید، آدرس زیر را دنبال کنید.

به طور تصادفی فایل‌ها را ردیابی می‌کنید یا دیگر نمی‌خواهید یک فایل را track کنید؟

در این قسمت فایده دستور git rm --cached نمایان می‌شود. همانطور که قبلا در این مقاله خواندید این‌دستور فایل را از INDEX و STAGING AREA و همچنین ریپازیتوری پاک می‌کند. بنابراین، git push فایل را از ریپازیتوری حذف و در قدم بعد git pull آن را از فایل‌های سیستم گیت پاک می‌کند (فایل‌ها در سیستم شما باقی می‌مانند).

  • برای un-track و پاک‌کردن همه چیز: git rm --cached .
  • برای un-track و پاک‌کردن یک فایل بخصوص: git rm --cached <fillename>
  • و در آخر برای un-track و پاک‌کردن یک پوشه: git rm --cached -r <directoryname>

توجه داشته‌باشید دستور git rm با git rm --cached متفاوت است. git rm نیز فایل را از سیستم شما، ریپازیتوری و هرجای دیگر سیستم پاک می‌کند. پس --cached را فراموش نکنید.

می‌خواهید فایل‌های un-tracked و ignore شده را حذف کنید؟ در ادامه با ما همراه باشید.

در مقابل شما دو راه‌حل وجود دارد. با دستور rm file1 file2 file3 ... این‌کار را انجام‌دهید. ولی اگر فایل‌ها زیاد باشند، این کار منطقی نیست پس یک راه دیگر پاک کردن فایل‌های درون .gitignore است. این‌کار با دستور git clean انجام می‌شود.

راهنمای (man) این‌دستور:

Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.

Normally, only files unknown to Git are removed, but if the -x option is specified, ignored files are also removed. This can, for example, be useful to
remove all build products.

همانطور که در متن بالا گفته شد، با این دستور به صورت بازگشتی (recursive) فایل‌ها از دایرکتوری فعلی که دستور در آن اجرا شده پاک می‌شوند.

  • برای حذف un-tracked فایل‌ها: git clean -f
  • برای حذف un-tracked و ignored فایل‌ها: git clean -xf
  • برای حذف دایرکتوری‌ و un-tracked فایل‌ها: git clean -fd
  • برای حذف دایرکتوری‌ و un-tracked, ignored فایل‌های : git clean -xfd

ولی چرا از ویژگی -f یا –force استفاده می‌کنیم؟ در پیکربندی گیت، متغییر clean.requireForce برابر با true قرار داده شده‌است. اگر از -f، -n، -i استفاده نکنیم دستور ما با موفقیت به پایان نمی‌رسد.

این دستور فایل و پوشه‌ها را به صورت فیزیکی حذف می‌کند. پس امیدوارم در هنگام اجرای این دستور اشتباه نکرده باشید. برای رفع این مشکل می‌توانید از دستور git clean -fi استفاده کنید.

دستور git clean -fi

شما می‌توانید از گزینه شماره 4 استفاده کنید و گیت قبل از حذف هر فایل، از شما می‌پرسد از فایل حذف شود یا خیر؟

راهنمای (man) این‌دستور:

راهنمای دستور git clean
راهنمای دستور git clean

آیا می خواهید تغییرات را به حالت un-committed برگردانید؟

شما دستور git commit را اجرا و پس از آن به ویرایش فایل‌های پروژه‌تان میپردازید. چندساعت بعد تصمیم می‌گیرید، تغییرات انجام شده را به حالت قبل در بیاورید.

راه‌حل، استفاده از دستور git checkout است. بله درست شنیدید، ولی هنگام استفاده از این دستور، مراقب باشید. استفاده نادرست این دستور باعث تخریب می‌شود. اجرای این دستور باعث حذف کارهای انجام‌شده بر روی دایرکتوری که در آن قرار دارید می‌شود و آن را به commit قبلی خود بازمی‌گرداند.

راهنمای این دستور:

git-checkout — Switch branches or restore working tree files

Updates files in the working tree to match the version in the index or the specified tree. If no paths are given, git checkout will also update HEAD to set
the specified branch as the current branch.

دستور git checkout .

پی‌نوشت: شاید در تصویر بالا شما دستور git restore <filename> را ببینید (این بخاطر استفاده از ورژن 2.25.0 گیت است). با توجه به راهنما، از این دستور استفاده نکنید.

دستور git restore <filename>
راهنمای دستور – git restore

در ادامه، میبایست به این موضوع اشاره کرد با دستور git checkout . می‌توانید فقط فایل‌های تغییر داده‌شده را به stage قبل (نه commit قبل) برگردانید. در تصویر بالا staging version قبل، خالی است. پس با دستور git checkout . محتوای first message to commit، خالی می‌شود.

گیت تاریخچه INDEX و STAGING AREA را نگهداری نمی‌کند. دو چییزی که گیت به شما نشان می‌دهد:

  • چه‌چیزی در INDEX است؟
  • چه‌چیزی در INDEX نیست؟

با اجرای دستور git add، گیت محتوای درون INDEX را اضافه یا با مقدار جدید جایگزین می‌کند. بنابراین شما به تاریخچه INDEX مانند COMMIT دسترسی ندارید و نمی‌توانید آن را بازگردانی کنید.

دستور git add

از آنجا که هیچ INDEX versions دیگری باقی نمانده است، گیت کپی از commit قبلی که somedbconfigfile1 خالی است دریافت می کند.

دستور git checkout <filename> را فقط می‌توان روی فایل‌های stage نشده اجرا کرد. به همین دلیل از git reset . برای un-stage کردن فایل در تصویر بالا استفاده شده است.

منبع: https://medium.com/from-the-scratch/git-commands-you-need-to-know-when-you-are-messed-up-e880fbf03819