כיצד לפתור התנגשויות מיזוג במדריך Git

מהי סוג של קונפליקט מרד ב Git?

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


דוגמא פשוטה לקונפליקט ב Git

התרשים למעלה נותן דוגמה מושלמת כיצד מתרחש קונפליקט מיזוג טיפוסי ב-Git. הענף הראשי מכיל קובץ עם הטקסט "HELLO, WORLD!". המשתמש abid מפצל את הענף הראשי ומשנה את הטקסט ל-"HELLO, CAT!". בזמן ש-abid מבצע שינויים, הענף הראשי המקורי גם הוא משתנה ל-"HELLO, DOG!". מיזוג הענפים הללו יגרום להופעת בעיית קונפליקט מיזוג ולעצירת התהליך.

הפקודה `git merge` עוסקת בעיקר בשילוב שני ענפים ופתרון אוטומטי של קונפליקטים. עם זאת, מדי פעם מופיעים קונפליקטים כאשר שני אנשים שינו את אותה שורת קוד או הסירו קבצים קריטיים שמפתח אחר עבד עליהם. Git יסמן את השינויים הללו ויעצור את תהליך המיזוג. במקרה הזה, הקונפליקט לא נפתר אוטומטית; המפתח יצטרך לבצע שינויים ידנית או להשתמש בכלים כדי לפתור את הקונפליקט.

סוגי מיזוג

Git merge ו-rebase הם שני הדרכים לשילוב התחייבויות מהענף המטרה לענף המקור. בנוסף, Git merge מבצע מיזוג מהיר או מיזוג שאינו מהיר. אם ראש הענף המטרה נמצא בענף המקור, אז כברירת מחדל, סוג המיזוג יהיה מיזוג מהיר ואם הוא חסר, אז מיזוג שאינו מהיר. Git rebase הוא סוג אחר של מיזוג שמסדר מחדש את היסטוריית ההתחייבויות של ענף המטרה.

מיזוג מהיר

כברירת מחדל, Git merge משתמש ב-fast-forward כדי לשלב קומיטים חסרים לתוך הענף היעד. למשל, הוא משמש לעדכן את הענף המקומי משרת מרוחק באמצעות הפקודה pull. Fast-forward לא יוצר בעיות קונפליקט מאחר ש-Git לא יישם אותו אם ראש הענף היעד חסר בענף המקור.

מיזוג ללא fast-forward

מיזוג ללא fast-forward נקרא גם מיזוג שלושה-כיוונים או מיזוג אמיתי. הוא יוצר קומיט חדש על הענף היעד על ידי שילוב שינויים בשני הענפים, המקור והיעד. השינויים משולבים לאחר הקומיט המשותף האחרון בשני הענפים. במקרה שלנו, זה אחרי C. סוג זה של מיזוג יגרום ל-Git להעלות קונפליקט אם הענף המקור במחלוקת עם הענף היעד. בתרשים למעלה, קומיט המיזוג (X) נוצר על ידי שילוב הענף המקור והיעד, כאשר K ו-E הם ההורים של קומיט המיזוג.

Rebase

Git rebase שונה מעט מסוגים אחרים. הוא משנה את סדר היסטוריית הקומיטים של הענף היעד. ה-rebase משלב את הענף המקור כך שהענף היעד מכיל את כל השינויים מהענף המקור, ולאחר מכן את כל הקומיטים של הענף היעד אחרי הקומיט המשותף האחרון. במקרה שלנו, הקומיט המשותף האחרון הוא C, בעוד D ו-E הם מהענף המקור. קומיט K* זהה ל-K עם מזהה קומיט שונה. במקום לקשר ל-C, הוא יקשר ל-E. בדומה למיזוג ללא fast-forward, אם יש בעיות תאימות בענף המקור והיעד, Git יעלה בעיה לפתרון הקונפליקט לפני השלמת ה-rebase.

סוגי קונפליקטים ב-Git Merge

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

בהתחלה של החיבור

Git merge יכשל בהתחלה אם קיים שינויים בתוך הדירוג או אזור העבודה. היכשלות בהתחלה מדברת על מנת למנוע את השינויים מהורדת על ידי ההפיכות המגיעות. זה קורה בגלל סכסוכים עם השינויים המקומיים, לא עם העמודות אחרות או מפתחים אחרים. על מנת ליציב את מצב המקומי, אפשר להשתמש בפקינסים כמו git stash, git commit, git checkout, או git reset.

במהלך החיבור

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

פקינסים לפתרון סכסוכים של Git Merge

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

פקינסים רגולריים

Git status הוא הפקינס הכי נפוץ להציג את מצב הקובצים המותקעים, אזור העבודה, וההפיכות. במהלך תהליך החיבור, הוא משמש כדי לזהות את הקובצים הסובבים סכסוך

git status

הגיט לוג עם ארגומנטים –merge מייצר את רשימת ההפצאות שבהן יש סתירה עם ענף המקור. 

git log --merge

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

git diff

פקודות עבור כשיכשלו של המיזוג בהתחלה

checkout נמצא בשימוש לביטול שינויים או החלפה לענף חדש או ישן. 

git checkout

Git reset משמש להחזרת שינויים בתוך ספריית העבודה ואזור ההכנה. 

git reset --mixed

פקודות עבור סתירות במהלך המיזוג

הארגומנט –abort יעצור את תהליך המיזוג ויחזיר את השינויים למצבם המקורי לפני התחלת המיזוג. 

git merge --abort

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

git reset

פתרון סתירות של קבצים שנמחקו-שונו

סתירת Git תתרחש אם נמחקת את הקובץ בענף הנוכחי, ומישהו אחר שינה אותו בענף אחר. במקרה זה, ניתן להוסיף קובץ ולהפוך להפצאה,

git add <filename>

או להסיר את הקובץ ולהפוך להפצאה. 

git rm <filename>

כלי המיזוג הוויזואליים

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

כדי לבדוק את רשימת הכלים המותקנים והתוקעים, השתמשות ב:

git mergetool --tool-help

הרשימה מכילה את כל הכלים התוקעים שניתן להתקין ולהתחבר לפקודות Git.

לדוגמה, יש לנו vim ו nvim מותקנים באופציה, ואם רוצים לראות את ההבדל בין קובץ שאינו מושבע וההגשה הקודמת, תקוו ב:

git difftool --tool=vimdiff3

הכלי vimdiff3 מדגיש את השינויים ומאפשר לך להשוות את ההגשות בתוך הטרמינל.

הבדל בין שני גרסאות של אותו קובץ ב vimdiff3

Meld

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

הפקודות הבאות נועדות רק למשתמשי Windows. השינוי היחיד שצריך לבצע הוא לשנות את הדרך של ה

git config --global merge.tool meld git config --global mergetool.meld.path "C:/Program Files (x86)/Meld/Meld.exe" git config --global diff.tool meld git config --global difftool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"

כאשר מכינים הגדרות ברירת מחדל, ניתן להקליד git difftool בתוך הספרייה המקומית של Git כדי לשגר את גירסת הווינדוס של Meld, או שניתן להשתמש ב-git mergetool כדי לפתור סכסוכי המיזוג כפי שמוצג בהמשך.

פתרון סכסוך מיזוג באמצעות Meld

VSCode

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

פתרון סכסוך מיזוג באמצעות VSCode

אם מחפשים פתרון מלא לפעולות Git, ניסו GitKraken. זה מגיע עם לקוח חינמי, הרחבה של VSCode ומספק כלי מובנה לפתרון סכסוכי מיזוג.  

איך לפתור סכסוך מיזוג בGit

בחלק זה נלמד איך ליצור סתם סכסוך של Git ואז לפתור אותו. המדריך מופרד לשני חלקים. בחלק הראשון, נלמד לפתור סכסוכים בגיט באופן מקומי; החלק השני הוא על פתירת סכסוכים עם שרת רחוק (GitHub).

סכסוך משולב מקומי

יצירת סכסוכים משולבים תעזור לנו ללמוד איך הם נובעים בהתחלה. אחר כך נוכל להשתמש בדרכים יצירתיות לפתרון הבעיות האלה או אפילו למנוע אותן מתרחשות בעתיד.

עכשיו ניצור אחד מאגרי Git עם קובץ אחד ונבצע את ההגשה הראשונה שלנו כדי להתחיל.

  1. יצירה תיקייה בשם datacamp.
  2. שינוי התיקייה לdatacamp.
  3. התחלת Git.
  4. יצירת קובץ README.md עם השתילה נתונית מסויימת.
  5. ארגון והגשה של השינויים בקובץ בעזרת האג'ד.
mkdir datacamp cd datacamp git init echo "# How to Resolve Git Merge Conflict" > README.md git add README.md git commit -m "first commit" >>> [main (root-commit) 8199ea2] first commit >>> 1 file changed, 1 insertion(+) >>> create mode 100644 README.md

בהמשך, ניצור ענף חדש readme ונשנה את השתילה העיקרית מ-“Git Merge” ל-“Git”. נשים את הקובץ וניצור את ההגשה בעזרת השורה -am.

git checkout -b readme echo "# How to Resolve Git Conflict" > README.md git commit -am "new branch conflict added" >>> [readme 155f694] new branch conflict added >>> 1 file changed, 1 insertion(+), 1 deletion(-)

חזרה לענף הראשי והוספת שורה חדשה לקובץ README.md בעזרת >>. על-ידי שימור השינויים והגשה שלהם, יצרנו בהצלחה סכסוך בין שתי גרסאות של אותו קובץ.

git checkout main echo "New change in base branch" >> README.md git commit -am " a line added to base branch Readme file" >>> [main f1f1874] a line added to base branch Readme file >>> 1 file changed, 1 insertion(+)

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

git merge readme >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.

בדיוק כפי שאנחנו עושים זאת באופן ידני על ידי פתיחה ועריכה של הקובץ במסמך הפתק, התמונה שלהלן מראה חץ עם HEAD, מפריד, וחץ בכיוון שונה עם קריאתמה. חלק ה-HEAD מראה את השינויים הקיימים בענף המרכזי, וחלק הקריאתמה הוא הענף שרוצים למרוץ, שמכיל כותרת שונה. 

פתרון סכסוך מריץ ידנית 

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

סכסוך נפתר 

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

git commit -am "conflict resolved in file README.md" >>> [main 9994a29] conflict resolved in file README.md

סכסוך מריץ רמוטרי

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

יצירת מאגר חדש ב-GitHub

לאחר מכן, הוסף שם מרוחק (origin) עם כתובת למאגר ודחוף את כל השינויים מהמאגר המקומי לסניף הראשי המרוחק באמצעות upstream.

git remote add origin https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git git push --set-upstream origin main >>> Enumerating objects: 12, done. >>> Counting objects: 100% (12/12), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (12/12), 998 bytes | 499.00 KiB/s, done. >>> Total 12 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), done. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> * [new branch] main -> main >>> branch 'main' set up to track 'origin/main'.

כדי ליצור קונפליקט, עלינו לבצע שינויים בקובץ README.md המרוחק והמקומי. ניתן להשתמש בעורך הקבצים של GitHub כדי לשנות "..Git merge.." ל-"..Sit-Merge.." ולאחר מכן להתחייב לשינויים. 

שינוי קבצים בעורך GitHub

לאחר מכן, במאגר המקומי, יש לשנות את קובץ README.md כדי להוסיף רק כותרת פשוטה ולהתחייב לשינויים. 

echo "# How to Resolve Merge Conflicts in Git Tutorial" > README.md git commit -am "local branch changes in README.md" >>> [main c677a13] local branch changes in README.md >>> 1 file changed, 1 insertion(+), 4 deletions(-)

לבסוף, דחוף את השינויים לשרת המרוחק. שים לב ש-Git העלה שגיאה עם רמזים על איך לפתור את הבעיה. 

git push >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> ! [rejected] main -> main (fetch first) >>> error: failed to push some refs to 'https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git' >>> hint: Updates were rejected because the remote contains work that you do >>> hint: not have locally. This is usually caused by another repository pushing >>> hint: to the same ref. You may want to first integrate the remote changes >>> hint: (e.g., 'git pull ...') before pushing again. >>> hint: See the 'Note about fast-forwards' in 'git push --help' for details.

נעקוב אחר הרמז הפשוט ביותר, שהוא למשוך את הקובץ מהשרת המרוחק לפני הדחיפה. 

משיכת הקובץ נכשלה עקב קונפליקט מיזוג בקובץ README.md. היינו יכולים לתקן זאת ידנית באמצעות Notepad, אך הפעם נשתמש בכלי חזותי שיעזור לנו בתהליך זה. 

git pull >>> remote: Enumerating objects: 5, done. >>> remote: Counting objects: 100% (5/5), done. >>> remote: Compressing objects: 100% (2/2), done. >>> remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 >>> Unpacking objects: 100% (3/3), 681 bytes | 75.00 KiB/s, done. >>> From https://github.com/kingabzpro/DataCamp-Git-Merge-Guide >>> aaf149d..49b7d14 main -> origin/main >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.

כלי המיזוג Meld יזהה קבצים בקונפליקט ויציג אותם באפליקציית ה-GUI של Meld.   

git mergetool >>> Merging: >>> README.md >>> Normal merge conflict for 'README.md': >>> {local}: modified file >>> {remote}: modified file

ישנם שלושה עמודות: README_LOCAL_473.md, README.md, ו-README_LOCAL_473.md. אם אתה חושב שהשינויים המרוחקים תקפים, לחץ על החץ השחור בעמודה המרוחקת; ואם אתה רוצה שהשינויים המקומיים יישארו, לחץ על החץ השחור בעמודה המקומית. זה כל כך פשוט.

פתרון קונפליקט באמצעות כלי המיזוג Meld

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

git commit -am "remote main branch conflict resolved" git push >>> Enumerating objects: 16, done. >>> Counting objects: 100% (16/16), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (10/10), 1.08 KiB | 550.00 KiB/s, done. >>> Total 10 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), completed with 1 local object. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> 49b7d14..8f5c3aa main -> main

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

סיכום

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

אם אתה חדש ב-Git ורוצה ללמוד כיצד הוא פועל, קרא: מבוא ל-Git ול-GitHub מדריך.

Source:
https://www.datacamp.com/tutorial/how-to-resolve-merge-conflicts-in-git-tutorial