מה ההבדל בין git rm cached ל git reset
פוסט זה כולל טיפ קצר לעבודה יעילה יותר עם Git.
בשביל להבין את גיט לעומק אני ממליץ על קורס גיט שלנו כאן באתר.
בקורס תלמדו איך גיט עובד מתחת למכסה המנוע ואיך להשתמש בו בצורה יעילה מהבסיס ועד לנושאים המתקדמים.
הגיעה אליי שאלה מעניינת הבוקר במייל וחשבתי לשתף את התשובה כאן לטובת כולם. והשאלה: מה ההבדל בין הפקודה git rm --cached
לבין הפקודה git reset
, מתי אשתמש בכל אחת?
הדבר הראשון שצריך לזכור הוא שקומיט כולל Snapshot של הפרויקט, כלומר אפשר לחשוב עליו בתור עותק של כל הקבצים והתיקיות שבפרויקט. עד שנוצר קומיט יש לנו תיקיה זמנית שנקראת Staging Area אליה אפשר להוסיף וממנה אפשר למחוק קבצים. ברגע שנרגיש מוכנים נפעיל git commit
ואז ה Staging Area יהפוך ל Commit Object ויישמר במאגר הגיט לעולמי עולמים. ה Staging Area אגב לא יימחק וימשיך לשמור את כל הקבצים והתיקיות כמו שהם היו בקומיט האחרון.
הפקודה git add לוקחת קובץ מתיקיית העבודה ומעתיקה אותו לאותה תיקיה זמנית של "הכנה לקומיט" שקראתי לה Staging Area. הפקודה git reset לוקחת קובץ מהריפוזיטורי ומעתיקה אותו לאותה תיקיה זמנית. לכן אפשר לחשוב על שתי פקודות אלה בתור הפכים. נכין רגע מאגר לדוגמא:
$ mkdir demo
$ cd demo
$ git init
$ echo one > demo.txt
$ git add demo.txt
$ git commit -m 'commit 1'
אז כשאני יוצר קובץ חדש בתיקיית העבודה אני יכול להשתמש ב git add כדי להוסיף אותו לתיקיה הזמנית:
$ echo two > two.txt
$ git add two.txt
$ git ls-files --stage
100644 5626abf0f72e58d7a153368ba57db4c673c0e171 0 demo.txt
100644 f719efd430d52bcfc8566a43b2eb655688d38871 0 two.txt
או בפקודה git reset כדי להעתיק את הגירסא מהריפוזיטורי לתיקיה הזמנית מה שיגרום למחיקת הקובץ משם:
$ git reset two.txt
$ git ls-files --stage
100644 5626abf0f72e58d7a153368ba57db4c673c0e171 0 demo.txt
בכל מקרה מהלך זה לא השפיע על הקבצים בתיקיה הנוכחית שלי או במאגר. כל מה שאני עושה זה בוחר איזה קבצים ייכנסו לקומיט הבא.
לעומתה הפקודה git rm
הרבה יותר דומה לפקודה git add
, רק שבעוד ש git add
מעתיקה קובץ מתיקיית העבודה ל Staging Area, תפקיד הפקודה git rm
הוא להעתיק את ה"אין קובץ", כלומר למחוק קובץ מה Staging Area.
נזכור שהדרך הרגילה שלנו להוציא קובץ מה Staging Area היא לדרוס את הקובץ ולהחליף אותו בגירסא ששמורה בריפוזיטורי, וזה מה שעושה git reset. אבל אם אנחנו רוצים למחוק קובץ לחלוטין זה לא באמת יעזור להעתיק את הגירסא מהריפוזיטורי. במילים אחרות בדוגמא שלנו הקובץ demo.txt
נמצא ב Staging Area וגם ב Repository. אם אפעיל git reset עליו לא יקרה כלום:
$ git ls-files --stage
100644 5626abf0f72e58d7a153368ba57db4c673c0e171 0 demo.txt
$ git reset demo.txt
$ git ls-files --stage
100644 5626abf0f72e58d7a153368ba57db4c673c0e171 0 demo.txt
בכל מקרה הוא נשאר ב Staging Area וייכנס לקומיט הבא. הפקודה git rm היא הדרך שלנו להעתיק את העובדה שהקובץ לא קיים אל ה Staging Area. שימו לב להשפעה שלה על המאגר שלנו:
$ git rm demo.txt
$ git ls-files --stage
$ ls
two.txt
עכשיו ה Staging Area ריק. מאחר והקומיט הבא שיווצר הוא בסך הכל עותק של ה Staging Area ברגע יצירת הקומיט, הקובץ demo.txt לא יהיה חלק מהקומיט הבא. הפעם לא לקחנו את הגירסא מהריפוזיטורי והעתקנו אותה ל Staging Area, אלא בדיוק כמו עם add לקחנו את הגירסא מתיקיית העבודה והעתקנו אותה ל Staging Area, אבל עשינו את זה אחרי שמחקנו את הקובץ מתיקיית העבודה.
ומה לגבי git rm --cached
? אם הגעתם עד לפה הסיפור שלו הוא הכי פשוט מכולם. לפעמים אנחנו תקועים עם קובץ או תיקייה שאנחנו רוצים להוציא מהריפוזיטורי אבל להשאיר אצלנו בתיקיית העבודה. דוגמא קלאסית היא תיקיית node_modules
: בטעות הוספנו תיקיה זו למאגר ועכשיו אנחנו רוצים להוציא אותה, אבל התיקיה כן עוזרת לי בעבודה השוטפת ולכן אני לא רוצה למחוק אותה מהדיסק. הפעלת git rm -r node_modules
לא באה בחשבון כיוון שהיא תביא למחיקת התיקיה מהדיסק. אבל, אם נוסיף את --cached
נקבל גירסא של git rm
שלא מוחקת את הקובץ או התיקיה מהדיסק אלא רק מה Staging Area.
בחזרה למאגר הדוגמא נחזיר את הקובץ demo.txt מהריפוזיטורי עם:
$ git restore -s HEAD demo.txt
$ git ls-files --stage
100644 5626abf0f72e58d7a153368ba57db4c673c0e171 0 demo.txt
ועכשיו נמחק אותו רק מה Staging Area בלי למחוק אותו מתיקיית העבודה:
$ git rm --cached demo.txt
$ ls
demo.txt two.txt
$ git ls-files --stage