تخطَّ إلى المحتوى

git stash: احفظ عملك مؤقتاً وعد إليه لاحقاً

الدرس 8 من 10 · Git و GitHub

أنت في منتصف العمل على قائمة التنقل، والكود نصف مكتوب ولا يعمل. فجأة يصلك بلاغ: خطأ عاجل في الموقع يجب إصلاحه الآن. لا تريد حفظ commit بكود مكسور، ولا تريد أن تخسر ما كتبته. الحل هو git stash: يضع تعديلاتك جانباً، ويعيد المجلد نظيفاً، ثم يرجعها لك متى شئت.

تخيّل stash مثل دُرج المكتب: تجمع الأوراق المبعثرة وتضعها فيه لتفرغ سطح المكتب لمهمة عاجلة، ثم تخرجها وتكمل من حيث توقفت.

عدّلنا index.html وأنشأنا ملفاً جديداً draft.html:

نافذة طرفيّة
git status --short
الناتج
M index.html
?? draft.html
نافذة طرفيّة
git stash
الناتج
Saved working directory and index state WIP on main: 53be69f Revert "إضافة شريط متحرك"

WIP اختصار «عمل قيد التنفيذ» (Work In Progress). لنرَ الحالة الآن:

نافذة طرفيّة
git status --short
الناتج
?? draft.html

تعديل index.html اختفى وعاد الملف كما في آخر commit. لكن draft.html ما زال موجوداً! السبب: git stash يخزّن افتراضياً تعديلات الملفات المتتبَّعة فقط، ويترك الملفات الجديدة في مكانها.

للاسترجاع:

نافذة طرفيّة
git stash pop
الناتج
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: index.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
draft.html
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (e4abac08bff563df57b9248b8607d9e71a84d343)

pop أعادت التعديلات إلى الملفات، وحذفت المخزون (السطر الأخير: Dropped).

تخزين الملفات الجديدة أيضاً: -u

Section titled “تخزين الملفات الجديدة أيضاً: -u”

لتخزين كل شيء، بما فيه الملفات غير المتتبَّعة، أضف -u:

نافذة طرفيّة
git stash -u
git status --short

الأمر الثاني لا يطبع شيئاً: المجلد نظيف تماماً، و draft.html دخل المخزون مع التعديل.

السيناريو الكامل: إصلاح عاجل

Section titled “السيناريو الكامل: إصلاح عاجل”

الآن والمجلد نظيف، ننفّذ الإصلاح العاجل كما تعلمت في درس الفروع:

نافذة طرفيّة
git switch -c hotfix
# ... نصلح الخطأ ونحفظه ...
git commit -am "تصحيح عنوان README"
git switch main
git merge hotfix
git branch -d hotfix

ثم نعود لعملنا:

نافذة طرفيّة
git stash pop

عاد تعديل index.html وملف draft.html فوق النسخة الجديدة التي فيها الإصلاح. أكملنا من حيث توقفنا كأن شيئاً لم يقاطعنا.

يمكنك تخزين عدة أعمال، وكل مخزون جديد يوضع فوق السابق. وحتى لا تنسى محتوى كل واحد، أعطه اسماً بـ -m:

نافذة طرفيّة
git stash push -u -m "قائمة التنقل"
# ... تجربة أخرى: غيّرنا لون العنوان ...
git stash push -m "تجربة لون أحمر"
git stash list
الناتج
stash@{0}: On main: تجربة لون أحمر
stash@{1}: On main: قائمة التنقل
  • stash@{0} هو الأحدث دائماً، والأرقام تكبر مع الأقدم.
  • git stash push هو الاسم الكامل للأمر، و git stash وحدها اختصار له.

لمعرفة ما بداخل مخزون دون استرجاعه:

نافذة طرفيّة
git stash show stash@{0}
الناتج
about.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

وأضف -p لرؤية الأسطر المتغيرة نفسها.

pop تسترجع وتحذف. إذا أردت الاسترجاع مع إبقاء المخزون، مثلاً لتطبيقه على أكثر من فرع، استخدم apply:

نافذة طرفيّة
git stash apply stash@{1}
git stash list
الناتج
stash@{0}: On main: تجربة لون أحمر
stash@{1}: On main: قائمة التنقل

التعديلات عادت إلى الملفات، والمخزونان ما زالا في القائمة. وللحذف يدوياً:

نافذة طرفيّة
git stash drop stash@{0}
الناتج
Dropped stash@{0} (c65a4b7018b02329d1e506822daea45299686b8c)
الأمر الوظيفة
git stash pop استرجاع الأحدث وحذفه من القائمة
git stash apply استرجاع مع إبقاء المخزون
git stash drop حذف مخزون دون استرجاعه
git stash clear حذف كل المخزونات

بدون رقم، تعمل هذه الأوامر على stash@{0}.

بعد apply السابقة حفظنا العمل في commit، ثم نفّذنا pop للمخزون نفسه:

نافذة طرفيّة
git stash pop
الناتج
draft.html already exists, no checkout
error: could not restore untracked files from stash
The stash entry is kept in case you need it again.

Git رفض أن يكتب فوق draft.html الموجود. والمهم هو السطر الأخير: عند أي فشل يبقى المخزون في القائمة ولا يضيع شيء. الأمر نفسه إذا تعارضت تعديلات المخزون مع ما تغيّر في الملفات: تظهر علامات التعارض التي تعرفها، فتحلها ثم تحذف المخزون بـ git stash drop.

أحياناً تكتشف أن التجربة المخزَّنة تستحق فرعاً مستقلاً:

نافذة طرفيّة
git stash branch css-idea
الناتج
Switched to a new branch 'css-idea'
On branch css-idea
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: about.css
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (6c9ab3df9388f8de89d171f39ba8fc96860a20dd)

أمر واحد أنشأ الفرع، وانتقل إليه، واسترجع التعديلات، وحذف المخزون.

  1. عدّل ملفاً متتبَّعاً وأنشئ ملفاً جديداً، ثم نفّذ git stash ولاحظ أي الملفين بقي.
  2. استرجع بـ git stash pop، ثم أعد التخزين بـ git stash -u وتأكد أن المجلد نظيف.
  3. أنشئ مخزونين باسمين مختلفين، واعرضهما بـ git stash list، واسترجع الأقدم منهما بـ apply.
  4. تحدٍّ: حاكِ السيناريو الكامل: عمل ناقص، ثم stash، ثم إصلاح على فرع hotfix ودمجه، ثم pop.
  • نسيان الملفات الجديدة: git stash بدون -u يترك الملفات غير المتتبَّعة في المجلد.
  • نسيان المخزون: تتراكم مخزونات قديمة لا تتذكر محتواها. سمّها بـ -m، وراجع git stash list بين حين وآخر.
  • stash clear بتسرع: يحذف كل المخزونات دون سؤال، واستعادتها صعبة.
  • pop على فرع آخر: التعديلات تعود إلى الفرع الحالي أياً كان. تأكد من الفرع بـ git status قبل الاسترجاع.

سؤال

ما الفرق بين git stash pop و git stash apply؟

سؤال

أنشأت ملفاً جديداً لم تضفه بـ git add، ثم نفّذت git stash. أين الملف؟

  • git stash يخزّن التعديلات غير المحفوظة ويعيد المجلد نظيفاً، و -u تضم الملفات الجديدة.
  • git stash pop يسترجع ويحذف، و apply يسترجع ويبقي، و drop يحذف.
  • git stash list يعرض المخزونات، و -m تعطيها أسماء، و stash@{0} هو الأحدث.
  • عند فشل الاسترجاع يبقى المخزون سليماً في القائمة.
  • git stash branch يحوّل المخزون إلى فرع، والمخزون للمقاطعات القصيرة فقط.