اکثر پروژه های نرم افزاری مدرن به کار دیگران بستگی دارد. زمانی که شخص دیگری راه حل فوق العاده ای را نوشته باشد ، اتلاف وقت است. به همین دلیل است که بسیاری از پروژه ها از کد شخص ثالث در قالب کتابخانه یا ماژول استفاده می کنند.

Git ، محبوب ترین سیستم کنترل نسخه جهان ، راهی عالی برای مدیریت این وابستگی ها به روشی زیبا و قوی ارائه می دهد. مفهوم “زیر ماژول” آن به ما امکان می دهد کتابخانه های شخص ثالث را شامل و مدیریت کنیم در حالی که آنها را کاملاً از کد خود جدا می کنیم.

در این مقاله می آموزید که چرا ماژول های فرعی در Git بسیار مفید هستند ، در واقع چیست و چگونه کار می کنند.

جدا نگه داشتن کد

برای روشن شدن اینکه چرا زیرگروه های Git در واقع یک ساختار ارزشمند هستند ، بیایید به یک مورد نگاه کنیم بدون زیر ماژول ها هنگامی که نیاز به وارد کردن کد شخص ثالث (مانند یک کتابخانه منبع باز) دارید ، مطمئناً می توانید راه آسان را طی کنید: فقط کد را از GitHub بارگیری کرده و آن را در جایی در پروژه خود قرار دهید. در حالی که قطعاً سریع، این رویکرد قطعاً است کثیف به چند دلیل:

  • با کپی اجباری کد شخص ثالث در پروژه خود ، به طور م multipleثر چندین پروژه را در یک پروژه مخلوط می کنید. خط بین پروژه خود شما و شخص دیگر (کتابخانه) تار می شود.
  • هر زمان که نیاز دارید کد کتابخانه را به روز کنید (زیرا نگهدارنده آن ویژگی جدید فوق العاده ای را ارائه کرده یا یک اشکال تند و زننده را برطرف کرده است) دوباره باید بارگیری ، کپی و جایگذاری کنید. این به سرعت تبدیل به یک فرایند خسته کننده می شود.

قانون کلی در توسعه نرم افزار برای “جدا نگه داشتن چیزهای جداگانه” به دلایلی وجود دارد. و مطمئناً برای مدیریت کد شخص ثالث در پروژه های خود صادق است. خوشبختانه مفهوم زیرمجموعه Git دقیقاً برای این موقعیت ها ساخته شده است.

اما مطمئناً ماژول های فرعی تنها راه حل موجود برای این نوع مشکلات نیستند. همچنین می توانید از یکی از سیستم های مختلف “مدیریت بسته” که بسیاری از زبانها و چارچوب های مدرن ارائه می دهند ، استفاده کنید. و هیچ مشکلی در این مورد وجود ندارد!

با این حال ، شما می توانید استدلال کنید که معماری زیرمجموعه Git دارای چند مزیت است:

  • زیرمجموعه ها یک رابط سازگار و قابل اعتماد ارائه می دهند – مهم نیست از چه زبان یا چارچوبی استفاده می کنید. به خصوص اگر با چندین فناوری کار می کنید ، هر کدام ممکن است مدیر بسته خود را با مجموعه قوانین و دستورات خاص خود داشته باشد. از طرف دیگر ، زیرمجموعه ها همیشه یکسان عمل می کنند.
  • ممکن است هر قطعه کد در یک مدیر بسته در دسترس نباشد. شاید شما فقط بخواهید کد خود را بین دو پروژه به اشتراک بگذارید – موقعیتی که زیرمدول ها ممکن است ساده ترین گردش کار ممکن را ارائه دهند.

Submodules Git واقعاً چیست

زیرمجموعه ها در Git واقعاً مخازن استاندارد Git هستند. بدون نوآوری فانتزی ، فقط همان مخازن Git که همه ما تا به حال به خوبی می شناسیم. این نیز بخشی از قدرت زیر ماژول ها است: آنها بسیار قوی و سرراست هستند زیرا بسیار “خسته کننده” (از نظر تکنولوژیکی) و آزمایش میدانی هستند.

تنها چیزی که یک مخزن Git را به یک ماژول فرعی تبدیل می کند ، قرارگیری آن است داخل یکی دیگر، والدین مخزن Git.

به غیر از این ، یک زیرمجموعه Git یک مخزن کاملاً کاربردی باقی می ماند: شما می توانید تمام اعمالی را که قبلاً از کار “معمولی” Git خود می دانید انجام دهید – از اصلاح فایل ها ، تا انجام ، کشیدن و فشار دادن. همه چیز در یک زیرمجموعه امکان پذیر است.

افزودن زیرمجموعه

بیایید مثال کلاسیک را بگیریم و بگوییم که ما می خواهیم یک کتابخانه شخص ثالث به پروژه خود اضافه کنیم. قبل از دریافت کد ، منطقی است که یک پوشه جداگانه ایجاد کنیم که مواردی مانند این می تواند خانه داشته باشد:

$ mkdir lib
$ cd lib

اکنون ما آماده ایم که برخی از کدهای شخص ثالث را به پروژه خود منتقل کنیم-اما به شیوه ای منظم ، با استفاده از زیر ماژول ها. فرض کنید ما به یک کتابخانه جاوا اسکریپت “مبدل منطقه زمانی” نیاز داریم:

$ git submodule add https://github.com/spencermountain/spacetime.git

وقتی این دستور را اجرا می کنیم ، Git شروع به شبیه سازی مخزن در پروژه ما می کند ، به عنوان یک زیر مدل:

Cloning into 'carparts-website/lib/spacetime'...
remote: Enumerating objects: 7768, done.
remote: Counting objects: 100% (1066/1066), done.
remote: Compressing objects: 100% (445/445), done.
remote: Total 7768 (delta 615), reused 975 (delta 588), pack-reused 6702
Receiving objects: 100% (7768/7768), 4.02 MiB | 7.78 MiB/s, done.
Resolving deltas: 100% (5159/5159), done.

و اگر به پوشه کپی کاری خود نگاهی بیندازیم ، می بینیم که فایلهای کتابخانه در واقع وارد پروژه ما شده اند.

فایلهای کتابخانه ما در اینجا ، در یک زیرمجموعه گنجانده شده است

“پس چه فرقی می کند؟” ممکن است بپرسید به هر حال ، فایلهای کتابخانه شخص ثالث اینجا هستند ، درست مانند زمانی که ما آنها را کپی پیست کرده بودیم. تفاوت اساسی در واقع این است که آنها هستند موجود در مخزن Git خود! اگر ما فقط برخی از فایلها را بارگیری کرده ، آنها را در پروژه خود پرتاب کرده و سپس آنها را متعهد می کردیم – مانند سایر فایلهای پروژه ما – آنها بخشی از یک مخزن Git بودند. با این حال ، زیرمجموعه اطمینان حاصل می کند که فایلهای کتابخانه به مخزن پروژه اصلی ما “نشت” نمی کند.

بگذارید ببینیم دیگر چه اتفاقی افتاده است: یک مورد جدید .gitmodules فایل در پوشه اصلی پروژه اصلی ما ایجاد شده است. در اینجا چیزی است که شامل می شود:

[submodule "lib/spacetime"]
  path = lib/spacetime
  url = https://github.com/spencermountain/spacetime.git

این .gitmodules فایل یکی از چندین مکان است که در آن Git زیرمجموعه های پروژه ما را پیگیری می کند. یکی دیگر است .git/config، که اکنون به این شکل به پایان می رسد:

[submodule "lib/spacetime"]
  url = https://github.com/spencermountain/spacetime.git
  active = true

و سرانجام ، Git همچنین یک کپی از هر زیرمجموعه را ذخیره می کند .git مخزن در یک داخلی .git/modules پوشه

همه اینها جزئیات فنی هستند که لازم نیست آنها را به خاطر بسپارید. با این حال ، احتمالاً به شما کمک می کند بفهمید که نگهداری داخلی زیرمجموعه های Git بسیار پیچیده است. به همین دلیل مهم است که یک چیز را حذف کنید: با تنظیمات زیر ماژول Git با دست درگیر نشوید! اگر می خواهید یک زیرمجموعه را جابجا ، حذف یا دستکاری کنید ، لطفاً به خودتان لطف کنید و انجام دهید نه این را به صورت دستی امتحان کنید یا از دستورات مناسب Git استفاده کنید یا a رابط کاربری گرافیکی برای Git مانند “Tower”، که از این جزئیات برای شما مراقبت می کند.

GUI های رومیزی Git مانند Tower مدیریت زیرمجموعه های Git را آسان تر می کند

بیایید نگاهی به وضعیت پروژه اصلی خود بیاندازیم ، در حال حاضر که ماژول فرعی را اضافه کرده ایم:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  new file:   .gitmodules
  new file:   lib/spacetime

همانطور که مشاهده می کنید ، Git افزودن یک زیرمجموعه را به عنوان تغییری مانند سایر موارد در نظر می گیرد. بر این اساس ، ما باید این تغییر را مانند سایر تغییرات انجام دهیم:

$ git commit -m "Add timezone converter library as a submodule"

شبیه سازی یک پروژه با Git Submodules

در مثال بالا ، ما یک زیرمجموعه جدید را به مخزن موجود Git اضافه کردیم. اما در مورد “برعکس” ، وقتی یک مخزن آن را کلون می کنید ، چطور؟ در حال حاضر شامل زیر ماژول ها؟

اگر وانیلی اجرا کردیم git clone <remote-URL> در خط فرمان ، پروژه اصلی را بارگیری می کنیم – اما هر پوشه فرعی را خالی می بینیم! این بار دیگر ثابت می کند که فایل های زیر ماژول جدا هستند و نه در مخازن والدین آنها گنجانده شده است.

در چنین حالتی ، برای پر کردن زیرمجموعه ها پس از کلون کردن مخزن اصلی آنها ، می توانید به سادگی اجرا کنید git submodule update --init --recursive پس از آن راه حتی بهتر این است که به سادگی آن را اضافه کنید --recurse-submodules گزینه درست هنگام تماس git clone در وهله اول

بررسی نسخه های بازبینی شده

در مخزن “معمولی” Git ، ما معمولاً شاخه ها را بررسی می کنیم. با استفاده از git checkout <branchname> یا جدیدتر git switch <branchname>، ما به Git می گوییم که شعبه فعلی ما باید چه باشد. وقتی تعهدات جدیدی در این شاخه ایجاد می شود ، نشانگر HEAD است به طور خودکار جابجا شد به آخرین تعهد درک این مهم است – زیرا زیرمجموعه های Git متفاوت عمل می کنند!

در یک ماژول فرعی ، ما همیشه یک نسخه خاص را بررسی می کنیم – نه یک شعبه! حتی وقتی در حال اجرای دستوراتی مانند هستید git checkout main در یک زیرمدل ، در پس زمینه ، جدیدترین در حال حاضر مرتکب شدن در آن شاخه ذکر شده است – نه خود شاخه.

البته این رفتار اشتباه نیست. در مورد آن فکر کنید: وقتی کتابخانه شخص ثالث را وارد می کنید ، می خواهید کنترل کاملی بر کد دقیق مورد استفاده در پروژه اصلی خود داشته باشید. وقتی نگهدارنده کتابخانه نسخه جدیدی را منتشر می کند ، همه چیز خوب و خوب است … اما شما لزوما نمی خواهید این نسخه جدید بطور خودکار در پروژه شما استفاده می شود فقط به این دلیل که نمی دانید ممکن است تغییرات جدید شکسته شوند یا خیر شما پروژه!

اگر می خواهید دریابید که فرمت های فرعی شما از چه نسخه ای استفاده می کنند ، می توانید این اطلاعات را در پروژه اصلی خود درخواست کنید:

$ git submodule status
   ea703a7d557efd90ccae894db96368d750be93b6 lib/spacetime (6.16.3)

این نسخه فعلی بررسی شده ما را برمی گرداند lib/spacetime زیر ماژول و همچنین به ما اطلاع می دهد که این نسخه یک برچسب است ، به نام “6.16.3”. استفاده از برچسب ها در هنگام کار با زیرمجموعه ها در Git بسیار رایج است.

فرض کنید می خواهید زیرمجموعه خود از an استفاده کند مسن تر نسخه ، که برچسب “6.14.0” را داشت. ابتدا ، ما باید دایرکتوری ها را تغییر دهیم تا دستور Git ما در زمینه زیر ماژول اجرا شود ، نه پروژه اصلی ما. سپس ، ما به سادگی می توانیم اجرا کنیم git checkout با نام برچسب:

$ cd lib/spacetime/
$ git checkout 6.14.0
Previous HEAD position was ea703a7 Merge pull request 
HEAD is now at 7f78d50 Merge pull request 

اگر اکنون به پروژه اصلی خود بازگردیم و اجرا کنیم git submodule status مجدداً ، پرداخت ما را منعکس می کنیم:

$ cd ../..
$ git submodule status
+7f78d50156ae1205aa50675ddede81a61a45fade lib/spacetime (6.14.0)

با این حال ، خروجی را از نزدیک بررسی کنید: کمی + نماد روبروي آن هش SHA-1 به ما مي گويد كه خرده ماژول در نسخه اي متفاوت از آنچه كه در مخزن والد ذخيره شده است قرار دارد. همانطور که ما نسخه بازبینی شده را تغییر دادیم ، این درست به نظر می رسد.

صدا زدن git status در پروژه اصلی ما اکنون ما را در مورد این واقعیت نیز مطلع می کند:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  modified:   lib/spacetime (new commits)

می بینید که Git نشانگر یک زیرمدول را مانند هر تغییری در نظر می گیرد: اگر می خواهیم ذخیره شود باید آن را به مخزن متعهد کنیم:

$ git commit -m "Changed checked out revision in submodule"
$ git push

به روز رسانی یک زیرمجموعه Git

در مراحل بالا ، چنین بود ما که اشاره گر زیرمودول را جابجا کرد: ما کسانی بودیم که یک نسخه متفاوت را بررسی کردیم ، متعهد شدیم و آن را به مخزن راه دور تیم خود هدایت کردیم. اما اگر یکی از همکاران ما تجدیدنظر زیرمودول را تغییر دهد ، چه اتفاقی می افتد – شاید به این دلیل که یک نسخه جدید جالب از زیر ماژول منتشر شد و همکار ما تصمیم گرفت از این پروژه در پروژه ما استفاده کند (البته پس از آزمایش کامل …).

بیایید یک کار ساده انجام دهیم git pull در پروژه اصلی ما – همانطور که احتمالاً اغلب اوقات انجام می دهیم – برای دریافت تغییرات جدید از مخزن راه دور مشترک:

$ git pull
From https://github.com/gntr/git-crash-course
   d86f6e0..055333e  main       -> origin/main
Updating d86f6e0..055333e
Fast-forward
   lib/spacetime | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)

خط دوم تا آخر نشان می دهد که چیزی در زیر ماژول ما تغییر کرده است. اما بیایید نگاه دقیق تری داشته باشیم:

$ git submodule status
+7f78d50156ae1205aa50675ddede81a61a45fade lib/spacetime (6.14.0)

من مطمئنم که شما آن کمی را به خاطر می آورید + علامت: این بدان معناست که اشاره گر زیر ماژول منتقل شد! برای به روز رسانی نسخه بازبینی شده محلی خود به نسخه “رسمی” که هم تیمی ما انتخاب کرده است ، می توانیم برنامه را اجرا کنیم update دستور:

$ git submodule update lib/spacetime 
Submodule path 'lib/spacetime': checked out '5e3d70a88180879ae0222b6929551c41c3e5309e'

بسیار خوب! زیرمجموعه ما اکنون با بازبینی که در مخزن اصلی پروژه ما ثبت شده است ، بررسی شده است!

کار با Submodules در Git

ما اجزای اساسی کار با زیرمجموعه های Git را پوشش داده ایم. گردشهای کار دیگر واقعا استاندارد هستند!

بررسی تغییرات جدید به عنوان مثال ، در یک ماژول فرعی ، مانند سایر مخازن Git کار می کند: شما a را اجرا می کنید git fetch دستور داخل مخزن زیرمجموعه ، احتمالاً با چیزی شبیه به آن دنبال می شود git pull origin main اگر واقعاً می خواهید از به روز رسانی استفاده کنید.

ایجاد تغییرات در زیرمدل همچنین ممکن است برای شما مورد استفاده قرار گیرد ، به خصوص اگر کد کتابخانه را خودتان مدیریت می کنید (زیرا یک کتابخانه داخلی است ، نه شخص ثالث). شما می توانید مانند زیر مخزن دیگر Git با زیرمجموعه کار کنید: می توانید تغییراتی ایجاد کنید ، آنها را مرتکب شوید ، آنها را تحت فشار قرار دهید و غیره.

استفاده از قدرت کامل Git

Git قدرت زیادی در زیر کاپوت دارد. اما بسیاری از ابزارهای پیشرفته آن – مانند زیر ماژول های Git – شناخته شده نیستند. واقعاً حیف است که بسیاری از توسعه دهندگان چیزهای قدرتمند زیادی را از دست داده اند!

اگر می خواهید عمیق تر شده و نیم نگاهی به دیگران داشته باشید تکنیک های پیشرفته Git، من به شدت توصیه می کنم “کیت پیشرفته Git“: این مجموعه ای (رایگان!) از فیلم های کوتاه است که شما را با موضوعاتی مانند Reflog ، Intebractive Rebase ، Cherry-Picking و حتی استراتژی های شاخه ای آشنا می کند.

از تبدیل شدن به یک توسعه دهنده بهتر لذت ببرید!