سرفصل‌های آموزشی
آموزش کاربردی گیت برای برنامه نویسان
Git stash

Git stash

Git stash

Git stash، تغییرهایی را که در نسخه ی کاریتان ایجاد کرده اید، به طور موقت ذخیره می کند تا بتوانید روی ویژگی دیگری کار کنید. سپس در آینده هر موقع نیاز شد، برگردید و آن ها را دوباره اعمال کنید. Stash کردن (ذخیره کردن) زمانی سودمند است که می خواهید روی زمینه ی دیگری کار کنید اما در وسط تغییر کدی هستید و هنوز آماده ی commit کردن نیستید. 

مقاله Git Stash، شامل بخش های زیر است: 

Stash کردن کارتان

دستور git stash تغییرهای commit نشده تان را (هم آن هایی که stage شده اند و هم آن هایی که stage نشده اند) می گیرد؛ برای استفاده ی بعدی، ذخیره شان می کند و سپس به نسخه ی کاریتان برمی گرداند. برای مثال:

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
nothing to commit, working tree clean

در این مرحله، می توانید تغییرها و commit های جدید ایجاد کنید،  شاخه را عوض کنید و هر کدام از کارهای git را انجام دهید. سپس برگردید و وقتی آماده شدید، stash خود را دوباره اعمال کنید.

توجه داشته باشید که stash در مخزن محلی git شماست و هنگام push کردن، stash ها به سرور منتقل نمی شوند.

تغییرهای stash شده خود را دوباره اعمال کنید.

می توانید با دستور git stash pop تغییرهای stash شده خود را دوباره اعمال کنید:

$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

pop کردن stash، تغییرها را از stash شما برداشته و دوباره در نسخه ی کاریتان اعمال می کند.

همچنین، می توانید با دستور git stash apply، تغییرهایی را هم اعمال کرده و هم در stash نگه دارید:

$ git stash apply
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

این دستور هنگامی مفید است که بخواهید تغییرهای stash شده را روی چند شاخه اعمال کنید.

اکنون که اصول stash کردن را می دانید، یک نکته ی مهم وجود دارد که باید از آن آگاه باشید: به طور پیش فرض، git تغییرهای فایل های ردیابی نشده یا نادیده گرفته شده را stash نمی کند.

Stash کردن فایل های ردیابی نشده یا نادیده گرفته شده

به طور پیش فرض، اجرای دستور git stash، موارد زیر را stash خواهد کرد:

  • تغییرهایی که به فهرست شما اضافه شده اند (تغییرهای stage شده).
  • تغییرهای ایجاد شده در فایل هایی که در حال حاضر git؛ آن ها را ردیابی می کند (تغییرهای stage نشده).

اما git موارد زیر را stash نمی کند:

بنابراین اگر فایل سومی به مثال بالا اضافه کنیم، اما آن را stage نکنیم (دستور git add را اجرا نکنیم)، git stash آن را stash نخواهد کرد.

$ script.js

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:

    script.js

$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
Untracked files:

    script.js

اضافه کردن -u (یا --include-untracked) به دستور git stash، موجب stash شدن فایل های ردیابی نشده نیز می شود:

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:
    script.js

$ git stash -u
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
nothing to commit, working tree clean

همچنین می توانید با اضافه کردن -a (یا --all) به دستور git stash تغییرهای فایل های نادیده گرفته شده را نیز stash کنید.

مدیریت چندین stash

شما به اجرای یک stash محدود نیستید و می توانید دستور git stash را چندین بار اجرا کنید تا چندین stash داشته باشید. سپس از git stash list برای مشاهده ی آن ها استفاده کنید. به طور پیش فرض، stash ها به عنوان “WIP ”(work in progress) در بالای شاخه مشخص می شوند و یک stash ای که از آن شاخه ساخته اید را commit می کنند. اما بعد از مدتی به یادآوردن این که هر stash شامل چیست، دشوار خواهد بود:

$ git stash list
stash@{0}: WIP on master: 5002d47 our new homepage
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

برای حل این مشکل می توانید با استفاده از “git stash save message”، یادداشتی برای توصیف stash مورد نظرتان بگذارید:

$ git stash save "add style to our site"
Saved working directory and index state On master: add style to our site
HEAD is now at 5002d47 our new homepage

$ git stash list
stash@{0}: On master: add style to our site
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

به طور پیش فرض، git stash pop آخرین stash ایجاد شده را اعمال می کند: stash@{0}

اما می توانید با اضافه کردن شناسه ی یک stash مانند مثال پایین، مشخص کنید کدام stash دوباره اعمال شود:

$ git stash pop stash@{2}

مشاهده ی تفاوت های stash ها

می توانید خلاصه ای از stash ها را با اجرای git stash show، مشاهده کنید:

$ git stash show
 index.html | 1 +
 style.css | 3 +++
 2 files changed, 4 insertions(+)

همچنین با اضافه کردن -p (یا --patch) می توانید تفاوت های کامل یک stash را ببینید:

$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

Stash کردن بخشی از تغییرها

می توانید تنها یک فایل، مجموعه ای از فایل ها یا تغییرهای خاصی از درون فایل ها را stash کنید. بدین صورت که اگر -p (یا --patch) به دستور git stash اضافه کنید، در مورد stash کردن هر بخشی از کارتان که تغییر یافته، از شما سوال می شود:

$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n

می توانید "?" را برای مشاهده ی لیست کاملی از دستورهای stash یک بخش، وارد کنید. متداول ترین این دستورها در جدول زیر آورده شده اند:

توضیح

دستور

جستجو برای یک بخش به کمک regex

/

مشاهده لیست کاملی از دستورهای بخش                                    (help)   

?

این بخش را stash نکن                                                          (no)

n

 هر بخشی که انتخاب شده باشد، stash خواهد شد                    (quite)

q

این بخش را به بخش های کوچک تر تقسیم کنید                        (split)

s

این بخش را stash کنید                                                       (yes)

y

هیچ دستور صریحی برای لغو وجود ندارد، اما با زدن CTRL-C فرایند stash قطع می شود.

ایجاد یک شاخه از stash

اگر تغییرهای شاخه ی فعلی شما با تغییرهای stash تان اختلاف داشته باشند، هنگام اعمال دوباره ی تغییرهای stash (اجرای git stash pop یا git stash apply) ممکن است با conflict مواجه شوید. برای حل این مشکل می توانید با استفاده از git stash branch یک شاخه ی جدید ایجاد کنید و تغییرهای stash شده خود را در آن اعمال کنید:

$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

این دستور بر اساس commit ای که شما stash تان را از آن ایجاد کرده اید، به یک شاخه ی جدید checkout می کند و سپس تغییرهای stash شما را به آن منتقل می کند.

تمیز کردن stash

اگر دیگر به stash خاصی نیاز نداشتید، می توانید با دستور git stash drop، آن را حذف کنید:

$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)

همچنین می توانید همه stash هایتان را با دستور زیر حذف کنید:

$ git stash clear

Git stash چگونه کار می کند؟

اگر فقط می خواستید بدانید که چگونه از git stash استفاده کنید، می توانید مطالعه را در اینجا متوقف کنید. اما اگر در مورد چگونگی عملکرد git stash کنجکاوید، به مطالعه ی این مقاله ادامه دهید!

Stash ها در واقع به صورت commit در مخزن شما کد می شوند. منبع مخصوص در .git/refs/stash به آخرین stash ایجاد شده ی شما رجوع می کند و با reflog منبع های stash، به stash های ایجاد شده ی قبلی، ارجاع داده می شود. به همین دلیل است که با stash@{n}، به stash ها مراجعه می کنید: شما در واقع به n امین ورودی reflog برای منبع stash رجوع می کنید. از آن جایی که stash فقط یک commit است، به کمک دستور git log می توانید آن را بازرسی کنید:

$ git log --oneline --graph stash@{0}
*-.   953ddde WIP on master: 5002d47 our new homepage
|\ \ 
| | * 24b35a1 untracked files on master: 5002d47 our new homepage
| * 7023dd4 index on master: 5002d47 our new homepage
|/ 
* 5002d47 our new homepage

بسته به آن چه شما stash می کنید، دستور git stash، دو یا سه commit ایجاد می کند. commit های مثال بالا عبارتند از:

  • stash@{0}: یک commit جدید برای ذخیره فایل هایی که ردیابی می شوند. فایل هایی که وقتی git stash را اجرا کردید، در نسخه ی کاریتان بوده اند.
  • اولین والدین stash@{0} : commit ای که قبلا در HEAD، هنگام اجرای git stash بوده است.
  • دومین والدین stash@{0} : یک commit جدید که index را نشان می دهد، وقتی که git stash را اجرا کردید.
  • دومین والدین stash@{0} : یک commit جدید به نمایندگی از فایل های غیرقابل ردیابی که هنگام اجرای git stash در نسخه ی کاریتان وجود داشته است. این والدین سوم فقط در صورتی ایجاد می شوند که:
  • نسخه ی کاریتان در واقع شامل فایل های غیرقابل ردیابی است.
  • شما در هنگام فراخوانی git stash گزینه ی --include-untracked یا --all را وارد کردید.

چگونه git stash درخت کار و فهرست شما را به عنوان commit در نظر می گیرد:

  • قبل از stash کردن، درخت کار شما ممکن است شامل تغییرهایی در فایل های ردیابی شده، فایل های ردیابی نشده و فایل های نادیده گرفته شده باشد. برخی از این تغییرها ممکن است در فهرست نیز stage شده باشند.
  • فراخوانی git stash، هرگونه تغییر در فایل های ردیابی شده را به عنوان دو commit جدید در DAG شما، کد می کند: یکی برای تغییرهای stage نشده و دیگری برای تغییرهای stage شده در فهرست. منبع مخصوص refs /stash  برای نشان دادن آن ها به روز می شود.
  • با استفاده از include-untracked—  می توانید هرگونه تغییر در فایل های ردیابی نشده را به عنوان یک commit اضافی کد کنید.
  • با استفاده از --all می توانید تغییر در فایل های نادیده گرفته شده را در کنار تغییر در فایل های ردیابی نشده، در یک commit قرار دهید.

هنگامی که git stash pop را اجرا می کنید، تغییرهای مربوط به commit های بالا، برای به روزرسانی فهرست و نسخه ی کاریتان استفاده می شود، و reflog stash برای حذف commit ای که pop شده، تغییر داده می شود. توجه داشته باشید که commit های pop شده بلافاصله حذف نمی شوند، اما در آینده، garbage collector، آن ها را جمع آوری می کند. 

منبع 

https://www.atlassian.com/git/tutorials/saving-changes/git-stash 

online-support-icon