چگونه می توان یک commit عمومی را با git revert لغو کرد؟
بیایید فرض کنیم که به مثال اصلی تاریخچه ی commit خود بازگشتیم. تاریخچه ای که شامل commit 872fa7e است. این بار بیایید لغو را revert کنیم. اگر دستور git revert HEAD را اجرا کنیم، Git با معکوس آخرین commit، یک commit جدید ایجاد می کند. این commit جدید به تاریخچه ی شاخه ی فعلی اضافه می شود و اکنون آن را به صورت زیر درآورده است:
git log –oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt 9773e52 Initial import
در این مرحله، ما commit با شناسه ی 872fa7e را از نظر فنی "لغو" کردیم. اگرچه 872fa7e هنوز در تاریخچه وجود دارد، commit جدید e2f9a78 معکوس تغییرهای 872fa7e است. برخلاف استراتژی قبلی checkout، ما می توانیم از همان شاخه استفاده کنیم. این راه حل لغو، رضایت بخش است. این روش ایده آل "لغو" برای کار با مخزن های مشترک عمومی هست. اگر شما به داشتن تاریخچه ی Git تنظیم شده و حداقلی نیاز دارید، این استراتژی راضی کننده نیست.
چگونه می توان یک commit عمومی را با git reset لغو کرد؟
برای این استراتژی لغو با همان مثال قبلی کار می کنیم. git reset یک دستور گسترده با چندین کاربرد و عملکرد است. اگر git reset –hard a1e8fb5 را فراخوانی کنیم، تاریخچه ی commit به آن commit خاص باز می گردد. بررسی تاریخچه ی commit با git log به صورت زیر خواهد بود:
git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
خروجی log نشان می دهد که commit های 872fa7e و e2f9a78 دیگر در تاریخچه وجود ندارند. در این مرحله، ما می توانیم به کار خود ادامه دهیم و commit های جدیدی ایجاد کنیم بدون اینکه commit های 'crazy' رخ دهند. این روش لغو تغییرها، تمیزترین تاثیر را روی تاریخچه دارد. انجام reset برای تغییرهای محلی عالی است اما وقتی با مخزن remote مشترک کار می شود، عوارضی به همراه دارد. اگر یک مخزن remote مشترک داشته باشیم که commit با شناسه ی 872fa7e به آن push شده باشد و تلاش کنیم که یک شاخه را git push کنیم (جایی که تاریخچه را reset کرده ایم)، Git، آن را catch می کند و خطایی throw می کند. Git فرض می کند که شاخه ی push شده به دلیل commit های از دست داده اش به روز نیست. در این موارد، git revert روش بهتری برای انجام لغو است.
لغو آخرین commit
در بخش قبلی، درباره ی استراتژی های مختلف برای لغو commit ها بحث کردیم. این استراتژی ها همه در آخرین commit نیز قابل اجرا هستند. اما در برخی موارد، ممکن است نیازی به remove یا reset کردن آخرین commit نباشد. در این حالت می توانید جدیدترین commit ها را اصلاح (amend) کنید. هنگامی که تغییرهای بیشتری را در مسیر کاری ایجاد کردید و آن ها را برای commit با استفاده از git add، stage کردید؛ می توانید git commit --amend را اجرا کنید. با این کار Git ویرایش گر سیستم پیکربندی شده را باز می کند و به شما این امکان را می دهد که آخرین پیام commit را اصلاح کنید. تغییرهای جدید به commit اصلاح شده، اضافه خواهد شد.
لغو تغییرات commit نشده
قبل از اینکه تغییرها در تاریخچه ی مخزن commit شوند، در فهرست stage و مسیر کاری وجود دارند. ممکن است نیاز داشته باشید تغییرها را در این دو قسمت لغو کنید. فهرست stage و مسیر کاری، سازوکارهای داخلی مدیریت Git هستند. برای اطلاعات دقیق تر در مورد شیوه ی عملکرد این دو مکانیسم، به آموزش git reset که آن ها را عمیق تر بررسی می کند، مراجعه کنید.
مسیر کاری
مسیر کاری معمولا با سیستم فایل محلی همگام سازی می شود. برای لغو تغییرها در مسیرکاری، می توانید با استفاده از ویرایش گر مورد علاقه تان، فایل ها را ویرایش کنید. Git دارای چند برنامه کاربردی است که به مدیریت مسیر کاری کمک می کند. دستور git clean وجود دارد که یک ابزار راحت برای لغو تغییرها در فهرست کار است. هم چنین، دستور git reset می تواند با --mixed یا --hard فراخوانی شود و یک reset به مسیر کاری اعمال کند.
فهرست stage
از دستور git add برای افزودن تغییرها به فهرست stage استفاده می شود. دستور git reset در درجه ی اول برای لغو تغییرهای موجود در فهرست stage، استفاده می شود. با افزودن --mixed به دستور git reset، هر گونه تغییرهای commit نشده از فهرست stage به مسیر کاری منتقل می شود.
لغو تغییرهای عمومی
هنگام کار تیمی با مخزن های remote، لازم است موقع لغو تغییرها، دقت بیشتری داشته باشید. git reset باید به طور عموم، به عنوان یک روش لغو محلی در نظر گرفته شود. از reset باید برای لغو تغییرها در شاخه ی شخصی استفاده شود. این امر موجب می شود که حذف commit ها از شاخه های دیگری که هم تیمی های شما از آن ها استفاده می کنند، جدا گردد. مشکل وقتی به وجود می آید که reset در یک شاخه ی مشترک استفاده شود و آن شاخه با git push به مخزن از راه دور، push بشود. Git مانع این push می شود و اعلام می کند که شاخه ای که push شده، از شاخه ی remote خود متفاوت است به این دلیل که commit های خود را از دست داده است.
روش مناسب برای لغو در تاریخچه ی مشترک، git revert بوده که ایمن تر از reset است، زیرا هیچ commit ای را از تاریخچه ی مشترک حذف نمی کند. Revert، commit هایی را که می خواهید لغو کنید؛ نگه می دارد و یک commit جدید که commit ناخواسته را خنثی کرده، ایجاد می کند.
خلاصه
در این بخش، بسیاری از استراتژی های سطح بالا برای لغو کارها در Git را پوشش دادیم. مهم است که به یاد داشته باشید که بیش از یک راه برای "لغو" در یک پروژه Git وجود دارد. بیشتر بحث در این بخش از آموزش، به موضوع های عمیق تری پرداخت که با دقت بیشتری در آموزش های خاص آن دستورها، توضیح داده می شوند. رایج ترین ابزار لغو مورد استفاده git checkout،git revert و git reset هستند. برخی از نکات کلیدی برای یادآوری عبارتند از:
- وقتی تغییرها، commit می شوند؛ معمولا دائمی هستند.
- از دستور git checkout برای مرور تاریخچه استفاده می شود.
- دستور git revert بهترین ابزار برای لغو تغییرهای عمومی مشترک است.
- دستور git reset بهترین ابزار برای لغو تغییرهای خصوصی محلی است.
افزون بر دستورهای لغو اولیه، نگاهی به سایر ابزارهای Git انداختیم: git log برای پیدا کردن commit های گم شده، git clean برای لغو تغییرهای commit نشده و git add برای تغییر فهرست stage.
هر یک از این دستورها، مستندهای عمیق خاص خود را دارند. برای یادگیری بیشتر در مورد یک دستور خاص که در این جا به آن اشاره شد، لینک مربوط به آن را ببینید.