سرفصل‌های آموزشی
آموزش کاربردی گیت برای برنامه نویسان
Rewriting history چیست؟

Rewriting history چیست؟

Rewriting history چیست؟

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

کار اصلی git این است که مطمئن شوید که هرگز تغییر انجام داده شده را از دست ندهید. اما این قابلیت را نیز طراحی کرده اند که شما کنترل کاملی بر جریان گردش کار خود داشته باشید. این قابلیت شامل اجازه ی تعریف تاریخ پروژه ی شما نیز هست که ممکن است باعث شود تغییرات را از دست بدهید. git دستورهای بازنویسی تاریخچه ی خود را با تاکید بر اینکه ممکن است محتوای شما را از بین ببرد ارائه کرده است. git دارای مکانیزم های متعددی برای ذخیره تاریخچه و حفظ تغییرات است. این مکانیزم ها شامل: git commit --amend و git rebase و git reflog است. این گزینه ها، ابزار های قدرتمندی را برای سفارشی سازی گردش کار به شما می دهد. در پایان این بخش شما با دستوراتی آشنا هستید که اجازه می دهند commit های خود را بازسازی کنید و بتوانید از مشکلاتی که معمولا موقع بازنویسی تاریخچه به آن بر می خورید، جلوگیری کنید.

تغییر آخرین Commit: git commit –amend

دستور git commit –amend یک راه مناسب برای تغییر commit آخر است. این دستور به شما این امکان را می دهد که به جای ایجاد یک commit به طور کامل، تغییرات جدید را با commit قبلی ترکیب کنید. همچنین می تواند برای تغییر پیام commit  قبلی مورد استفاده قرار بگیرد بدون این که تغییری در کار اصلی آن ایجاد شود. اما، اصلاحیه (amending)، فقط جدیدترین commit را تغییر نمی دهد، آن را به طور کامل جایگرین می کند، به این معنی که commit اصلاح شده یک commit جدید با منبع خود خواهد بود. Git آن را مانند یک commit جدید با نام تجاری، که در نمودار زیر با یک ستاره (*) نشان داده شده است، مشخص می کند. چند مورد معمول برای استفاده از git commit --amend  وجود دارد. ما نمونه هایی از موارد استفاده را در بخش های زیر می آوریم.

تغییر پیام جدیدترین git commit 

این دستور را زمانی اجرا می کنیم که هیچ خطایی در کد اصلی وجود ندارد و فقط در پیام commit اشتباهی وجود دارد. این دستور به شما اجازه می دهد که پیام commit قبلی را بدون تغییر کارهای اصلی ویرایش کنید.

در طول دوره ی توسعه ی روزمره ی شما، ممکن هست این اتفاق پر تکرار باشد. پرچم  amend-- یک راه مناسب برای حل این اشتباه های جزئی است.

git commit –amend -m “an updated commit message”

اضافه کردن گزینه ی m- اجازه می دهد تا شما یک پیام جدید را از راه خط فرمان ارسال کنید بدون اینکه ویرایش گری باز شود.

تغییر فایل هایی که commit شده اند.

فرض کنید ما چند فایل را ویرایش کرده ایم و می خواهیم همه ی این تغییرات را در یک commit  ثبت کنیم اما پس از ثبت commit متوجه می شویم که فراموش کرده ایم که یکی از فایل ها را اضافه کنیم.  این مثال نشان دهنده ی یک اتفاق رایج در توسعه با Git است. برای رفع این خطا از پرچم amend – می توان استفاده کرد.

# Edit hello.py and main.py 
# git add hello.py 
# git commit
# Realize you forgot to add the changes from main.py
# git add main.py
git commit –amend –no-edit

پرچم –no-edit به شما این امکان را می دهد که بدون تغییر پیام، ویرایش خود را انجام دهید. با این دستور، git می فهمد که commit ناقص است و hello.py و  main.py را در یک commit قرار می دهد.

Commit های عمومی را اصلاح نکنید.

commit اصلاح شده در واقع یک commit جدید است و commit قبلی دیگر در شاخه ی فعلی شما وجود ندارد. عواقب تغییر commit های عمومی مانند بازنشانی یک عکس عمومی (public snapshot) است.  از اصلاح commit سایر توسعه دهندگان، خودداری کنید. با این کار شما و دیگر توسعه دهندگان از یک وضعیت پیچیده و گیج کننده رها می شوید.

تغییر commit های قدیمی یا چندگانه

برای اصلاح commit  های قدیمی یا چندگانه، می توان از git rebase استفاده کرد. همچنین برای ترکیب یک دنباله ای از commit ها به یک commit  جدید نیز از این دستور استفاده می شود. در حالت استاندارد، git rebase به شما اجازه می دهد تا به طور واضح تاریخچه را بازنویسی کنید - به طور خودکار commit هایی که در شاخه ی قبلی وجود داشته اند را به شاخه ای که الان روی آن کار می کنید منتقل می کند - از آنجایی که commit جدید شما جایگزین قدیمی می شود، مهم است که از git rebase روی commit هایی که به صورتی عمومی push شده اند، استفاده نکنید. وقتی از این دستور استفاده می کنید این طور به نظر می رسد که تاریخچه ی پروژه ی شما از بین رفته است.

در این موارد یا موارد مشابه که در آن حفظ تمیزی تاریخچه ی یک پروژه مهم است، اضافه کردن گزینه ی i- به git rebase به شما اجازه می دهد تا rebase Interactive را اجرا کنید. همچنین اجازه می دهد که به جای انتقال تمام commit ها فقط commit های یک فرد را در این فرایند تغییر دهید. شما می توانید درمورد دستورهای rebase Interactive و additional rebase در بخش های بعدی این دوره اطلاعات بیشتر کسب کنید.

تغییر فایل های commit شده

در طی بازیابی، دستور edit یا e، پخش مجدد rebase (rebase playback) را روی commit متوقف خواهد کرد و به شما اجازه می دهد تا تغییرات بیشتری را با git commit --amend ارسال کنید.

Stopped at 5d025d1… formatting
You can amend the commit now, with
git commit  --amend
Once  you are satisfied with your changes, run
git rebase –continue

پیام های چندگانه

هر git commit یک پیام دارد که اتفاقی را که در آن commit رخ داده است، توضیح می دهد. این پیام ها بینش ارزشمندی را به تاریخچه ی پروژه اضافه می کنند. در طول یک rebase، برای تغییر پیام commit های انجام شده می توانید چند دستور را اجرا کنید.

  • Reword یا ‘r’ که اجرای rebase را متوقف می کند و به شما اجازه می دهد پیام های فردی را در طی آن بازنویسی کنید.
  • Squash یا ‘s’ در هنگام اجرای rebase، هر گونه  commit ای که با s مشخص شده است را متوقف می کند و از شما می خواهد که پیام های commit را به یک پیام ترکیبی ویرایش کنید. در بخش بعدی بیشتر راجع به squash commit توضیح خواهیم داد.
  • Fixup یا ‘f’ دارای اثر ترکیب مانند squash است. بر خلاف squash، fixup commits اجرای rebase را متوقف نخواهد کرد تا یک ویرایش گر را برای ترکیب پیام های commit باز کند. commit هایی که با ‘f’ مشخص شده اند پیام های خود را به نفع پیام commit قبلی از بین می برند.

Squash commit برای یک تاریخچه ی تمیز

دستور ‘s’ یا ‘squash’ جایی است که سودمندی rebase نشان داده می شود. Squash به شما اجازه می دهد که انتخاب کنید که کدام commit ها با commit های قبلی ادغام شود. این چیزی است که تاریخچه ی تمیزی را رقم می زند. در طی انجام عملیات rebase، git برای هر commit، دستور مشخصی را اجرا خواهد کرد. در مورد squash commit، git ویرایش گر تنظیم شده ی خود را باز می کند وپیام های commit های مشخص شده را ترکیب می کند. کل این فرایند را به صورت زیر می توان تجسم کرد:

توجه داشته باشید که commit ای که rebase آن را ویرایش کرده، شناسه ای متفاوت با commit های اصلی دارد. commit های انتخاب شده برای بازنویسی، شناسه ی جدیدی نسبت به قبل می گیرند. 

میزبان های مدرن git مانند BitBucket، در حال حاضر ویژگی های "squashing خودکار" را پس از ادغام ارائه می دهند.

جمع بندی

Git rebase قدرت تغییر تاریخچه ی خود را به شما می دهد و اجازه می دهد که این کار را بدون رها کردن مسیری کثیف، انجام دهید. این کار، برای ایجاد و اصلاح اشتباه ها، آزادی ایجاد و کار خود را اصلاح می کند، در حالی که هنوز یک تاریخچه ی پروژه تمیز را حفظ می کند.

شبکه ی ایمنی: git reflog

لاگ های مرجع یا "Reflogs" یک مکانیسم است که Git برای ذخیره به روزرسانی های اعمال شده روی نوک های  شاخه ها و سایر مراجع commit شده استفاده می شود. Reflog به شما اجازه می دهد تا به عقب برگردید حتی زمانی که commit ها برای هیچ شاخه یا برچسبی نباشند. پس از بازنویسی تاریخچه، Reflog شامل اطلاعاتی در مورد وضعیت قدیمی شاخه هاست و به شما اجازه می دهد تا در صورت لزوم به آن وضعیت بازگردید. هر بار که شاخه ی شما به هر دلیلی به روز می شود (با تعویض شاخه ها، pull کردن تغییرات جدید، بازنویسی تاریخ یا مورد ساده تر با اضافه کردن یک commit جدید)، یک ورودی جدید به Reflog اضافه خواهد شد. در این بخش ما یک نگاه کلی به دستور git reflog خواهیم انداخت و برخی از کاربردهای رایج آن را بررسی خواهیم کرد.

کاربرد git reflog

این دستور، reflog را برای مخزن محلی نشان می دهد.

Git reflog –relative-date

این دستور، reflog را برای مخزن محلی در یک تاریخ نسبی نشان می دهد (برای مثال 2 هفته پیش).

مثال

برای درک بهتر دستور git reflog بیایید یک مثال را در پیش بگیریم:

0a2e358 HEAD@{0}: reset : moving to HEAD~2
025ea7 HEAD@{1}: checkout : moving from 2.2 to master
C10f740 HEAD@{2}: checkout : moving from master to 2.2

Reflog بالا یک checkout از شاخه ی master به شاخه ی 2.2 و بازگشت از آن را نشان می دهد. آخرین فعالیت در بالای صفحه ی نمایش با عنوان HEAD@{0} نشان داده شده است که یک بازنشانی به commit قدیمی را نشان می دهد.

git reset –hard 0254ea7

با استفاده از دستور git reset، امکان تغییر شاخه ی master به یک commit انجام شده وجود دارد. اگر تغییرات به مخزن محلی commit شوند و فقط حرکات شاخه های مخزن را دنبال کند باعث فراهم شدن یک شبکه ی ایمن می شود. افزون بر این، مطالب reflog دارای تاریخ انقضا هستند.  برای نوشته های reflog زمان انقضای پیش فرض، 90 روز است.

 برای اطلاعات بیشتر، به صفحه git reflog ما مراجعه کنید.

نتیجه

در این مقاله ما چندین روش تغییر تاریخچه ی git را مورد بحث قرار دادیم و تغییرات git را بازنشانی کردیم و به صورت کلی به روند انجام دستور git rebase پرداختیم. برخی از مواردی که در این مقاله به آن پرداخته شد:

  • با استفاده از دستور git commit –amend می توان آخرین پیام وارد شده به سیستم را تغییر داد.
  • با استفاده از دستور git commit –amend می توان آخرین commit انجام شده را اصلاح کرد.
  • با استفاده از دستور git rebase می توان commit ها را ترکیب کرد و تاریخچه ی یک شاخه را تغییر داد.
  • git rebase -i کنترل دقیق تری را روی تغییرات تاریخچه ی git نسبت به یک git rebase استاندارد می دهد.

درباره دستورات زیر می توانید به صفحات آن ها مراجعه کنید: 

منبع

https://www.atlassian.com/git/tutorials/rewriting-history

online-support-icon