git stash הוא אחד הכלים הכי שימושיים ב־Git כשאתם באמצע שינוי, משהו דחוף נכנס, ואתם לא רוצים לעשות commit חצי־אפוי רק כדי “לנקות שולחן”. יחד עם git cherry-pick, אפשר לשמור עבודה זמנית בצד, להעביר commit בודד מענף אחר, ואז לחזור בדיוק לנקודה שבה הייתם.
המאמר הזה הוא מדריך מעשי, עם פקודות מלאות שאפשר להריץ בסביבת בדיקה. לא נבנה מחדש היסטוריה שלמה, לא נעשה קסמים מסוכנים, ולא נניח שאתם זוכרים בעל פה את כל מצבי Git. המטרה היא להבין מה קורה, מה להריץ, ומה לעשות כשהפקודה נתקעת.
אם אתם בתחילת הדרך עם שורת הפקודה, כדאי לעבור קודם על צעדים ראשונים. ואם Git הוא חלק מלימוד רחב יותר של פיתוח, למשל לצד סקריפטים ב־פייתון, תגלו מהר מאוד שהרגלי עבודה טובים עם גרסאות חוסכים הרבה כאב ראש.
מתי משתמשים ב־git stash ומתי ב־cherry-pick?
שתי הפקודות פותרות בעיות שונות, אבל הן נפגשות הרבה ביום־יום:
git stashשומר שינויים מקומיים זמניים בצד, בלי ליצור commit רגיל.git cherry-pickלוקח commit קיים מענף אחר ומיישם אותו על הענף הנוכחי.
דוגמה נפוצה: אתם עובדים על פיצ’ר בענף feature-report, אבל פתאום צריך להעביר תיקון קטן שכבר קיים בענף אחר אל main. הבעיה: יש לכם קבצים פתוחים ושינויים לא גמורים. במקום לעשות commit מבולגן או להעתיק קוד ידנית, שומרים את העבודה עם git stash, עוברים לענף המתאים, עושים cherry-pick, ואז מחזירים את העבודה מה־stash.
מה להכין מראש לפני שמריצים פקודות
לפני עבודה עם stash ו־cherry-pick, כדאי לוודא שלושה דברים:
- אתם יודעים באיזה ענף אתם נמצאים:
git branch --show-current. - אתם רואים את מצב הקבצים:
git status --short. - אתם יודעים איזה commit רוצים להעביר:
git log --onelineבענף שבו הוא נמצא.
כדאי גם לזכור: stash אינו תחליף ל־commit. הוא מגירה זמנית. אם שינוי חשוב, מתועד, ונועד להישמר כחלק מהיסטוריית הפרויקט, עדיף commit מסודר. stash מתאים לעבודה רגעית, ניסוי, מעבר הקשר מהיר, או ניקוי סביבת העבודה לפני פעולה אחרת.
git stash בפועל: לשמור שינויים בצד ולחזור לעבודה נקייה
הדוגמה הבאה מיועדת ל־Linux/macOS עם bash. היא יוצרת תיקיית Git זמנית, מבצעת commit ראשון, משנה קובץ, שומרת את השינוי ב־stash, ומציגה את הרשימה.
#!/usr/bin/env bash
set -e
repo=$(mktemp -d)
cd "$repo"
git init -q
git config user.name "Demo User"
git config user.email "[email protected]"
git checkout -q -b main
printf "line one\n" > notes.txt
git add notes.txt
git commit -q -m "Add notes"
printf "work in progress\n" >> notes.txt
echo "Before stash:"
git status --short
git stash push -m "wip: notes change"
echo "After stash:"
git status --short
echo "Stashes:"
git stash listמה קורה כאן? לפני ה־stash תראו שורה כמו M notes.txt, כלומר הקובץ השתנה. אחרי git stash push, פלט git status --short יהיה ריק, כי סביבת העבודה חזרה למצב נקי. בסוף תראו רשומה דומה ל־stash@{0}: On main: wip: notes change.
הפקודה git stash push -m "..." עדיפה על git stash קצר, כי ההודעה עוזרת להבין אחר כך מה שמרתם. אחרי שבוע, stash@{3} בלי תיאור לא אומר הרבה.
להחזיר stash: apply מול pop
יש שתי דרכים נפוצות להחזיר שינויים מה־stash:
| פקודה | מה היא עושה | מתי להשתמש |
|---|---|---|
git stash apply |
מחזירה את השינויים אבל משאירה את ה־stash ברשימה | כשאתם רוצים ניסיון בטוח יותר |
git stash pop |
מחזירה את השינויים ומנסה למחוק את ה־stash מהרשימה | כשאתם בטוחים שזה ה־stash הנכון |
במקרה של קונפליקט, git stash pop בדרך כלל לא ימחק את ה־stash, כדי שלא תאבדו את השינוי. עדיין, למתחילים עדיף להשתמש קודם ב־apply, לבדוק שהכול בסדר, ורק אחר כך למחוק ידנית עם git stash drop.
שמירת קבצים חדשים עם git stash
ברירת המחדל של git stash שומרת שינויים בקבצים ש־Git כבר מכיר. אם יצרתם קובץ חדש שלא נוסף עם git add, הוא לא תמיד ייכנס ל־stash. לשם כך משתמשים ב־-u, קיצור של untracked.
גם הדוגמה הזו מיועדת ל־Linux/macOS עם bash:
#!/usr/bin/env bash
set -e
repo=$(mktemp -d)
cd "$repo"
git init -q
git config user.name "Demo User"
git config user.email "[email protected]"
git checkout -q -b main
printf "app=demo\n" > settings.txt
git add settings.txt
git commit -q -m "Add settings"
printf "mode=local\n" >> settings.txt
printf "temporary note\n" > scratch.txt
echo "Before stash:"
git status --short
git stash push -u -m "wip: settings and scratch file"
echo "After stash:"
git status --short
git stash apply
echo "After apply:"
git status --short
echo "scratch.txt content:"
cat scratch.txtלפני ה־stash תראו גם שינוי בקובץ קיים וגם קובץ חדש: בערך M settings.txt ו־?? scratch.txt. אחרי ה־stash סביבת העבודה נקייה. אחרי git stash apply, שני השינויים חוזרים, כולל הקובץ החדש. הפלט של cat scratch.txt יהיה temporary note.
cherry-pick: להעביר commit בודד מענף לענף
git cherry-pick לא “מעביר” commit במובן של גזירה והדבקה. הוא לוקח את השינוי שבוצע ב־commit מסוים ומייצר commit חדש בענף הנוכחי. בדרך כלל ההודעה נשמרת, אבל מזהה ה־commit יהיה שונה, כי ההורה שלו שונה.
הדוגמה הבאה יוצרת ענף feature, מבצעת בו שני commits, ואז מעבירה רק את הראשון אל main.
#!/usr/bin/env bash
set -e
repo=$(mktemp -d)
cd "$repo"
git init -q
git config user.name "Demo User"
git config user.email "[email protected]"
git checkout -q -b main
printf "invoice\n" > app.txt
git add app.txt
git commit -q -m "Add base app file"
git checkout -q -b feature
printf "tax label\n" >> app.txt
git add app.txt
git commit -q -m "Add tax label"
pick_hash=$(git rev-parse HEAD)
printf "debug note\n" >> app.txt
git add app.txt
git commit -q -m "Add debug note"
git checkout -q main
git cherry-pick "$pick_hash"
echo "Current file:"
cat app.txt
echo "Recent commits:"
git log --oneline -3בסיום, הקובץ app.txt בענף main יכיל את invoice ואת tax label, אבל לא את debug note. זה בדיוק היתרון של cherry-pick: אפשר לבחור commit יחיד בלי למזג את כל הענף.
התרחיש הקלאסי: stash ואז cherry-pick
נניח שאתם על main עם שינוי מקומי, אבל צריכים להביא commit מענף hotfix. אם תנסו לעבור ענף או לבצע cherry-pick בזמן שיש שינויים מתנגשים, Git עשוי לעצור. הסדר הבטוח הוא:
- בודקים מצב:
git status --short. - שומרים עבודה זמנית:
git stash push -u -m "wip before cherry-pick". - מבצעים את ה־cherry-pick:
git cherry-pick COMMIT_HASH. - מריצים בדיקות או לפחות בודקים קבצים רלוונטיים.
- מחזירים עבודה:
git stash apply. - אם הכול תקין, מוחקים את ה־stash:
git stash drop.
הדוגמה הבאה מדגימה את כל הרצף בסביבת בדיקה. היא מיועדת ל־Linux/macOS עם bash:
#!/usr/bin/env bash
set -e
repo=$(mktemp -d)
cd "$repo"
git init -q
git config user.name "Demo User"
git config user.email "[email protected]"
git checkout -q -b main
printf "version=1\n" > config.txt
git add config.txt
git commit -q -m "Add config"
git checkout -q -b hotfix
printf "safe=true\n" >> config.txt
git add config.txt
git commit -q -m "Add safe flag"
hotfix_hash=$(git rev-parse HEAD)
git checkout -q main
printf "local_note=unfinished\n" > local.txt
git stash push -u -m "wip: local note before hotfix"
git cherry-pick "$hotfix_hash"
git stash apply
echo "config.txt:"
cat config.txt
echo "local.txt:"
cat local.txtהפלט הצפוי יראה ש־config.txt כולל גם version=1 וגם safe=true, ובמקביל local.txt חזר עם local_note=unfinished. כלומר, ה־hotfix נכנס לענף, והעבודה המקומית לא נעלמה.
איך למצוא את ה־commit הנכון ל־cherry-pick
הדרך הפשוטה היא לעבור לענף שבו נמצא השינוי ולהציג היסטוריה קצרה:
git log --oneline --decorate -10חפשו את הודעת ה־commit המתאימה, העתיקו את המזהה הקצר שמופיע בתחילת השורה, ואז חזרו לענף היעד. אם אתם לא בטוחים מה יש בתוך commit מסוים, בדקו אותו לפני הפעולה:
git show --stat COMMIT_HASHכדי לראות את התוכן המלא של השינוי:
git show COMMIT_HASHאל תעשו cherry-pick לפי תחושת בטן. אם ההודעה היא fix stuff, בדקו את הקבצים. הרבה טעויות קורות כי commit אחד כולל גם תיקון חשוב וגם שינוי ניסיוני לא קשור.
קונפליקטים: מה עושים כש־Git עוצר באמצע
קונפליקט ב־stash או ב־cherry-pick אינו אסון. הוא אומר ש־Git לא יודע לחבר לבד שתי גרסאות של אותו אזור בקובץ. התהליך דומה:
- מריצים
git statusורואים אילו קבצים בקונפליקט. - פותחים את הקבצים ומחפשים סימונים כמו
<<<<<<<,=======,>>>>>>>. - משאירים את התוכן הנכון ומוחקים את סימוני הקונפליקט.
- מריצים
git add FILE_NAME. - אם זה cherry-pick:
git cherry-pick --continue.
אם הסתבכתם במהלך cherry-pick ורוצים לחזור למצב שלפני הפעולה, השתמשו ב־git cherry-pick --abort. זה לא מוחק commits קיימים; זה מבטל את פעולת ה־cherry-pick שלא הושלמה.
טעויות נפוצות והודעות שגיאה אמיתיות
error: Your local changes to the following files would be overwritten by checkout
ההודעה המלאה תיראה בערך כך:
error: Your local changes to the following files would be overwritten by checkout:
app.txt
Please commit your changes or stash them before you switch branches.
Abortingהמשמעות: יש שינוי מקומי שייפגע אם Git יעבור ענף. הפתרון: אם זה שינוי זמני, הריצו git stash push -u -m "wip before switching branches". אם זה שינוי מוכן, בצעו commit מסודר. אל תשתמשו ב־git checkout -f בלי להבין שהוא עלול למחוק שינויים מקומיים.
No local changes to save
זו לא בדיוק שגיאה, אלא הודעה מ־Git:
No local changes to saveהיא מופיעה כשמריצים git stash ואין ל־Git מה לשמור. בדקו עם git status --short. אם יש קבצים חדשים שמופיעים כ־??, השתמשו ב־git stash push -u. אם גם שם אין כלום, כנראה שסביבת העבודה באמת נקייה.
fatal: bad revision
בעת cherry-pick ייתכן שתראו:
fatal: bad revision 'abc123'המשמעות: Git לא מזהה את מזהה ה־commit שסיפקתם. אולי העתקתם תו חסר, אולי אתם בריפוזיטורי הלא נכון, ואולי הענף שמכיל את ה־commit לא קיים אצלכם מקומית. בדקו עם git log --oneline --all --decorate. אם אתם עובדים מול remote, ודאו שהמידע המקומי מעודכן לפני שאתם מחפשים את ה־commit.
error: could not apply
ב־cherry-pick עם קונפליקט, תראו הודעה בסגנון:
error: could not apply 1a2b3c4... Add tax label
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".הפתרון הוא לא להריץ שוב cherry-pick. קודם פותרים את הקונפליקט בקבצים, מריצים git add, ואז git cherry-pick --continue. אם החלטתם שהפעולה לא נכונה, הריצו git cherry-pick --abort.
הבדלים קטנים שעושים סדר גדול
stash applyלא מוחק את ה־stash — טוב לניסיון זהיר.stash popכן מנסה למחוק — נוח, אבל פחות זהיר.cherry-pickיוצר commit חדש — אל תצפו לאותו hash.- לא חייבים לשמור הכול ב־stash אחד — אפשר לתת הודעות ברורות ולנהל כמה stashes.
- קונפליקט אינו כישלון — זו נקודת החלטה ידנית.
שאלות שקוראים באמת שואלים
האם stash נשמר גם אחרי סגירת הטרמינל?
כן. stash נשמר בתוך ריפוזיטורי Git, לא בחלון הטרמינל. אם תסגרו ותפתחו מחדש, git stash list עדיין יציג אותו, כל עוד לא מחקתם אותו.
אפשר לעשות cherry-pick לכמה commits?
כן, אבל בזהירות. אפשר להריץ git cherry-pick HASH1 HASH2, או טווח commits, אבל במדריך הזה התמקדנו ב־commit בודד כי זה התרחיש הבטוח והנפוץ ביותר. כשמעבירים כמה commits, חשוב להבין את הסדר והתלויות ביניהם.
מה עדיף: merge או cherry-pick?
אם אתם רוצים להביא ענף שלם, לרוב merge מתאים יותר. אם אתם צריכים שינוי נקודתי מענף אחר, cherry-pick מתאים. שימוש מוגזם ב־cherry-pick עלול ליצור היסטוריה מבלבלת, במיוחד אם אותם שינויים מגיעים אחר כך גם דרך merge.
האם stash מתאים לקוד חשוב?
רק לזמן קצר. אם הקוד חשוב, עדיף commit בענף עבודה. stash מצוין להפסקה רגעית, אבל הוא פחות גלוי, פחות מתועד, וקל לשכוח מה יש בו. אפשר לראות תוכן של stash עם git stash show -p stash@{0}.
סיכום מעשי
git stash ו־git cherry-pick הם שילוב חזק כשצריך לעבוד נקי בלי להפוך שינוי קטן לפרויקט גדול. שומרים עבודה זמנית בצד, מביאים commit מדויק, בודקים שהכול תקין, ואז מחזירים את העבודה המקומית.
הכלל החשוב הוא לא למהר: לפני כל פעולה בדקו git status, תנו הודעות ברורות ל־stash, ודאו שאתם בוחרים את ה־commit הנכון. עם כמה הרגלים פשוטים, הפקודות האלה מפסיקות להיות “פקודות חירום” והופכות לכלי עבודה יומיומי, יציב וברור.


