Git - חלק 1 (הקדמה)

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

כדי שיהיה ברור, הפוסט כן יהווה מדריך למידה ל Git.

 

רקע כללי

גיט (באנגלית: Git) היא מערכת ניהול קבצים מבוזרת הנוצרה ע”י לינוס טורבאלדס בשנת 2005.

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

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

מה זה בעצם “מבוזרת”?
עד לא ממזמן מערכות לניהול קבצים השתמשו במאגר (repository) מרכזי, ז”א שכל חברי הצוות שעובדים על הפרויקט ומבצעים שינויים, מעלים אותו למאגר אחד, שרת אחד. מערכות לניהול קבצים אחרות, דוגמת Git, הן מבוזרות, ז”א שלכל חבר צוות יש העתק שלם של המאגר (repository ובקיצור repo) אצלו באופן מקומי. וזה נותן את היכולת לבצע commit במהירות, היכולת לעבוד על הפרויקט גם כשלא מחוברים, וכמובן גיבוי, גם אם העתק אחד מושמד, לכל חברי הצוות יש העתק של המאגר.

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

 

פקודות בסיסיות

כמו רוב הכלים של שרתי הפקודה, git מגיעה עם מערכת ‘עזרה’. לכן אם ניתקע, תמיד אפשר לכתוב את הפקודה git help וזה יתן לנו רשימה של כל הפקודות. ואם נרצה להיות יותר ספציפיים נוכל לכתוב git help config (ובמקום ה config כל פקודה קיימת אחרת).

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

git config --global user.name "Nir Galon"
git config --global user.email "nirgn975@gmail.com"

כמובן שאת השם משתמש והאימייל בין הגרשיים תחליפו בשלכם.

אז הורדנו והגדרנו git ואנחנו מוכנים לעבוד על המאגר הראשון שלנו, הדבר הראשון שאנחנו צריכים זו תיקייה, אז ניצור אחת אם אין לנו (אם זה פרויקט קיים סביר להניח שהוא נמצא אצלכם בתיקייה מיוחדת כבר), ע”י הפקודה mkdir nameOfDir (כמובן שתבחרו באיזה שם שתרצו), וננווט בשורת הפקודה אל התיקייה עם הפקודה cd nameOfDir. בשלב הזה אנחנו יכולים להתחיל לעבוד על הפרויקט, או מיד לאתחל את התיקייה, כך או כך, ברגע שנרצה לאתחל (אם זה מיד, במהלך או אחרי העבודה) נכתוב את הפקודה git init, זה יצור לנו מאגר גיט (git repo) מקומי (לא על אף שרת, אלה רק על המחשב שלנו).

  • המאגר יהיה מוחבא בתיקייה מוסתרת בשם “git.” בתוך התיקייה של הפרויקט.

 

התנהלות

לפני שנמשיך, ארצה לדבר על ההתנהלות עם git, או יותר נכון workflow. ברשותכם, אשאיל את השמות של חברי הצוות שלנו מדמויות מוכרות אחרות: אליס ובוב. נניח שאליס יוצרת קובץ README.txt שמתחיל כקובץ ללא מעקב (ז”א שהמערכת לניהול קבצים, Git, אינה עוקבת אחרי הקובץ, לא מגבה אותו, לא עוקבת אחרי שינויים בו, וכד’). כדי להתחיל לעקוב אחרי הקובץ אנחנו צריכים להוסיף אותו ל”אזור היערכות” (בעצם אנחנו מתכוננים לקחת תמונת בזק של המצב הנוכחי). ולבסוף אנחנו מבצעים commit שזהו בעצם לקיחת snapshot של הקבצים ששמנו ב”אזור ההיערכות”.

כעת, נניח שאליס עובדת על קובץ ה README.txt (עושה כמה שינויים), ואפילו מוסיפה קובץ נוסף בשם LICENSE. כעת, היא שוב צריכה להוסיף את הקבצים ל”אזור ההיערכות”, ולבצע commit (לקיחת snapshot נוסף, של המצב החדש).

וזה פחות או יותר ההתנהלות כרגע, אנו נבצע קצת עבודה, נשלח את הקבצים לאזור היערכות (אולי נבצע עוד עבודה, ניצור קובץ חדש וכד’ וגם אותו נצרף אח”כ לאזור היערכות). וכשסיימנו לצרף את כל הקבצים לאזור ההיערכות, ניקח snapshot ע”י ביצוע פקודות ה commit.

 

נחזור לשורת הפקודה

אחת הפקודות החשובות ביותר היא git status, היא תאפשר לנו לבדוק איזה שינויים התרחשו מהפעם האחרונה שביצענו commit. אם נדמה כתיבה של הפקודה לאחר שיצרנו את המאגר וקובץ README.txt (ז”א ישר לאחר הפקודה git init, ויצירת קובץ חדש, ללא והוספה שלו לאזור ההיערכות או ביצוע commit). נקבל חזרה את הקובץ ותיאור שלו למטה (ניתן לראות בקוד למטה). ניתן לראות כי בתיאור נאמר לנו שישנו קובץ שלא נמצא באזור ההיערכות, ז”א שהמערכת לניהול קבצים (Git) אינה עוקבת אחריו, והוא README.txt. וכלי הפקודה אף מייעץ לנו להשתמש בפקודה git add על מנת להתחיל לעקוב אחריו (ז”א להוסיף אותו לאזור ההיערכות).

$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#    (user "git add <file>.." to include in what will be committed)
#
#    README.txt
nothing added to commit but untracked files present (use "git add" to track)

אז בואו נתחיל לעקוב אחריו, נכתוב את הפקודה git add README.txt ואם נכתוב שוב את הפקודה git status נראה שהמערכת עוקבת אחרי הקובץ (כמו שניתן לראות: “new file: README.txt”) והוא מוכן ל commit (בעברית זה ישמע קצת מוזר, אולי “מוכן להיות מבוצע”).

$ git add README.txt

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#    (use "git rm --cached <file>.." to unstage)
#
#    new file:    README.txt
#

ועכשיו אנחנו מוכנים לביצוע ה commit הראשון שלנו. נעשה זאת עם הפקודה ".git commit -m "Create a Readme file (שימו לב שאחרי הפקודה אנחנו שמים גרשיים ובתוכם תיאור של ה commit, הגרשיים והמלל שבתוכם הינם חלק מהפקודה!). כמו שאמרנו הפקודה יוצרת את ה commit הראשון שלנו, בעצם לוקחת snapshot של אזור ההיערכות, וה snapshot הזה מתווסף ל”ציר הזמן” של הפרויקט. 

$ git commit -m "Create a README."

[master abe28da] Create a REAME.
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 README.txt

 לפני שנסביר מה זה ציר הזמן, אם נכתוב שוב את הפקודה git status נראה כי אין עוד מה לבצע לו commit, בעצם אין עוד שינויים או קבצים חדשים שלא ביצענו להם commit. בנוסף, הפקודה git status אומרת לנו שאנחנו בענף master (בשורה “On branch master”). בעקרון, כל מה שצריך להבין בשלב הזה הוא שיש לנו ענף אחד בציר הזמן של הפרויקט, וקוראים לו master (בהמשך נרד לעומק של הענפים האלו).

$ git status
# On branch master
nothing to commit (working directory clean)

 

עכשיו נניח שאליס ביצעה כמה שינויים בקובץ README.txt, ואף הוסיפה קובץ נוסף – LICENSE, כעת נריץ שוב את הפקודה git status ונראה כי הקובץ שאנו עוקבים אחריו (הלא הוא README.txt) שונה (המערכת עוקבת אחרי הקובץ, היא שמה עליו עין, ככה שהיא יודעת שהוא שונה). ובנוסף, נוצר קובץ חדש בתיקייה, אחריו המערכת לא עוקבת, בשם LICENSE.

$ git status
# On branch master
# Changed but not updated:
#
# modified:    README.txt
#
# Untracked files:
#
# LICENSE
no changes added to commit

כדי לבצע commit לשני הקבצים, יש להוסיף אותם קודם לאזור ההיערכות, ואפשר לעשות זאת ע”י הפקודה git add וכתיבת שני הקבצים (עם רווח בינהם), כך: git add README.txt LICENSE או שאפשר לכתוב git add -all שתוסיף את כל השינויים (קבצים חדשים, שינויים בקבצים ישנים ומחיקת קבצים) לאזור ההיערכות. כעת, אם נריץ שוב את הפקודה git status נראה שיש לנו 2 קבצים (אחד חדש, והשני ששונה) המכונים באזור ההיערכות, כדי להיות commit.

$ git add README.txt LICENSE

    OR

$ git add --all

$ git status
# On branch master
# Changes to be committed:
#
#    new file:    LICENSE
#    modified:    README.txt
#

 

אז נבצע commit לאזור ההיערכות, על ידי כתיבת הפקודה "git commit -m "Add License and finish Readme, ושוב יצרנו snapshot רגעי בענף master, וניתן לראות תיאור של מה שונה.

$ git commit -m "Add LICENSE and finish README."

[master 1b0019c] Add LICENSE and finish README.
 2 files changed, 21 insertions(+), 0 deletions(-)
 create mode 100644 LICENSE

בתמונה משמאל ניסיתי לצייר את ציר הזמן של הענף master, הנקודה הראשונה (לידה כתוב 1) היא ה commit הראשון שביצענו, והשניה (לידה כתוב 2) היא ה commit הנוכחי שביצענו. ליד הפקודה בעצם שמתי תמונה של מצלמה המסמלת את לקיחת ה snapshot, וה snapshot הזה מצביע ל commit השני.

Snapshot

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

 

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

  • <git add <list of files – במקום list of files כתבו את הקובץ / קבצים (לא לשכוח לשים רווח בינהם).
  • git add -all – יוסיף את כל הקבצים (קבצים חדשים, יעדכן מחיקת קבצים, ושינויים בקבצים שהמערכת כבר עוקבת אחריהם).

אך יש עוד כמה שימושיים:

  • git add *.txt – יוסיף את כל הקבצים בסיומת txt הנמצאים בתיקייה.
  • git add docs/*txt – יוסיף את כל הקבצים בסיומת txt הנמצאים בתיקייה docs.
  • git add docs – יוסיף את כל הקבצים הנמצאים בתיקייה docs (כולל הקבצים הנמצאים בתת תקיות בתוכה).
  • "git add "*txt – יוסיף את כל הקבצים בסיומת txt הנמצאים שבפרויקט (כל התיקיות והתת תיקיות הנמצאים בפרויקט).

 

שאלות ותשובות

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

שאלות:

  1. ברצונם להתחיל פרויקט חדש, יש לכם כבר תיקייה עם קובץ בתוכה. כדי להקים repo (מאגר) חדש, איזה פקודה עליכם לכתוב?
  2. יצרתם כמה קבצים, ביצעתם כמה פעמים commit, עדכנתם עוד כמה קבצים וכ’ו. יום העבודה הסתיים, ואתם רוצים לבצע commit אחרון עם השינויים שביצעתם, אך אתם כבר לא זוכרים איזה מהם דורשים commit,תשתמשו בפקודת git כלשהי שתראה לכם את הסטטוס של הקבצים.
  3. אוקי, גיליתם שיש רק קובץ אחד שנשאר לבצע לו commit, נקרא לקובץ index.html. הכינו אותו לביצוע commit ע”י הוספה שלו לאזור ההיערכות.
  4. כעת, בצעו commit לאזור ההיערכות.
  5. הוספתם תיקייה נוספת ל stylesheets, הוסיפו את כל הקבצים בתיקייה (הנקראת css) לאזור ההיערכות.
  6. חבר צוות עובר ליד העמדה שלכם ושואל אתכם על מה ביצעתם commit, הראו לו.

תשובות:

  1. הפקודה: git init (כמובן שיש לפני כן לנווט עם שורת הפקודה לתיקייה ולכתוב את הפקודה כשאתם נמצאים בתוך התיקייה).
  2. הפקודה: git status.
  3. הפקודה: git add index.html.
  4. הפקודה: "git commit -m "Add index.html.
  5. הפקודה: git add css.
  6. הפקודה: git log.

 

לסיכום

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

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