ענפים וניתוחים

ערימות ענפים

ערימה היא שרשרת של ענפים שכל אחד מהם נבנה על זה שמתחתיו: main → api → ui. סקירה של שלוש בקשות משיכה קטנות עדיפה על סקירה של אחת ענקית.

ערימת ענפים

‏Gitcito מצייר אותה כמסלול: ענף התחלה למעלה, ואז תחנה אחת לכל שכבה. ה־PR של כל תחנה מכוון לתחנה שמעליה, והתחנה הראשונה נוחתת על ענף ההתחלה. תחנה מציגה את הקומיטים שלה, האם היא זקוקה ל־restack, ואחרי השליחה גם את מספר ה־PR.

עריכת המסלול

שום דבר לא רץ עד שתלחצו על החלה. בחירת ענף, הזזת תחנה, הסרתה מהמסלול — כל אלה עורכים רשימה על המסך. הפעולה האמיתית עושה rebase לענפים ומוציאה אותם ב־checkout, וזה לא דבר שקליק סקרן אמור לעשות. כשהמסלול נקרא נכון, להחיל את המסלול מבצע אותו כצעד אחד הפיך; לבטל מחזיר את השרטוט למה שהמאגר באמת אומר.

המסלול משורטט בסדר המיזוג: הענף העליון ממוזג אל זה שמתחתיו, עד לענף שעליו הערימה נוחתת.

פקד מה הוא עושה
שדה ההתחלה היכן הערימה נוחתת. שנו אותו וכל השרשרת תחובר מחדש לענף החדש ותנוגן.
שדה של תחנה מחליף איזה ענף תופס את המיקום הזה. הענף שיוצא מהמסלול רק מנותק, לעולם לא נמחק.
↑ / ↓ מזיז תחנה מקום אחד לאורך המסלול.
✕ מוציא את התחנה מהמסלול; השכנות מתחברות.
הוספת תחנה בחרו ענף שכבר יש לכם והוא יצטרף לראש המסלול, או הקלידו שם שאינו קיים — הוא ייווצר על קצה התחנה האחרונה ותעברו אליו.
כפתור החץ עובר לאותה תחנה.

כל השדות הם השלמה תוך כדי הקלדה: הקלידו כדי לסנן, ↑/↓ ו־Enter כדי לבחור, ומה שתקלידו נחשב גם אם אינו ברשימה — כך שהפניה מרוחקת כמו origin/main מתאימה כענף התחלה.

מתחת למכסה כל העריכות האלה הן אותה פעולה: המסלול כולו, מוחזר בבת אחת. לכן מחווה אחת היא ביטול אחד (⌘Z) ולא שובל של קישורים שיושמו למחצה.

מה עולה שינוי מסלול

כל דבר שמשנה את הסדר — החלפה, הזזה, התחלה אחרת — מנגן מחדש את השרשרת: הקומיטים של כל תחנה עוברים rebase על הבסיס החדש שלה. שתי תחנות שנוגעות באותן שורות לא יתחלפו בלי אדם, וכשזה קורה לא קורה כלום: כל העריכה מתגלגלת אחורה — קצוות, קישורי הורה וה־rebase שנעצר באמצע — ו־Gitcito נוקב בשם שתי התחנות המתנגשות. תפריט שנגעתם בו בטעות לא אמור להשאיר אתכם באמצע rebase.

Restack הוא החצי השני של העסקה: זהו rebase שביקשתם בשמו, ולכן הוא כן עוצר בהתנגשות ומוסר את מסך ההתנגשויות — וזו גם הדרך להשיג את הסידור ש־Gitcito סירב לו: פתרו שם, ואז הזיזו את התחנה.

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

דחיפת הכול

דחיפת הכול דוחפת כל שכבה עם --force-with-lease ועוצרת שם — gh stack push בלי לפתוח דבר. שליחת הערימה כ־PR למטה עושה את אותה דחיפה ואז את עבודת ה־PR; השתמשו בדחיפת הכול כשאתם רוצים את הענפים במרוחק אבל עדיין לא בביקורת.

שליחת הערימה כבקשות משיכה משורשרות

שליחה שואלת קודם: כמה pull requests ייפתחו, כמה יכוונו מחדש, באיזה מרוחק, ואת שורת ה־ענף → בסיס של כל אחד — פתיחת PR היא פומבית וקשה לביטול. מקטע הניווט שנכתב בכל גוף הוא מה שהופך את השרשרת לגלויה ב־GitHub, שאין לו מושג של ערימה.

השליחה מתרחשת במסך משלה: קודם התוכנית, אחר כך ההתקדמות שלב אחר שלב, ובסוף הקישורים לכל pull request ולערימה עצמה.

שליחת ערימה

שליחת הערימה כבקשות משיכה עושה בלחיצה אחת את מה שכלי ערימות גובים עליו כסף:

  1. דוחפת כל רמה עם --force-with-lease (ענפים טריים סובלים אותו, ענפים אחרי ריסטאק זקוקים לו).
  2. פותחת בקשת משיכה לכל רמה שחסרה לה אחת — כל אחת מבוססת על ענף ההורה שלה, לא על main, כך שכל סקירה מציגה רק את הקומיטים שלה. הכותרת והתיאור נלקחים מהקומיטים של הרמה עצמה.
  3. מכוונת מחדש כל בקשת משיכה קיימת שהבסיס שלה נסחף.
  4. כותבת מקטע ניווט בערימה לתוך גוף כל בקשת משיכה, כך שסוקר בכל רמה יכול לראות את השרשרת כולה ואת מקומה של הבקשה הזאת בתוכה.

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

כשבקשת המשיכה התחתונה מוזגה, אותו כפתור מנקה אחריה: הילד של הרמה הממוזגת מוסב אל הענף הראשי, המעקב אחרי הרמה מבוטל, הענף המקומי שלה נמחק (בבטחה — מוכח שהענף הראשי מכיל אותו), השרשרת עוברת ריסטאק וכל בקשת משיכה שנותרה מכוונת מחדש. מזגו מלמטה למעלה, לחצו על שליחה, וחזרו על כך.

ב־GitHub זה גם הופך לערימה אמיתית

בסיסים משורשרים הם מה שכל אחסון מבין, וב־GitLab, Bitbucket ו־Azure DevOps זה כל מה שיש. ל־GitHub יש יותר: מאז ההצצה ל־stacked pull requests, ערימה היא אובייקט בצד השרת. ברגע שה־pull requests קיימים, Gitcito רושם אותם כערימה — מלמטה למעלה — ואתם מקבלים את מפת הערימה בממשק ה־PR, rebase מדורג שרץ בצד השרת, ומיזוג ב־PR העליון שמנחית גם את כל השכבות שמתחתיו.

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

ריסטאק

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

מגבלות

  • השליחה עובדת בינתיים רק על GitHub (יצירה עובדת בכל ארבעת המארחים, אבל כיוון מחדש ועדכון גוף הבקשה דורשים את ה-API של GitHub).
  • ניקוי מיזוג התחתית מזהה מיזוגי merge ומיזוגי rebase לפי יחסי אבות, ומיזוגי squash — בשאילתה ל-GitHub אם בקשת המשיכה של הענף נחתה. כך שעם אסימון GitHub כל סגנון מיזוג מנוקה. במארחים אחרים, או בלי אסימון, רמה שמוזגה ב-squash עדיין דורשת ביטול מעקב ידני. וגם עשו fetch תחילה — בדיקת האבות קוראת את הענף הראשי כפי שהיה ב-fetch האחרון שלכם.
  • מקטע הערימה בגוף בקשת המשיכה מתוחזק בין סמנים נסתרים — התיאור שלכם שמעליו נשמר.
  • סידור מחדש והחלפת גזע כותבים היסטוריה מחדש בכל שכבה שהם נוגעים בה. הענפים שלכם, ושכבות שלא נדחפו אינן עולות דבר, אבל שכבה שכבר בביקורת תקבל דחיפה כפויה בשליחה הבאה.
  • שכבה זזה מקום אחד בכל פעם. שתי החלפות הן שני rebase, ועצירה באמצע היא מצב קריא; גרירה שנוחתת שלושה מקומות משם — לא.
  • תחנה עוברת rebase, ולכן הענף שעליו הערימה נוחתת אינו גם תחנה בה, וגם לא ענף מוגן (main ו־master, אלא אם שיניתם את הרשימה). שניהם נדחים במקום לכתוב מחדש בשקט היסטוריה משותפת.
  • לפני שנפתח משהו, השליחה שואלת את המרוחק אילו ענפים באמת הגיעו, ומונה בשם את אלה שלא. על head חסר GitHub עונה ב"Validation Failed" יבש, שלא מועיל לאיש. גם הענף שעליו הערימה נוחתת נבדק: אם הוא קיים רק מקומית, השליחה תציע לדחוף אותו ולהמשיך.

היכן הקישורים חיים

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

ראו גם: ריבייס אינטראקטיבי · אירוח ובקשות משיכה

שיפור התרגום הזה ב־GitHub