במקום הקדמה
שלום! היום אנחנו הולכים לדבר על מערכת בקרת גרסאות, כלומר Git. אין לך מה לעשות עם תכנות אם אתה לא יודע/מבין את Git. אבל היופי הוא שאתה לא צריך לשמור את כל הפקודות והתכונות של Git בראש כדי להיות מועסקים ברציפות. אתה צריך לדעת סט פקודות שיעזור לך להבין כל מה שקורה.יסודות Git
Git היא מערכת בקרת גרסאות מבוזרת עבור הקוד שלנו. למה אנחנו צריכים את זה? צוותים מבוזרים זקוקים למערכת כלשהי לניהול העבודה שלהם. יש צורך לעקוב אחר שינויים המתרחשים לאורך זמן. כלומר, עלינו להיות מסוגלים לראות שלב אחר שלב אילו קבצים השתנו וכיצד. זה חשוב במיוחד כאשר אתה חוקר מה השתנה בהקשר של משימה בודדת, מה שמאפשר לבטל את השינויים.התקנת Git
בוא נתקין ג'אווה במחשב שלך.התקנה על Windows
כרגיל, עליך להוריד ולהפעיל קובץ exe. הכל פשוט כאן: לחץ על הקישור הראשון של גוגל , בצע את ההתקנה, וזהו. לשם כך, נשתמש בקונסולת bash שמספקת Windows. ב-Windows, אתה צריך להפעיל את Git Bash. כך זה נראה בתפריט התחל: כעת זוהי שורת פקודה שתוכל לעבוד איתה. כדי להימנע מהצורך ללכת לתיקיה עם הפרוייקט בכל פעם כדי לפתוח שם את Git, ניתן לפתוח את שורת הפקודה בתיקיית הפרוייקט בלחצן העכבר הימני עם הנתיב שאנו צריכים:התקנה על לינוקס
בדרך כלל Git הוא חלק מהפצות לינוקס והוא כבר מותקן, מכיוון שמדובר בכלי שנכתב במקור לפיתוח ליבת לינוקס. אבל יש מצבים שלא. כדי לבדוק, אתה צריך לפתוח מסוף ולכתוב: git --version. אם אתה מקבל תשובה מובנת, אז שום דבר לא צריך להיות מותקן. פתח מסוף והתקן את Git באובונטו . אני עובד על אובונטו, אז אני יכול להגיד לך מה לכתוב עבורו: sudo apt-get install git.התקנה על macOS
גם כאן צריך קודם כל לבדוק אם Git כבר שם. אם אין לך את זה, אז הדרך הקלה ביותר להשיג את זה היא להוריד את הגרסה העדכנית ביותר כאן . אם Xcode מותקן, אז Git בהחלט יותקן אוטומטית.הגדרות Git
ל-Git יש הגדרות משתמש עבור המשתמש שיגיש עבודה. זה הגיוני והכרחי, מכיוון ש-Git לוקח את המידע הזה עבור שדה Author כאשר נוצרת commit. הגדר שם משתמש וסיסמה עבור כל הפרויקטים שלך על ידי הפעלת הפקודות הבאות:
git config --global user.name "Ivan Ivanov"
git config --global user.email ivan.ivanov@gmail.com
אם אתה צריך לשנות את המחבר עבור פרויקט ספציפי, אתה יכול להסיר את "--global". זה ייתן לנו את הדברים הבאים:
git config user.name "Ivan Ivanov"
git config user.email ivan.ivanov@gmail.com
קצת תיאוריה...
כדי לצלול לתוך הנושא, כדאי שנכיר לכם כמה מילים ופעולות חדשות...- מאגר git
- לְבַצֵעַ
- ענף
- לְמַזֵג
- קונפליקטים
- מְשׁוֹך
- לִדחוֹף
- כיצד להתעלם מקבצים מסוימים (.gitignore)
סטטוסים ב-Git
ל-Git יש כמה פסלים שצריך להבין ולזכור:- ללא מעקב
- שונה
- מְבוּיָם
- מְחוּיָב
איך אתה צריך להבין את זה?
אלו הם סטטוסים החלים על הקבצים המכילים את הקוד שלנו:- לקובץ שנוצר אך עדיין לא נוסף למאגר יש את הסטטוס "לא במעקב".
- כאשר אנו עורכים שינויים בקבצים שכבר נוספו למאגר Git, אז הסטטוס שלהם "משתנה".
- בין הקבצים ששינינו, אנו בוחרים את הקבצים שאנו צריכים, והמחלקות הללו משתנות לסטטוס "מבוים".
- commit נוצר מקבצים מוכנים במצב מבוים ונכנס למאגר Git. לאחר מכן, אין קבצים עם הסטטוס "מבוים". אבל ייתכן שעדיין יש קבצים שהסטטוס שלהם "משונה".
מהי התחייבות?
התחייבות היא האירוע המרכזי בכל הנוגע לבקרת גרסאות. הוא מכיל את כל השינויים שבוצעו מאז תחילת ההתחייבות. התחייבויות מקושרות יחד כמו רשימה מקושרת בודדת. ליתר דיוק: יש התחייבות ראשונה. כאשר ה-commit השני נוצר, הוא יודע מה מגיע אחרי הראשון. ובאופן זה ניתן לעקוב אחר מידע. ל-commit יש גם מידע משלה, מה שנקרא מטא נתונים:- המזהה הייחודי של ה-commit, שניתן להשתמש בו כדי למצוא אותו
- שמו של מחבר ה-commit, שיצר אותו
- התאריך שבו ה-commit נוצר
- הערה המתארת את מה שנעשה במהלך ההתחייבות
מה זה סניף?
ענף הוא מצביע על התחייבות כלשהי. מכיוון שמתחייב יודע איזו התחייבות קודמת לו, כאשר ענף מצביע על התחייבות, חלים עליו גם כל אותם התחייבויות קודמות. בהתאם, נוכל לומר שאתה יכול להחזיק כמה סניפים שאתה רוצה המצביעים על אותו commit. העבודה מתרחשת בסניפים, כך שכאשר נוצר commit חדש, הענף מעביר את המצביע שלו ל-commit האחרון.תחילת העבודה עם Git
אתה יכול לעבוד עם מאגר מקומי לבד וגם עם מאגר מרוחק. כדי לתרגל את הפקודות הנדרשות, אתה יכול להגביל את עצמך למאגר המקומי. זה מאחסן רק את כל המידע של הפרויקט באופן מקומי בתיקיית .git. אם אנחנו מדברים על המאגר המרוחק, אז כל המידע מאוחסן איפשהו בשרת המרוחק: רק עותק של הפרוייקט מאוחסן באופן מקומי. ניתן לדחוף שינויים שבוצעו בעותק המקומי שלך (git push) למאגר המרוחק. בדיון שלנו כאן ומטה, אנחנו מדברים על עבודה עם Git בקונסולה. כמובן, אתה יכול להשתמש באיזשהו פתרון מבוסס GUI (לדוגמה, IntelliJ IDEA), אבל תחילה עליך להבין אילו פקודות מבוצעות ומה משמעותן.עבודה עם Git במאגר מקומי
לאחר מכן, אני מציע לך לעקוב ולבצע את כל השלבים שעשיתי בזמן שקראת את המאמר. זה ישפר את ההבנה והשליטה שלך בחומר. ובכן, תאבון! :) כדי ליצור מאגר מקומי, עליך לכתוב:
git init
פעולה זו תיצור תיקיית .git בספרייה הנוכחית של המסוף. תיקיית .git מאחסנת את כל המידע על מאגר Git. אל תמחק את זה ;) לאחר מכן, קבצים מתווספים לפרויקט, והם מקבלים את הסטטוס "לא במעקב". כדי לבדוק את המצב הנוכחי של העבודה שלך, כתוב את זה:
git status
אנחנו בסניף המאסטר, וכאן נישאר עד שנעבור לסניף אחר. זה מראה אילו קבצים השתנו אך עדיין לא נוספו לסטטוס "מבוים". כדי להוסיף אותם לסטטוס "מבוים", עליך לכתוב "git add". יש לנו כאן כמה אפשרויות, למשל:
- git add -A - הוסף את כל הקבצים לסטטוס "מבוים".
- git add . - הוסף את כל הקבצים מתיקיה זו ואת כל תיקיות המשנה. בעיקרון, זה זהה לקודם
- git add <שם קובץ> - מוסיף קובץ ספציפי. כאן אתה יכול להשתמש בביטויים רגולריים כדי להוסיף קבצים לפי דפוס כלשהו. לדוגמה, git add *.java: זה אומר שאתה רוצה להוסיף רק קבצים עם סיומת java.
git add *.txt
כדי לבדוק את המצב, אנו משתמשים בפקודה שכבר ידועה לנו:
git status
כאן אתה יכול לראות שהביטוי הרגולרי עבד כהלכה: test_resource.txt הוא כעת בעל הסטטוס "מבוים". ולבסוף, השלב האחרון לעבודה עם מאגר מקומי (יש עוד אחד כשעובדים עם המאגר המרוחק ;)) - יצירת commit חדש:
git commit -m "all txt files were added to the project"
הבא הוא פקודה מצוינת להסתכל על היסטוריית ההתחייבויות על סניף. בואו ננצל את זה:
git log
כאן אתה יכול לראות שיצרנו את ה-commit הראשון שלנו והוא כולל את הטקסט שסיפקנו בשורת הפקודה. חשוב מאוד להבין שהטקסט הזה צריך להסביר בצורה מדויקת ככל האפשר מה נעשה במהלך ההתחייבות הזו. זה יעזור לנו פעמים רבות בעתיד. קורא סקרן שעדיין לא נרדם אולי תוהה מה קרה לקובץ GitTest.java. בוא נגלה כבר עכשיו. לשם כך, אנו משתמשים ב:
git status
כפי שאתה יכול לראות, הוא עדיין "לא מעקב" ומחכה בכנפיים. אבל מה אם אנחנו לא רוצים להוסיף אותו לפרויקט בכלל? לפעמים זה קורה. כדי להפוך את הדברים למעניינים יותר, ננסה כעת לשנות את קובץ test_resource.txt שלנו. בואו נוסיף שם קצת טקסט ונבדוק את הסטטוס:
git status
כאן אתה יכול לראות בבירור את ההבדל בין הסטטוס "לא במעקב" ו"שונה". GitTest.java "לא מעקב", בעוד test_resource.txt "משונה". כעת, כאשר יש לנו קבצים במצב שונה, אנו יכולים לבחון את השינויים שבוצעו בהם. ניתן לעשות זאת באמצעות הפקודה הבאה:
git diff
כלומר, ניתן לראות כאן בבירור מה הוספתי לקובץ הטקסט שלנו: שלום עולם! בואו נוסיף את השינויים שלנו לקובץ הטקסט וניצור commit:
git add test_resource.txt
git commit -m "added hello word! to test_resource.txt"
כדי להסתכל על כל ההתחייבויות, כתוב:
git log
כפי שאתה יכול לראות, יש לנו כעת שני התחייבויות. נוסיף את GitTest.java באותו אופן. אין כאן הערות, רק פקודות:
git add GitTest.java
git commit -m "added GitTest.java"
git status
עבודה עם .gitignore
ברור שאנחנו רוצים לשמור רק את קוד המקור לבד, ולא שום דבר אחר, במאגר. אז מה עוד יכול להיות? לכל הפחות, מחלקות ו/או קבצים הידור שנוצרו על ידי סביבות פיתוח. כדי להגיד ל-Git להתעלם מהם, עלינו ליצור קובץ מיוחד. עשה זאת: צור קובץ בשם .gitignore בשורש הפרוייקט. כל שורה בקובץ זה מייצגת דפוס שיש להתעלם ממנו. בדוגמה זו, קובץ ה-gitignore ייראה כך:
```
*.class
target/
*.iml
.idea/
```
בואו נסתכל:
- השורה הראשונה היא להתעלם מכל הקבצים עם סיומת .class
- השורה השנייה היא להתעלם מתיקיית ה"מטרה" ומכל מה שהיא מכילה
- השורה השלישית היא להתעלם מכל הקבצים עם סיומת .iml
- השורה הרביעית היא להתעלם מתיקיית .idea
git status
ברור שאיננו רוצים להוסיף בטעות את המחלקה הקומפילית לפרויקט (באמצעות git add -A). כדי לעשות זאת, צור קובץ .gitignore והוסף את כל מה שתואר קודם לכן: כעת בוא נשתמש ב-commit כדי להוסיף את קובץ ה-gitignore לפרויקט:
git add .gitignore
git commit -m "added .gitignore file"
ועכשיו רגע האמת: יש לנו מחלקה קומפילית GitTest.class שהיא "לא מעקב", אותה לא רצינו להוסיף למאגר Git. כעת אנו אמורים לראות את ההשפעות של קובץ .gitignore:
git status
מושלם! .gitignore +1 :)
עבודה עם סניפים וכאלה
מטבע הדברים, עבודה בסניף אחד בלבד אינה נוחה למפתחים בודדים, ואי אפשר כשיש יותר מאדם אחד בצוות. זו הסיבה שיש לנו סניפים. כפי שאמרתי קודם, ענף הוא רק מצביע מטלטלין להתחייבויות. בחלק זה, נחקור עבודה בענפים שונים: כיצד למזג שינויים מענף אחד לאחר, אילו קונפליקטים עלולים להיווצר ועוד. כדי לראות רשימה של כל הסניפים במאגר ולהבין באיזה מהם אתה נמצא, עליך לכתוב:
git branch -a
אתה יכול לראות שיש לנו רק סניף מאסטר אחד. הכוכבית שלפניו מציינת שאנו נמצאים בה. אגב, אתה יכול גם להשתמש בפקודה "git status" כדי לגלות באיזה סניף אנחנו נמצאים. לאחר מכן ישנן מספר אפשרויות ליצירת סניפים (ייתכן שיהיו עוד - אלו הן האפשרויות שאני משתמש בהן):
- צור סניף חדש על סמך זה שאנחנו נמצאים בו (99% מהמקרים)
- צור סניף על סמך התחייבות ספציפית (1% מהמקרים)
בואו ניצור סניף על סמך מחויבות ספציפית
אנו נסתמך על המזהה הייחודי של ההתחייבות. כדי למצוא אותו, אנו כותבים:
git log
הדגשתי את ההתחייבות עם ההערה "הוסף שלום עולם..." המזהה הייחודי שלו הוא 6c44e53d06228f888f2f454d3cb8c1c976dd73f8. אני רוצה ליצור סניף "פיתוח" שמתחיל מההתחייבות הזו. כדי לעשות זאת, אני כותב:
git checkout -b development 6c44e53d06228f888f2f454d3cb8c1c976dd73f8
נוצר סניף עם שני המחויבויות הראשונות בלבד מהסניף הראשי. כדי לאמת זאת, תחילה אנו מקפידים לעבור לסניף אחר ולבחון את מספר ההתחייבויות שם:
git status
git log
וכצפוי, יש לנו שני התחייבויות. אגב, הנה נקודה מעניינת: עדיין אין קובץ .gitignore בסניף הזה, אז הקובץ הקומפילד שלנו (GitTest.class) מודגש כעת בסטטוס "לא מעקב". כעת נוכל לסקור את הסניפים שלנו שוב על ידי כתיבת הדברים הבאים:
git branch -a
ניתן לראות שיש שני ענפים: "מאסטר" ו"פיתוח". אנחנו כרגע בפיתוח.
בואו ניצור סניף על סמך הענף הנוכחי
הדרך השנייה ליצור ענף היא ליצור אותו מתוך אחר. אני רוצה ליצור סניף המבוסס על ענף המאסטר. ראשית, אני צריך לעבור אליו, והשלב הבא הוא ליצור אחד חדש. בואו נסתכל:- git checkout master — עבור לסניף המאסטר
- git status - ודא שאנחנו באמת בענף המאסטר
git checkout -b feature/update-txt-files
אם אינך בטוח אם הענף הזה זהה ל"מאסטר", אתה יכול לבדוק בקלות על ידי הפעלת "git log" והסתכלות על כל ה-commits. צריכים להיות ארבעה מהם.
פתרון סכסוכים
לפני שנחקור מהו קונפליקט, עלינו לדבר על מיזוג ענף אחד לאחר. תמונה זו מתארת את תהליך מיזוג סניף אחד לאחר: הנה, יש לנו סניף ראשי. בשלב מסוים, נוצר סניף משני מחוץ לסניף הראשי ולאחר מכן משתנה. לאחר סיום העבודה, עלינו למזג ענף אחד לשני. לא אתאר את המאפיינים השונים: במאמר זה ברצוני רק להעביר הבנה כללית. אם אתה צריך את הפרטים, אתה יכול לחפש אותם בעצמך. בדוגמה שלנו, יצרנו את ענף feature/update-txt-files. כפי שמצוין בשם הסניף, אנו מעדכנים טקסט. כעת עלינו ליצור מחויבות חדשה לעבודה זו:
git add *.txt
git commit -m "updated txt files"
git log
כעת, אם ברצוננו למזג את ענף ה- feature/update-txt-files לתוך מאסטר, עלינו לעבור אל מאסטר ולכתוב "git merge feature/update-txt-files":
git checkout master
git merge feature/update-txt-files
git log
כתוצאה מכך, ענף המאסטר כולל כעת גם את ה-commit שהתווסף לקבצי feature/update-txt. פונקציונליות זו נוספה, כך שתוכל למחוק ענף תכונה. לשם כך, אנו כותבים:
git branch -D feature/update-txt-files
הכל ברור עד כה, כן? בואו נסבך את המצב: עכשיו נניח שאתה צריך לשנות שוב את קובץ ה-txt. אבל עכשיו הקובץ הזה ישתנה גם בענף המאסטר. במילים אחרות, זה ישתנה במקביל. Git לא תוכל להבין מה לעשות כשנרצה למזג את הקוד החדש שלנו לתוך ענף המאסטר. בוא נלך! אנו ניצור סניף חדש המבוסס על מאסטר, נבצע שינויים ב-text_resource.txt וניצור מחויבות לעבודה זו:
git checkout -b feature/add-header
... we make changes to the file
git add *.txt
git commit -m "added header to txt"
עבור אל הענף הראשי ועדכן גם את קובץ הטקסט הזה באותה שורה כמו בענף הפיצ'רים:
git checkout master
… we updated test_resource.txt
git add test_resource.txt
git commit -m "added master header to txt"
ועכשיו הנקודה המעניינת ביותר: אנחנו צריכים למזג שינויים מהענף של feature/add-header למאסטר. אנחנו בסניף המאסטר, אז אנחנו צריכים רק לכתוב:
git merge feature/add-header
אבל התוצאה תהיה התנגשות בקובץ test_resource.txt: כאן אנו יכולים לראות ש-Git לא הצליח להחליט לבד כיצד למזג את הקוד הזה. זה אומר לנו שאנחנו צריכים לפתור את הסכסוך קודם, ורק אז לבצע את ההתחייבות. בסדר. אנחנו פותחים את הקובץ עם הקונפליקט בעורך טקסט ורואים: כדי להבין מה Git עשה כאן, אנחנו צריכים לזכור אילו שינויים ביצענו ואיפה, ואז להשוות:
- השינויים שהיו בשורה זו בענף המאסטר נמצאים בין "<<<<<<< HEAD" ו-"========".
- השינויים שהיו בענף feature/add-header נמצאים בין "=======" ו">>>>>>> feature/add-header".
git status
אנחנו יכולים לשכנע את עצמנו שמדובר במקרה מיוחד ויוצא דופן. בוא נמשיך:
git add *.txt
אולי תשים לב שהתיאור מציע לכתוב רק "git commit". בוא ננסה לכתוב את זה:
git commit
ובדיוק ככה, עשינו את זה - פתרנו את הקונפליקט בקונסולה. כמובן שניתן לעשות זאת קצת יותר בקלות בסביבות פיתוח משולבות. לדוגמה, ב-IntelliJ IDEA, הכל מוגדר כל כך טוב שאתה יכול לבצע את כל הפעולות הדרושות ישירות בתוכו. אבל IDEs עושים הרבה דברים "מתחת למכסה המנוע", ולעתים קרובות אנחנו לא מבינים מה בדיוק קורה שם. וכשאין הבנה, יכולות להתעורר בעיות.
עבודה עם מאגרים מרוחקים
השלב האחרון הוא להבין כמה פקודות נוספות הדרושות לעבודה עם המאגר המרוחק. כפי שאמרתי, מאגר מרוחק הוא מקום שבו המאגר מאוחסן וממנו ניתן לשכפל אותו. איזה סוג של מאגרים מרוחקים יש? דוגמאות:-
GitHub היא פלטפורמת האחסון הגדולה ביותר עבור מאגרים ופיתוח שיתופי. כבר תיארתי את זה במאמרים קודמים.
עקבו אחרי ב- GitHub . אני מרבה להשוויץ בעבודתי שם באותם תחומים שאני לומד לעבודה. -
GitLab הוא כלי מבוסס אינטרנט למחזור החיים של DevOps עם קוד פתוח . זוהי מערכת מבוססת Git לניהול מאגרי קוד עם ויקי משלה, מערכת מעקב אחר באגים , צינור CI/CD ופונקציות אחרות.
לאחר החדשות שמיקרוסופט קנתה את GitHub, כמה מפתחים שכפלו את הפרויקטים שלהם ב-GitLab. -
BitBucket הוא שירות אינטרנט לאירוח פרויקטים ופיתוח שיתופי המבוסס על מערכות בקרת גרסאות Mercurial ו-Git. פעם היה לו יתרון גדול על GitHub בכך שהוא הציע מאגרים פרטיים בחינם. בשנה שעברה, GitHub גם הציג את היכולת הזו לכולם בחינם.
-
וכולי…
git clone https://github.com/romankh3/git-demo
כעת יש עותק מקומי שלם של הפרויקט. כדי להיות בטוח שהעותק המקומי של הפרויקט הוא העדכני ביותר, עליך למשוך את הפרויקט על ידי כתיבה:
git pull
במקרה שלנו, שום דבר במאגר המרוחק לא השתנה כרגע, ולכן התגובה היא: כבר מעודכן. אבל אם אני מבצע שינויים כלשהם במאגר המרוחק, המאגר המקומי מתעדכן לאחר שנמשוך אותם. ולבסוף, הפקודה האחרונה היא לדחוף את הנתונים למאגר המרוחק. כאשר עשינו משהו מקומי ורוצים לשלוח אותו למאגר המרוחק, עלינו ליצור תחילה commit חדש באופן מקומי. כדי להדגים זאת, בואו נוסיף עוד משהו לקובץ הטקסט שלנו: עכשיו משהו די נפוץ עבורנו - אנחנו יוצרים מחויבות לעבודה הזו:
git add test_resource.txt
git commit -m "prepared txt for pushing"
הפקודה לדחוף את זה למאגר המרוחק היא:
git push
ובכן, זה כל מה שרציתי לומר. תודה על תשומת לבך. עקבו אחרי ב- GitHub
, שם אני מפרסם פרויקטים מגניבים שונים הקשורים ללימודים ולעבודה האישיים שלי.
קישור שימושי
- תיעוד רשמי של Git . אני ממליץ על זה בתור התייחסות.
GO TO FULL VERSION