
- Published on
איך נכון לעבוד בבראנצ' הפרטי שלכם?
- Authors

- Name
- אביב אביטן
- in/avivavitan

נתחיל מזה שיש בGIT בעיני שתי רמות: פרויקטואלית ואישית.
ברמה הפרויקטאלית יש שתי שיטות מרכזיות, TRUNK BASED DEVELOPMENT וGITFLOW. הפוסט הזה לא נוגע אליהם כלל.
אנחנו נתרכז ברמה האישית - לא משנה באיזו שיטה פרוייקטיאלית נעבוד, בכל השיטות המוזכרות אנחנו נדרשים בימים כתיקונם פשוט למזג קוד מהבראנצ' האישי שלנו לבראנצ' כללי יותר (נניח מאסטר לשם פשטות), דרך PULL REQUEST.
בראנצ'ים אישיים אמורים להיות קצרי מועד. ככל שהזמן עובר אנו ניצבים בפני שתי אפשרויות לשאלה כיצד נתיישר לשינויים שקרו במאסטר, אותם נרצה להביא אותם לבראנצ' פיתוח שלנו. אני אכנה את שתי האפשרויות למען הפשטות: שיטת הREBASE ושיטת הMERGE.
REBASE
בשיטת הREBASE - יישור לשינויים מתרחש כאילו יצרנו הבראנצ' ברגע זה מתוך המאסטר. זו מתרחשת ע"י הפעולה GIT REBASE ORIGIN MASTER. בסופו הבראנצ' יכיל רק קומיטים של השינוי שלנו בלבד (קרי ללא MERGE COMMITS). כלומר ככל שהמאסטר מתקדם, אנחנו ניקח את כל קומיטים שיצרנו ונעביר אותם על בסיס הHEAD של המאסטר המעודכן. בשיטה זו אנחנו נמנעים מMERGE COMMITS שעליהם נפרט בהמשך מדוע ראוי להימנע מהם.
MERGE
שיטת הMERGE היא כנראה השיטה הנפוצה ביותר. היא מתרחשת ע"י ביצוע הפעולה GIT MERGE ORIGIN MASTER. פעולה זאת תביא לבראנצ' פיתוח שלנו את כל שינויי הקוד מהמאסטר (אלו שלא נכללו בבראנצ' שלנו) אבל נקבל אותם כקומיט מיוחד שאורז את כל השינויים האלה לתוך הבראנצ' שלנו. אותו הקומיט שנכנס לבראנצ' שלנו הוא הMERGE COMMIT שהזכרנו קודם והייחוד שלו הוא בשני דברים:
- הוא יכיל את כל הקוד מהמאסטר, מכלל הקומיטים החדשים + תיקוני הקונפליקטים שנעשו בזמן הmerge
- חשוב מכך, בעל הצבעה לשתי אבות ולא לאחד (הצבעת לקומיט האחרון בברנאצ' הפרטי שלנו והצבעה לקומיט האחרון בראנצ' מאסטר).
שתי השיטות מקובלות מאוד בתעשייה. למעשה לשתי השיטות יש חסידים מושבעים. אבל צריך לעמוד על ההבדלים ונמנה שלושה עיקריים ונציג שיטת עבודה שנהנת מהיתרונות והחסרונות של כל אחת.
הבדל 1: תהליך יישור למאסטר

גם אם "הסיפור" של הקומיטים נשמר, ייתכן שעדיין חסר קוד. נניח למשל, שבשינוי שלנו הוספנו לוגים לפונקציות במודול. הREBASE הכניס קוד חדש של המודול, אבל לא כולל הלוגים אותם הוספנו בבראנצ' הפרטי שלנו. במקרה הזה ליצור קומיט חדש עם התיקון ואז להשתמש בREBASE אינטראקטיבי כדי להכניס את הלוגים ולמזג את הקומיט החדש בקומיט הישן המתאים. להלן איך נראה חלון של REBASE אינטרקטיבי: רואים רשימת קומיטים, שאפשר לשנות את הסדר שלהם ולמזג קומיטים ע"י השימוש במילה השמורה FIXUP או SQUASH במקום PICK.

כעת נעבור לשיטת הMERGE. בשיטה זו התחלנו עם N קומיטים ונסיים עם N+1 לכל יישור כאשר הקומיט ה+1 הוא הMERGE COMMIT. ועכשיו נניח בדומה למקרה הקודם, בהוספת הלוגים, שיש שינוי בקוד החדש שצריך להיות כחלק מקומיט ישן יותר. בדומה, נצטרך ליצור קומיט חדש שמוסיף את התיקון, אך אחרי שנעשה את השינוי לא נוכל למזג אותו לקומיט הישן יותר באמצעות GIT REBASE אינטרקטיבי.
מדוע? ברגע שנכנס MERGE COMMIT לברנאצ' שלך - אי אפשר לשנות יותר את העץ ו\או את הסידור קומיטים של הבראנצ'. ייתכן גם שאותו שינוי קוד היה נעשה כחלק מפתירת קונפליקטים בזמן היישור. במקרה זה הקומיט הישן שלנו עדיין לא יכיל את הלוגיקה הנוספת שנכנסה בMERGE COMMIT עצמו ולא בקומיט המתאים לכך. חוסר האפשרות לערוך קומיטים לפני הMERGE COMMIT הוא חסרון שפוגע בשליטה שלנו על מבנה הבראנצ' הפרטי שלנו.

הבדל 2: ניהול קונפליקטים
בשיטת הREBASE, כל קומיט בברנאצ' שלנו מוכל לפי סדר על הMASTER החדש. כאשר יש קונפליקט, צריך לפתור אותו כאילו אנו כותבים את הקומיט הנוכחי, בהתעלמות מהמצב הסופי של הקוד. אם למשל יש קומיט C1 ששינה קטע קוד מסויים, אך קיים גם קומיט C2 מאוחר יותר ששינה את אותו קטע קוד, עלינו להיות מודעים לכך שאנחנו צריכים לשנות לפי C1 ולא לפי C2. לטעויות אין מקום, כל טעות ביישור תוביל לעוד ועוד קונפליקטים בקומיטים הבאים ותגרום לתהליך היישור להיות לא ישים. דבר זה עלול להקשות מאד על התיישרות לMASTER.
בשיטת הMERGE, אין לנו שיקול כזה. בזמן קונפליקט אנחנו מחפשים את המצב הסופי הראוי של הקוד. קרי, לוקחים מTHEIRS את הקוד "החדש" ומוסיפים אליו את הקוד שלנו. בסיום הקונפליקטים יווצר לנו הMERGE COMMIT בראש הבראנצ' שלנו שיכיל את השינויים. דבר זה יותר אינטואיטיבי למפתח. בנוסף יש סלחנות כלפי טעויות: אפשר ליצור קומיט חדש שמתקן את הטעות שנעשה בזמן קונפליקט.
בשיטה הREBASE אנחנו נוכל ליהנות מיתרון ההשוואה של הקונפליקט רק למצב הקוד הסופי - רק אם טרום היישור איחדנו את כל הקומיטים לקומיט יחיד. דבר שמתרחש רק כאשר סיימנו את השינוי שלנו ואנחנו לפני מיזוגו למאסטר.
הבדל 3: איך ממזגים את השינוי בחזרה למאסטר
בשיטת הREBASE - כאשר נסיים את העבודה נעשו REBASE אינטרקטיבי ונמזג את כל השינויים עד הקומיט הראשון. כותבים הודעת קומיט יפה שמתארת כלל השינוי ולוחצים על REBASE בחזרה לMASTER. למעשה כיווצנו את השינוי לקומיט בודד ושמנו אותו מעל הHEAD של המאסטר העדכני. המוטיבציה לכך היא שנרצה שהMASTER שלנו תמיד יראה לינארי, קומיטים של פיצ'רים מלאים, ללא כל MERGE COMMITS. בשיטת הREBASE הדבר הזה ודאי מבחינת פרטיקה ותאוריה.

בשיטת הMERGE - יש שתי אופציות עיקריות של MERGE-ים: REGULAR וSQUASH. בתרחיש שלנו, אנחנו נשתמש כמעט תמיד ב SQUASH. בREGULAR MERGE נוצר לנו MERGE COMMIT וזה יבטיח לנו שלא יהיה עץ MASTER לינארי. במקרה שלנו, סביר שלא נראה לשמור קומיטים בודדים מתהליך הפיתוח, אלא רק קומיט שמתאר כל הפיצ'ר, לכן REGULAR MERGE תהיה בחירה חריגה. לעומת זאת האופציה השנייה, SQUASH AND MERGE, ממזגת את כל הבראנצ' שלנו לקומיט בודד ומכניסה אותו למאסטר ללא MERGE COMMIT (במקרה כזה הקומיט שנוצר מפעולת הSQUASH AND MERGE יכיל הצבעה רק לאב הישיר שלו במאסטר)

מה אני ממליץ לכם כחלק מהכתיבה של הדברים האלה?
- אם על הבראנצ' פיתוח הזה עובד יותר מאדם אחד, תעבדו רק בשיטת הMERGE. במקרה כזה GIT PUSH --FORCE אחד לא במקום ואתם עלולים למחוק לקולגה שלכם את כל העבודה.
- בואו נתחיל מהאמת הפשוטה- אתם יכולים לעבוד ולעשות קומיטים עם הערות של WIP בלי שום משמעות ובסוף למזג עם SQUASH AND MERGE, זה יעבוד. אם אתה עובדים ככה - לקומיטים שלכם אין אפילו משמעות סמלית בעינכם, אלא רק כדרך לוודא שהקוד שלכם שמור במידה והמחשב שלכם יעלה בלהבות. במקרה כזה תעבדו עם השיטת הMERGE ותדאגו לעשות SQUASH AND MERGE במיזוג לMASTER עם הודעה טובה. חובה SQUASH AND MERGE כמו שהסברנו, כי נרצה שכל הפיצ'ר בבראנצ' MASTER יהיה בקומיט יחיד ובמיוחד אם הקומיטים שלכם לא מכילים שום מידע אינפורמטיבי.
- אם אתם עובדים בצורה יותר מבנית ודואגים לקומיטים מסודרים תשתמשו בשיטת הREBASE, ולרב היא תעבוד לכם בלי בעיות. אך אם בכל זאת מתגלה שיש לכם שינוי עם נטייה לקונפליקטים רבים בתהליך היישור (למשל שינוי ריפקטורינג), עדיף לחסוך את עוגמת הנפש של השיטת הREBASE ולעבור לשיטת הMERGE באמצע. קחו בחשבון אחרי המעבר לשיטת הMERGE תהיו מאד מגובלים בשליטה על העץ קומיטים שלכם. כמו מקודם, בסוף לדאוג לבצע SQUASH AND MERGE