פוסט מהבלוג בנושא: מעיכת קומיטים עם Merge Squash

היי @ynonp ,

אני חושב שיש לך שתי טעויות בפוסט הזה מהבלוג:

בדוגמה בפוסט יש סה"כ 7 קומיטים לפני המיזוג:

  • קומיטים 1 ו-2 נוצרו ב-master אך נמצאים גם ב-dev.
  • קומיטים 3 ו-4 נוצרו ב-master אחרי הפיצול של ענף dev ולכן קיימים רק ב-master.
  • קומיטים: 5, 6, 7 שנוצרו וקיימים ב-dev בלבד.

בדרך הראשונה המוצגת, כתוב:

  1. נעבור לענף dev
  2. נחזיר את HEAD אחורה ל C4 בלי לשנות את הקבצים בתיקיית העבודה (עם פקודת reset)
  3. נעשה קומיט אחד שיכלול את כל הקבצים בתיקיית העבודה

שים לב שכתוב “נחזיר את HEAD אחורה ל C4” אבל אנחנו בענף dev שהקומיט הזה לא היה חלק ממנו.
ביצוע הפעולות הנ"ל עלול לבטל שינויים מקומיטים 3 ו-4, לדוגמה מחוק קבצים שנוספו בהם ולא קיימים בקומיט 7 (ובכול ענף dev).
לכאורה אלו אמורים להיות השלבים הנכונם:

  1. נעבור לענף dev
  2. נחזיר את HEAD אחורה ל-c2 ע"י reset
  3. נעשה קומיט אחד שיכלול את כל הקבצים בתיקיית העבודה.
  4. נעבור לענף master
  5. נבצע מיזוג של dev

בדרך השנייה חסר שלב (וכנראה גם לא מוזכר השלב הראשון בו עוברים לענף master).
לפחות בהתקנה רגילה של גיט, אחרי הרצת פקודת git merge --squash dev אמורה להתקבל הודעה שמספרת לנו מה קרה ובמיוחד מה לא קרה - לא בוצע קומיט (או מיזוג):

git merge --squash dev
Automatic merge went well; stopped before committing as requested
Squash commit -- not updating HEAD

כך שכרגע השינויים של המיזוג ממתינים באינדקס לביצוע קומיט (כשאפשר לראות אותם עם פקודת git status).
הפלט האחרון של git log בדוגמה בפוסט מדוייק ומראה רק את אבעת הקומיטים הראשונים שכבר היו ב-master.
השלב האחרון חסר והוא ביצוע הקומיט של “המיזוג המעוך”.
אחריו הלוג יראה כך (הוספתי לתצוגה הלוג גם את ענף dev):

λ git log --graph --oneline --all
* 37d431c (HEAD -> master) Squashed commit of the following: c5, c6, c7
* 615df2f c4
* 423ea34 c3
| * aa0dd0d (dev) c7
| * 0fdc3ff c6
| * 7de5afb c5
|/
* e04642b c2
* f7ff5de c1

הי,

נתחיל עם הנקודה הראשונה, ובוא נשאל - מה המשמעות של ״נחזיר את HEAD אחורה ל C4״ ?

אתה כותב ש C4 לא נמצא ב dev ולכן אי אפשר לחזור אליו. זה לא נכון. אפשר להשתמש ב git reset כדי להעביר את HEAD (ואת הבראנצ׳ שעליו הוא מצביע) לכל קומיט במאגר.

אתה צודק כשאתה אומר שאחרי שנעשה את זה קומיטים 5, 6 ו-7 כבר לא יהיו ״חלק מ dev״ במובן זה ש dev קודם הצביע על קומיט 7 ועכשיו הוא מצביע על קומיט 4 שהוא ישן יותר. אבל זאת בדיוק המטרה.

אני רוצה להחליף את קומיטים 5, 6 ו-7 שהיו הקומיטים במסלול dev בקומיט חדש (נקרא לו 8 לצורך הדיון) שיכיל את כל השינויים של שלושת הקומיטים האלה אבל בלי שום קשר אליהם ובלי הודעות הקומיט שלהם. זאת המשמעות של ״מעיכה״: אני מחליף כמה קומיטים בקומיט יחיד שכולל את השינויים עצמם בלי ההיסטוריה.

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

  1. ה HEAD מצביע על הענף dev
  2. הענף dev מצביע על קומיט C4
  3. קומיטים C5, C6 ו C7 ״נעלמו״ (הם עכשיו לא בשום ענף)
  4. תיקיית העבודה שלי נראית בדיוק כמו בקומיט C7 (כי שם הייתי לפני ה reset).

עכשיו כשאני אכניס את השינויים ואעשה קומיט אני מקבל קומיט יחיד C8 שכולל את כל השינויים של 5, 6 ו-7 ומחליף אותם.


בחלק השני התכוונתי בדיוק למה שכתבת. הוספתי עכשיו משפט חידוד לפוסט שיהיה יותר ברור, תודה.

לא כתבתי שאי אפשר “לחזור” ל-c4, אלא שבגלל שאינו חלק מהענף הזה, ביצוע הפעולה הנ"ל מסוכנת ולא בהכרך תבצע את מה שרצינו.
אם לדוגמה בקומיט 3 או 4 הוספנו קובץ חדש, הוא לא יהיה קיים בענף dev בכלל וכשנבצע את ה-reset ב-dev לקומיט 4 תייקת העבודה תשאר ללא הקובץ החדש. כשנבצע עכשיו קומיט למעשה נמחוק את הקובץ החדש מהמאגר.
לכאורה הפעולה הבטוחה היא לחזור עם ה-reset לקומיט המשותף האחרון לשני הענפים, לבצע קומיט ואז את המיזוג “שיראה” הסטוריה נכונה (ההורה של קומיט 8 החדש יהיה קומיט 2, כך ששינויים מקומיטים 3 ו-4 לא “ידרסו” אוטומטית כמו במקרה שקומיט 4 היה ההורה של קומיט 8).
[כמובן שבמקרים רבים, הקומיט המשותף האחרון יהיה הקומיט האחרון של master.]

בהקשר הזה כדאי להזכיר שיש אפשריות שונות לפקודה, כש-soft או mixed לא ישנו את תקיית העבודה, hard כן ישנה. לרוב אם לא כותבים במפורש את האפשרות הרצויה, mixed יהיה ברירת המחדל וישנה את המאגר ואת האינדקס, אבל לא את תיקיית העבודה.

מציע שתעדכן גם הקוד והפלט של git log שאתה מציג בסוף, כי כאמור הוא לא מציג את הקומיט ובלוג מוצג המצב לפני הקומיט וסביר שתרצה להראות את המצב הסופי.

לייק 1

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

תוקן