שאלות גיט: קומיט אחרי ריסט?

26/10/2021

שאלה- האם צריך לבצע commit אחרי reset? מה יקרה אם נעשה? מה יקרה אם לא נעשה?

תשובה- זה תלוי. והנה הפירוט.

1. שאלה ראשונה - איזה ריסט

לפעמים שאלות הן רק תירוץ בשביל להתחיל שיחה. במקום לתת לך את כל המידע ולצפות לתשובה הוגנת הם משמיטים את הפרט הכי חשוב. ל git יש 5 פקודות reset שונות שכולן נקראות באותו השם:

  1. ריסט רך (soft) שמשנה רק את HEAD אבל לא נוגע בקבצים

  2. ריסט מעורב (mixed) שמשנה רק את ה HEAD ואת ה Staging Area אבל לא נוגע בקבצים בתיקיית העבודה.

  3. ריסט קשה (hard) שמשנה את ה Staging Area ואת תיקיית העבודה, וכמובן מזיז את ה HEAD.

  4. השניים האחרונים - merge ו keep עוזרים לנו לבטל merge ובאופן כללי פחות רלוונטים לשאלה זו.

עכשיו אפשר לחזור לשאלה שלנו - האם ומתי צריך לעשות commit אחרי reset?

2. צריך - שינוי קומיטים

סוג אחד של שינויים שאנחנו עושים עם reset הוא שינוי בקומיטים עצמם. הנה לדוגמה פקודות ליצירת מאגר בתיקיה חדשה:

$ echo '# first version' > myapp.py
$ git init
$ git add .
$ git commit -m 'add first version'
$ echo '# second version' > myapp.py
$ git add .
$ git commit -m 'add second version'
$ echo '# thidr version' > myapp.py
$ git add .
$ git commit -m 'add third version'

אחריהן המאגר כולל 3 קומיטים:

b858a9e (HEAD -> master) add third version
b8c9ca2 add second version
71bc205 add first version

פקודת ההדפסה האחרונה כללה שגיאת כתיב. אם עכשיו אני אתקן את השגיאה ואפעיל קומיט מחדש יהיה לי לוג של 4 קומיטים, אבל האמת שכשאני חושב על ההיסטוריה של הפרויקט אין פה באמת סיבה ל-4 קומיטים. לעולם לא תהיה לי סיבה לחזור לגירסה עם השגיאת כתיב במילה third.

דרך קלה להחליף קומיט אחד באחר (בהנחה שלא עשיתי עדיין push) היא למחוק את הקומיט הסורר אבל להשאיר את הקבצים, ואז לבנות קומיט חדש במקומו. בשביל זה reset ואחריו commit יהיה מושלם:

$ git reset b8c9ca2
$ echo '# third version' > myapp.py
$ git commit -a -m 'third version take 2'

אחרי ה reset אני מפעיל מחדש את השינוי ואז עושה לו קומיט, והתוצאה היא הלוג הבא:

aa87b22 (HEAD -> master) third version take 2
b8c9ca2 add second version
71bc205 add first version

הקומיט עם השגיאה נעלם ובמקומו קיבלתי קומיט תקין. מה שיפה שאחרי ה reset כל הקבצים שלי נשארו במקום (גם ב soft וגם ב mixed). זה פותח את הדלת לעוד סוג של שינויים שמטרתו לאחד קומיטים. בואו ניקח את אותו מאגר ונניח שאנחנו רוצים לבטל הקומיט האמצעי ולהישאר רק עם הקומיט הראשוני והגירסה השלישית העדכנית, אז באמצעות reset נוכל לעשות את זה די בקלות:

$ git reset 71bc205
$ git commit -a -m  'final version'
$ git log --oneline

fc86355 (HEAD -> master) final version
71bc205 add first version

ושוב הייתי צריך את הקומיט אחרי ה reset כדי ליצור את הקומיט החדש במקום זה שביטלתי. אגב, בשביל לבטל את הקומיט הראשון במאגר צריך להשתמש בטריק קצת שונה וליצור ענף חדש וריק באופן הבא:

$ git branch -m master oldmaster
$ git checkout --orphan master
$ git commit -m 'initial commit with third version'
$ git branch -D oldmaster
$ git log --oneline

0690709 (HEAD -> master) initial commit with third version

מה שמשותף לכל המקרים כאן הוא שאחרי reset צריך לעשות קומיט כי המטרה היתה ליצור קומיטים חדשים במקום קומיטים שלא אהבנו.

3. לא צריך - וויתור על קומיט וחזרה אחורה בזמן

סוג שני של מקרים קורה כשאנחנו רק רוצים להזיז את ה branch בלי ליצור קומיט חדש, פשוט בשביל לחזור אחורה לגירסה ישנה יותר של הפרויקט. אני חוזר למאגר המקורי שלי:

6fbfc8c (HEAD -> master) add third version
839e784 add second version
4dd061a add first version

ועכשיו בואו נניח שהתחרטתי לגבי הגירסה השניה ואני רוצה לשכוח ממנה לגמרי. במצב כזה קל מאוד להשתמש ב git reset --hard כדי להיפטר מכל הקבצים של הקומיט ולהזיז את הענף אחורה:

$ git reset --hard 839e784

839e784 (HEAD -> master) add second version
4dd061a add first version

$ cat myapp.py
# second version

במצב כזה אין סיבה לעשות commit כי פשוט ביטלנו משהו שלא היה טוב. נקודה שקל לפספס כאן היא שברוב המקרים אתם גם לא רוצים לעשות push אחרי שינוי כזה: אנחנו לא רוצים לעדכן את השרת כי השרת אף פעם לא הכיר את הקומיט השלישי. ממילא לא מומלץ לבצע את כל הטריקים של שינויי קומיטים אחרי שעשינו push, כי מישהו אחר יכול היה להתבסס על הקומיטים שאנחנו מוחקים.

נ.ב. ההשראה לפוסט הגיעה משאלה בקבוצת טלגרם בנושא גיט. יש שם שאלות מעניינות ואנשים חכמים אז אם יש לכם טלגרם שווה להצטרף: https://t.me/Git_IL