טיפ גיט: איך לאחד מספר מאגרים למונוריפו

27/08/2022

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

1. מה לא כדאי לעשות

נפתח תיקיה חדשה ונשכפל לתוכה שני פרויקטים בשביל הדוגמה:

$ git clone https://github.com/sindresorhus/awesome.git

$ git clone https://github.com/ossu/computer-science.git

עכשיו ניצור תיקיית monorepo חדשה:

$ mdkir monorepo

ובתוכה ניצור את המונוריפו שלנו בתור מאגר גיט:

$ cd monorepo
$ git init .

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

$ cp -R ../awesome .
$ rm -rf ./awesome/.git

$ cp -R ../computer-science .
$ rm -rf ./computer-science/.git

$ git add .
$ git commit -m 'initial monorepo commit'

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

2. איך לאחד ולשמור את ההיסטוריה

פיתרון טוב יותר ישתמש בכלי שנקרא filter-repo ובמנגנון ה merge של גיט.

נמחק את תיקיית monorepo שיצרנו וניצור חדשה במקומה:

$ rm -rf monorepo
$ mkdir monorepo

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

$ cd ../awesome
$ git filter-repo --to-subdirectory-filter awesome

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

את אותו דבר אני עושה על המאגר השני:

$ cd ../computer-science
$ git filter-repo --to-subdirectory-filter computer-science

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

$ cd ../monorepo
$ git init .
$ git remote add awesome ../awesome
$ git remote add computer-science ../computer-science
$ git fetch --all

$ git merge --allow-unrelated-histories awesome/main
$ git merge --allow-unrelated-histories computer-science/master

וזה כל הסיפור. עכשיו ב monorepo יש את שתי תתי התיקיות awesome ו computer-science, את כל הקומיטים של שני הפרויקטים, ואני יכול להפעיל log על כל אחת מתתי התיקיות כדי לראות רק את הקומיטים מאותו פרויקט.