| GIT-SUBTREE(1) | Git Manual | GIT-SUBTREE(1) |
نام (NAME)
git-subtree - ادغام زیردرختها با یکدیگر و تقسیم مخزن به زیردرختها
خلاصه دستور (SYNOPSIS)
git subtree [<options>] -P <prefix> [-S[<keyid>]] add <local-commit> git subtree [<options>] -P <prefix> [-S[<keyid>]] add <repository> <remote-ref> git subtree [<options>] -P <prefix> [-S[<keyid>]] merge <local-commit> [<repository>] git subtree [<options>] -P <prefix> [-S[<keyid>]] split [<local-commit>]
git subtree [<options>] -P <prefix> [-S[<keyid>]] pull <repository> <remote-ref> git subtree [<options>] -P <prefix> [-S[<keyid>]] push <repository> <refspec>
توضیحات (DESCRIPTION)
زیردرختها (subtrees) اجازه میدهند زیرپروژهها در یک زیرپوشه از پروژه اصلی گنجانده شوند، و به صورت اختیاری تمام تاریخچه زیرپروژه را نیز در بر گیرند.
به عنوان مثال، میتوانید کد منبع یک کتابخانه را به عنوان یک زیرپوشه از برنامه کاربردی خود اضافه کنید.
زیردرختها نباید با زیرماژولها (submodules) که برای هدفی مشابه در نظر گرفته شدهاند، اشتباه گرفته شوند. بر خلاف زیرماژولها، زیردرختها به هیچ ساختار ویژهای (مانند فایلهای .gitmodules یا gitlinks) در مخزن شما نیاز ندارند و کاربران نهایی مخزن شما را وادار نمیکنند کار خاصی انجام دهند یا نحوه کار زیردرختها را یاد بگیرند. یک زیردرخت تنها یک زیرپوشه است که میتوان مانند هر بخش دیگری از پروژه روی آن کامیت زد، شاخه ایجاد کرد و آن را ادغام نمود.
همچنین نباید آنها را با استفاده از راهبرد ادغام زیردرخت (subtree merge strategy) اشتباه گرفت. تفاوت اصلی در این است که علاوه بر ادغام پروژه دیگر به عنوان یک زیرپوشه، میتوانید کل تاریخچه یک زیرپوشه را از پروژه خود استخراج کرده و آن را به یک پروژه مستقل تبدیل کنید. بر خلاف راهبرد ادغام زیردرخت، میتوانید به صورت رفتوبرگشتی بین این دو عملیات جابهجا شوید. اگر کتابخانه مستقل بهروزرسانی شود، میتوانید به صورت خودکار تغییرات را در پروژه خود ادغام کنید؛ اگر کتابخانه را درون پروژه خود بهروزرسانی کنید، میتوانید تغییرات را دوباره تفکیک (split) کرده و مجدداً در پروژه کتابخانه ادغام نمایید.
برای مثال، اگر کتابخانهای که برای یک برنامه کاربردی ساختهاید در جای دیگری نیز مفید واقع شود، میتوانید کل تاریخچه آن را استخراج کرده و به عنوان مخزن گیت مستقل منتشر کنید، بدون اینکه به اشتباه تاریخچه پروژه اصلی شما با آن آمیخته شود.
نکته
به منظور تمیز نگه داشتن پیامهای کامیت، توصیه میکنیم تا حد امکان کامیتهای خود را بین زیردرختها و پروژه اصلی تفکیک کنید. به عبارت دیگر، اگر تغییری ایجاد میکنید که هم روی کتابخانه و هم روی برنامه اصلی تأثیر میگذارد، آن را در دو کامیت جداگانه ثبت کنید. به این ترتیب، زمانی که بعداً کامیتهای کتابخانه را تفکیک میکنید، توضیحات آنها همچنان با مفهوم خواهند بود. اما اگر این موضوع برای شما اهمیتی ندارد، انجام آن ضروری نیست. دستور git subtree به سادگی بخشهای غیرمرتبط با کتابخانه در کامیت را هنگام تفکیک آن به زیرپروژه نادیده میگیرد.
دستورها (COMMANDS)
add <local-commit>, add <repository> <remote-ref>
merge <local-commit> [<repository>]
اگر از --squash استفاده کنید، جهت ادغام همواره نیازی نیست رو به جلو باشد؛ برای مثال، میتوانید از این دستور برای بازگشت در زمان از v2.5 به v2.4 استفاده کنید. اگر ادغام شما باعث ایجاد تداخل شود، میتوانید آن را به روشهای معمول برطرف کنید.
هنگام استفاده از --squash, اگر ادغام قبلی با --squash یک برچسب نشانهدار (annotated tag) از مخزن زیردرخت را ادغام کرده باشد، آن برچسب باید به صورت محلی در دسترس باشد. اگر <repository> داده شود، برچسب مفقود به صورت خودکار از آن مخزن واکشی خواهد شد.
split [<local-commit>] [<repository>]
پس از تفکیک موفق، یک شناسه کامیت منفرد در خروجی استاندارد چاپ میشود. این شناسه متناظر با HEAD درخت ایجادشده جدید است که میتوانید آن را به هر نحو دلخواه مدیریت کنید.
تفکیکهای مکرر بر روی دقیقاً همان تاریخچه تضمین میشود که یکسان باشند (یعنی شناسههای کامیت یکسانی تولید کنند) تا زمانی که تنظیمات ارائهشده به split (مانند --annotate) یکسان باشند. به همین دلیل، اگر کامیتهای جدیدی اضافه کنید و مجدداً تفکیک نمایید، کامیتهای جدید به عنوان کامیتهایی روی تاریخچه تولیدشده قبلی پیوست میشوند، بنابراین git merge و دستورهای مرتبط همانطور که انتظار میرود کار خواهند کرد.
هنگامی که یک ادغام قبلی با --squash یک برچسب نشانهدار از مخزن زیردرخت را ادغام کرده باشد، آن برچسب باید به صورت محلی در دسترس باشد. اگر <repository> مشخص شده باشد، برچسب مفقود به صورت خودکار از آن مخزن دریافت خواهد شد.
pull <repository> <remote-ref>
push <repository> [+][<local-commit>:]<remote-ref>
گزینهها برای همه دستورها (OPTIONS FOR ALL COMMANDS)
-q, --quiet
-d, --debug
-P <prefix>, --prefix=<prefix>
-S[<keyid>], --gpg-sign[=<keyid>], --no-gpg-sign
گزینهها برای ADD و MERGE (همچنین: PULL، SPLIT --REJOIN، و PUSH --REJOIN)
این گزینهها برای add و merge همچنین میتوانند به pull (که merge را پوشش میدهد)، split --rejoin (که بسته به مورد add یا merge را پوشش میدهد)، و push --rejoin (که split --rejoin را پوشش میدهد) داده شوند.
--squash
استفاده از این گزینه به کاهش شلوغی گزارش تاریخچه (log) کمک میکند. کاربران به ندرت میخواهند همه تغییراتی را که بین نسخه v1.0 و v1.1 کتابخانه رخ داده است ببینند، زیرا هیچیک از نسخههای میانی هرگز در برنامه آنها گنجانده نشده است.
استفاده از --squash همچنین به جلوگیری از مشکلاتی کمک میکند که در آنها یک زیرپروژه یکسان چندین بار در یک پروژه اضافه شده یا حذف و مجدداً اضافه میشود. در چنین حالتی، ترکیب تاریخچهها در هر صورت منطقی نیست، زیرا مشخص نیست کدام بخش از تاریخچه به کدام زیردرخت تعلق دارد.
علاوه بر این، با --squash, میتوانید بین نسخههای مختلف یک زیردرخت به جلو و عقب جابهجا شوید، نه صرفاً رو به جلو. دستور git subtree merge --squash همیشه زیردرخت را دقیقاً مطابق با کامیت مشخصشده تنظیم میکند، حتی اگر رسیدن به آن کامیت مستلزم بازگرداندن تغییراتی باشد که قبلاً اضافه شده بودند.
چه از --squash استفاده کنید یا خیر، تغییرات ایجادشده در مخزن محلی شما دستنخورده باقی میمانند و میتوان بعداً آنها را تفکیک کرده و به بالادست به زیرپروژه ارسال نمود.
-m <message>, --message=<message>
گزینهها برای SPLIT (همچنین: PUSH)
این گزینهها برای split همچنین میتوانند به push (که split را پوشش میدهد) داده شوند.
--annotate=<annotation>
هر بار که عملیات تفکیک را انجام میدهید، باید از همان <annotation> یکسان استفاده کنید؛ در غیر این صورت تضمینی وجود ندارد که تاریخچه بازتولیدشده جدید با تاریخچه قبلی یکسان باشد. این موضوع مانع از کارکرد صحیح عملیات ادغام خواهد شد. ابزار git subtree تلاش میکند تا در هر صورت کار را پیش ببرد، به ویژه اگر از --rejoin استفاده کنید، اما ممکن است همیشه کارساز نباشد.
-b <branch>, --branch=<branch>
--ignore-joins
--onto=<onto>
اگر از git subtree add استفاده کردهاید، هرگز به این گزینه نیاز نخواهید داشت.
--rejoin
اگر کامیتهای تفکیکشده شما در نهایت در زیرپروژه بالادست ادغام شوند و سپس بخواهید آخرین نسخه بالادست را دریافت کنید، این امر به الگوریتم ادغام گیت اجازه میدهد هوشمندانهتر از تداخلها جلوگیری کند (چرا که میداند این کامیتهای ترکیبی از قبل بخشی از مخزن بالادست هستند).
متأسفانه، استفاده از این گزینه باعث میشود git log یک نسخه اضافی از هر کامیت جدید ایجادشده (نسخه اصلی و نسخه ترکیبی) را نمایش دهد.
اگر تمام ادغامهای خود را با --squash انجام میدهید، مطمئن شوید که هنگام اجرای split --rejoin نیز از --squash استفاده میکنید.
مثال ۱. دستور ADD
فرض کنید یک مخزن محلی دارید و میخواهید یک کتابخانه خارجی را به آن اضافه کنید. در این مثال، مخزن git-subtree را به عنوان یک زیرپوشه از مخزن موجود git-extensions در مسیر ~/git-extensions/ اضافه میکنیم:
$ git subtree add --prefix=git-subtree --squash \
git://github.com/apenwarr/git-subtree.git master
عبارت master باید یک ارجاع ریموت معتبر باشد و میتواند نام شاخه دیگری باشد.
میتوانید از پرچم --squash صرفنظر کنید، اما انجام این کار تعداد کامیتهای موجود در مخزن محلی شما را افزایش میدهد.
اکنون در مخزن git-extensions خود، یک پوشه ~/git-extensions/git-subtree داریم که حاوی کدهای شاخه master از git://github.com/apenwarr/git-subtree.git است.
مثال ۲. استخراج یک زیردرخت با استفاده از COMMIT، MERGE و PULL
بیایید از مخزن کد منبع git به عنوان مثال استفاده کنیم. ابتدا، نسخه خود را از مخزن git.git دریافت کنید:
$ git clone git://git.kernel.org/pub/scm/git/git.git test-git $ cd test-git
ابزار gitweb (کامیت 1130ef3) از زمان کامیت 0a8f4f0 در git ادغام شد و پس از آن دیگر به طور مستقل نگهداری نشد. اما فرض کنید که به طور مستقل نگهداری میشد و ما میخواستیم تغییرات گیت در gitweb را از آن زمان به بعد استخراج کنیم تا با پروژه بالادست به اشتراک بگذاریم. میتوانید این کار را انجام دهید:
$ git subtree split --prefix=gitweb --annotate='(split) ' \
0a8f4f0^.. --onto=1130ef3 --rejoin \
--branch gitweb-latest
$ gitk gitweb-latest
$ git push git@github.com:whatever/gitweb.git gitweb-latest:master
(ما از 0a8f4f0^.. استفاده میکنیم زیرا به معنای «تمام تغییرات از 0a8f4f0 تا نسخه فعلی، شامل خود 0a8f4f0» است.)
اگر gitweb در ابتدا با استفاده از git subtree add ادغام شده بود (یا یک تفکیک قبلی با مشخص کردن --rejoin انجام شده بود)، آنگاه میتوانستید تمام تفکیکهای خود را بدون نیاز به به خاطر سپردن شناسههای نامتعارف کامیت انجام دهید:
$ git subtree split --prefix=gitweb --annotate='(split) ' --rejoin \
--branch gitweb-latest2
و میتوانید تغییرات را به همان سادگی از پروژه بالادستی ادغام کنید:
$ git subtree pull --prefix=gitweb \
git@github.com:whatever/gitweb.git master
یا با استفاده از --squash، میتوانید در واقع به نسخه قبلی gitweb برگردید:
$ git subtree merge --prefix=gitweb --squash gitweb-latest~10
سپس تغییراتی اعمال کنید:
$ date >gitweb/myfile $ git add gitweb/myfile $ git commit -m 'created myfile'
و دوباره به جلو حرکت سریع (fast-forward) انجام دهید:
$ git subtree merge --prefix=gitweb --squash gitweb-latest
و مشاهده کنید که تغییرات شما همچنان دستنخورده باقی مانده است:
$ ls -l gitweb/myfile
و میتوانید آن را تفکیک کرده و تغییرات خود را نسبت به gitweb استاندارد مشاهده کنید:
git log gitweb-latest..$(git subtree split --prefix=gitweb)
مثال ۳. استخراج یک زیردرخت با استفاده از یک شاخه
فرض کنید یک دایرکتوری سورس با فایلها و زیرپوشههای فراوان دارید و میخواهید دایرکتوری lib را به پروژه گیت مستقل خود تبدیل کنید. روش سریعی برای انجام این کار در ادامه آورده شده است:
ابتدا، مخزن جدید را در هر مکانی که میخواهید ایجاد کنید:
$ <go to the new location> $ git init --bare
بازگشت به دایرکتوری اصلی شما:
$ git subtree split --prefix=lib --annotate="(split)" -b split
سپس شاخه جدید را به مخزن خالی جدید ارسال کنید:
$ git push <new-repo> split:master
نویسنده (AUTHOR)
نوشتهشده توسط Avery Pennarun <apenwarr@gmail.com[1]>
GIT
بخشی از مجموعه git(1)
نکات (NOTES)
- 1.
- apenwarr@gmail.com
| 2026-06-29 | Git 2.55.0 |