سرفصل‌های آموزشی
آموزش گیت
آشنایی با کاربرد Branch در Git

آشنایی با کاربرد Branch در Git

زمانی که با استفاده از گیت یک ریپازیتوری جدید می‌سازیم، به صورت خودکار یک برنچ (شاخه) تحت عنوان master ساخته می‌شود که نقش شاخهٔ اصلی ریپازیتوری مذکور را بازی خواهد کرد و هر کامیتی که انجام دهیم نیز روی این شاخه اِعمال خواهد شد و این در حالی است که معمولاً‌ تیم‌های نرم‌افزاری از این شاخه به عنوان نسخه‌ای از نرم‌افزار استفاده می‌کنند که قرار است روی سرورهای اصلی دیپلوی گردد. با این تفاسیر، منطقی به نظر می‌رسد که این بِرَنچ به عنوان فضای آزمون و خطا در حین کدنویسی قملداد نشده بلکه فضاها یا بهتر بگوییم شاخه‌های فرعی دیگری ساخته و در آن‌ها اقدام به توسعهٔ فیچرهای جدید نموده سپس آن‌ها را با شاخهٔ مَستر ادغام نمود.

یکی از مزایای وجود شاخه‌ها در سیستم کنترل نسخهٔ گیت آن است که می‌توان به تعداد توسعه‌دهندگانی که در تیم حضور دارند برنچ‌های اختصاصی ساخته و در آنِ واحد تمامی اعضای تیم بتوانند اقدام به توسعهٔ نرم‌افزار کنند. برای درک بهتر این موضوع، فرض کنیم دولوپری داریم به نام بهزاد قرار است قابلیت درگاه پرداخت را به پروژه بیفزاید و دولوپر دیگری به نام سهند قرار است تا رابط کاربری را تکمیل کند؛ در چنین شرایطی، می‌توان دو شاخهٔ‌ فرعی از شاخهٔ مَستر تحت عناوین دلخواهی همچون behzad-branch-gateway و sahand-branch-ui ایجاد کرده و هر کدام از ایشان با سهولت هرچه تمام‌تر شروع به کدنویسی کرده و چنانچه در نهایت کدهای نوشته‌شده مورد تأیید مدیر فنی بود،‌ با شاخهٔ اصلی (مَستر) ادغام خواهند شد.

همان‌طور که در تصویر فوق ملاحظه می‌شود، خط افقی که در سراسر نمودار ملاحظه می‌شود به عنوان بِرَنچ اصلی یا مَستر است که فرض می‌کنیم توسط توسعه‌دهندهٔ اصلی پروژه کامیت‌هایی تحت عناوین C1 و C2 انجام شده است. سپس یک شاخه از شاخهٔ اصلی جدا شده و نامی دلخواه همچون Branch1 برای آن در نظر گرفته‌ایم که فرضاً توسط یکی از اعضای تیم هَندل می‌گردد به طوری که وی سه کامیت داخل این شاخه انجام داده است. در آنِ واحد،‌ برای یکی دیگر از اعضای تیم شاخه‌ای به نام Branch2 ساخته شده و او نیز یک کامیت انجام داده است. در نهایت، دولوپر اصلی این پروژه کلیهٔ تغییرات اِعمال‌شده در دو بِرَنچ فوق را با بِرَنچ اصلی (مَستر) ادغام کرده و کلیهٔ‌ این تغییرات را تحت عنوان C7 کامیت کرده است.

با این توضیحات تئوریک،‌ در ادامهٔ‌ این آموزش خواهیم دید که به چه شکل به صورت عملی می‌توانیم اقدام به ساخت بِرَنچ‌های مختلف کرده سپس آن‌ها را با یکدیگر ادغام نمود.

برای شروع کار با بِرَنچ‌ها، ابتدا کامند زیر را اجرا می‌کنیم:

/var/www/git-tutorial$ git branch
* master

اساساً دستور branch لیستی از کلیهٔ بِرَنچ‌ها را در معرض دیدمان قرار می‌دهد و همان‌طور که پیش از این گفتیم، پس از شروع استفاده از گیت یک بِرَنچ اصلی تحت عنوان master ساخته می‌شود و همان‌طور که در خروجی فوق ملاحظه می‌شود، علامت * نشان می‌دهد که در حال حاضر این بِرَنچ در حال استفاده است.

    نکته

توجه داشته باشیم که در نام‌گذاری شاخه‌ها نمی‌توان از اِسپیس (فاصله) استفاده نمود.

فرض کنیم که می‌خواهیم شروع به استایل دادن به فایل اچ‌تی‌ام‌ال کنیم که این کار وظیفهٔ‌ دولوپر فرانت‌اند است. برای همین منظور، یک بِرَنچ جدید اختصاصاً برای وی به صورت زیر می‌سازیم:

/var/www/git-tutorial$ git branch ui-feature

در واقع،‌ پس از دستور branch از نامی دلخواه بدون اِسپیس استفاده کرده‌ایم و اگر مجدد به لیست بِرَنچ‌ها نگاهی بیندازیم، خواهیم داشت:

/var/www/git-tutorial$ git branch
* master
  ui-feature

می‌بینیم که بِرَنچ جدید اضافه شده اما کماکان شاخهٔ مَستر در حالت انتخاب قرار دارد که برای سوئیچ کردن به بِرَنچ جدید، از دستور زیر می‌باید استفاده کرد:

/var/www/git-tutorial$ git checkout ui-feature 
Switched to branch 'ui-feature'

اگر مجدد به لیست بِرَنچ‌ها نگاهی بیندازیم، خواهیم دید:

/var/www/git-tutorial$ git branch
  master
* ui-feature

می‌بینیم که بِرَنچ اختصاصی توسعه‌دهندهٔ فرانت‌اند انتخاب شده است. حال جهت تست، در مسیر روت پروژه فایلی تحت عنوان styles.css حاوی کدهای سی‌اس‌اس زیر می‌سازیم:

body {
    background: #ffde57;
}

اکنون این فایل را کامیت کرده و سپس لاگ می‌گیریم:

/var/www/git-tutorial$ git add styles.css
/var/www/git-tutorial$ git commit -m "stylesheet added"
[ui-feature b276cac] stylesheet added
 1 file changed, 3 insertions(+)
 create mode 100644 styles.css

‌می‌بینیم که در پیامی که پس از کامیت کردن در معرض دیدمان قرار گرفته است،‌ آمده که کامیت مذکور در شاخهٔ‌ ui-feature افزوده شده است که این موضوع در لاگ گیت هم نشان داده می‌شود:

/var/www/git-tutorial$ git log --oneline
b276cac (HEAD -> ui-feature) stylesheet added
23d2256 (master) a new line added
fd728ca Yet another commit

حال مجدد به بِرَنچ master سوئیچ می‌‌کنیم:

/var/www/git-tutorial$ git checkout master 
Switched to branch 'master'

اکنون اگر به محتویات داخل پوشه نگاهی بیندازیم،‌ خواهیم دید که فایل styles.css حذف شده است و این مسئله از آنجا ناشی می‌گردد که ما این فایل را در بِرَنچ ui-feature افزوده‌ایم و بِرَنچ master هیچ اطلاعی از این موضوع ندارد. فرض کنیم که تغییرات اِعمال‌شده توسط توسعه‌دهندهٔ فرانت‌اند مورد تأیید هستند و می‌خواهیم آن‌ها را با بِرَنچ اصلی ادغام نماییم، اما پیش از بررسی این موضوع قصد داریم ببینیم که به چه شکل می‌توان یک بِرَنچ را حذف کرد:

/var/www/git-tutorial$ git branch -d ui-feature 
error: The branch 'ui-feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D ui-feature'.

با استفاده از آپشن d- و آوردن نام شاخهٔ مد نظر،‌ می‌توان این کار را عملی ساخت اما همان‌طور که ملاحظه می‌شود، خطایی با این مضمون در معرض دیدمان قرار گرفته که «شاخهٔ ui-feature با شاخهٔ اصلی ادغام نشده است و اگر از حذف آن مطمئن هستید،‌ می‌باید به جای آپشن d- از D- استفاده نمایید.» که برای این منظور داریم:

/var/www/git-tutorial$ git branch -D ui-feature 
Deleted branch ui-feature (was b276cac).

اکنون اگر به لیست بِرَنچ‌ها نگاهی بیندازیم خواهیم داشت:

/var/www/git-tutorial$ git branch
* master

می‌بینیم که بِرَنچ مد نظرمان حذف شده و صرافاً بِرَنچ اصلی موجود داشت. حال برای آن که ببینیم به چه شکل می‌توان دو بِرَنچ را با یکدیگر ادغام نمود، ابتدا اقدام به ساخت یک بِرَنچ جدید می‌کنیم اما این بار با استفاده یک دستور ترکیبی این کار را انجام خواهیم داد:

/var/www/git-tutorial$ git checkout -b new-branch
Switched to a new branch 'new-branch'

پس از دستور checkout، با استفاده از آپشن b- که برگرفته از واژهٔ‌ Branch است بِرَنچ جدیدی تحت عنوان new-branch ساخته‌ایم و این در حالی است که نسبت به روش قبلی ساخت یک بِرَنچ جدید، بلافاصله به این بِرَنچ سوئیچ شده‌ایم که برای اطمینان حاصل کردن از این موضوع،‌ می‌توانیم کامند زیر را اجرا کنیم:

/var/www/git-tutorial$ git branch
  master
* new-branch

طبق روال گذشته، فایلی تحت عنوان styles.css ساخته کدی دلخواه داخلش می‌نویسیم و آن را کامیت می‌کنیم:

/var/www/git-tutorial$ git add styles.css 
/var/www/git-tutorial$ git commit -m "stylesheet added"
[new-branch e6d18e7] stylesheet added
 1 file changed, 3 insertions(+)
 create mode 100644 styles.css

با سوئیچ کردن به بِرَنچ مَستر با استفاده دستوری که پیش از این فرا گرفتیم،‌ می‌بینیم که این فایل قابل‌مشاهده نیست. حال فرض کنیم دولوپر دیگری در تیم داریم که این وظیفه را دارا است تا روی کدهای جاوااسکریپت کار کند که در همین راستا، بِرَنچ جدیدی به صورت زیر برای وی می‌سازیم:

/var/www/git-tutorial$ git checkout -b js-branch
Switched to a new branch 'js-branch'

در این مرحله از آموزش،‌ فایلی با نامی دلخواه همچون main.js ساخته و کدهای زیر را داخل آن می‌نویسیم:

console.log('something ...');

سپس تغییراتی که در این مرحله از کار اِعمال شده‌اند را کامیت می‌کنیم:

/var/www/git-tutorial$ git commit -m "a js file added"
[js-branch 3902bd7] a js file added
 1 file changed, 1 insertion(+)
 create mode 100644 main.js

حال قصد داریم تا تغییرات را با شاخهٔ اصلی ادغام کنیم که برای این منظور،‌ ابتدا می‌باید وارد شاخهٔ master شویم:

/var/www/git-tutorial$ git checkout master 
Switched to branch 'master'

سپس با استفاده از دستور merge به صورت زیر‌،‌ قصد داریم تا شاخهٔ اولی که ساختیم را ادغام کنیم:

/var/www/git-tutorial$ git merge new-branch 
Updating 23d2256..e6d18e7
Fast-forward
 styles.css | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 styles.css

همان‌طور که ملاحظه می‌شود، کلیهٔ‌ تغییرات انجام‌شده در این شاخه به شاخهٔ اصلی (مَستر) انتقال یافته و از این پس شاهد فایل styles.css در شاخهٔ مَستر خواهیم بود (اصطلاح Fast-forward حاکی از آن است که بِرَنچ مَستر هیچ گونه تغییری نداشته بلکه فقط یک بِرَنچ دیگر با آن ادغام شده است.) طبق همین روال،‌ بِرَنچ دیگر را نیز ادغام می‌کنیم:

/var/www/git-tutorial$ git merge js-branch 
Merge made by the 'recursive' strategy.
 main.js | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 main.js

تفاوت در این پروسه نسبت به مرحلهٔ‌ قبل در آن است که مجدد ادیتور پیش‌فرض سیستم باز شده و پیامی در معرض دیدمان قرار می‌گیرد که همچون روال قبل، اگر ادیتور مذکور nano باشد می‌توان دکمه‌های Ctrl + X را فشرد و در متن پیامی که پس از اجرای کامند فوق در معرض دیدمان قرار می‌گیرد جملهٔ .Merge made by the 'recursive' strategy آمده و دلیلش هم آن است که پس از ادغام بِرَنچ new-feature، این بار بِرَنچ مَستر خود نیز آپدیت شده است چرا که کدهای داخل بِرَنچ new-branch به آن افزوده شده‌اند و از همین روی همچون مورد قبل شاهد پیام Fast-forward نخواهیم بود. به هر روی، می‌بینیم که از این پس فایل main.js نیز به شاخهٔ‌ اصلی افزوده شده است و قابل‌روئیت است.

آشنایی با مفهوم Conflict در Git

آنچه در ارتباط با ساخت بِرَنچ‌های مختلف معمولاً به کَرات رخ می‌دهد،‌ مفهومی است تحت عنوان Conflict یا «تداخل» که یک توسعه‌‌دهنده‌ای که با گیت کار می‌کند حتماً‌ می‌باید با روش‌های حل کانفلیکت‌ها آشنا باشد. برای درک بهتر این موضوع، یک بِرَنچ جدید می‌سازیم:

/var/www/git-tutorial$ git checkout -b another-branch
Switched to a new branch 'another-branch'

بِرَنچ جدیدی تحت عنوان another-branch ساخته شده که حاوی کلیهٔ تغییراتی است که تاکنون در بِرَنچ master رخ داده‌اند؛‌ به عبارتی،‌ حاوی کدهای نوشته‌شده در بِرَنچ‌های new-branch و js-branch است. در این مرحله،‌ با استفاده از دستور git checkout master مجدد به شاخهٔ اصلی سوئیچ می‌کنیم و تغییراتی در فایل styles.css به صورت زیر می‌دهیم:

body {
    background: #ffde57;
    font-size: 12px;
}

همان‌طور که ملاحظه می‌شود، پراپرتی font-size را افزوده‌ایم سپس این تغییر را کامیت می‌کنیم:

/var/www/git-tutorial$ git add styles.css 
/var/www/git-tutorial$ git commit -m "changes made to the styles.css file in master branch"
[master 1250bb5] changes made to the styles.css file in master branch
 1 file changed, 1 insertion(+)

حال سوئیچ می‌کنیم به آخرین بِرَنچ تحت عنوان another-branch که پیش از این ساختیم:

/var/www/git-tutorial$ git checkout another-branch 
Switched to branch 'another-branch'

اگر اکنون به فایل styles.css مراجعه کنیم، خواهیم دید که نسخهٔ‌ قدیمی فایل در معرض دیدمان قرار خواهد گرفت و در ادامه آن را به صورت زیر آپدیت می‌کنیم:

body {
    background: #ffde57;
    padding: 10px;
}

حال تغییرات را کامیت می‌کنیم:

/var/www/git-tutorial$ git add styles.css 
/var/www/git-tutorial$ git commit -m "changes made to the styles.css file in another-branch"
[another-branch dadc226] changes made to the styles.css file in another-branch
 1 file changed, 1 insertion(+)

در ادامه،‌ به منظور ادغام تغییرات ابتدا با استفاده از دستور git checkout master وارد شاخهٔ مَستر شده سپس با استفاده از دستور زیر قصد داریم تغییرات صورت‌گرفته توسط بِرَنچ another-branch را ادغام کنیم:

/var/www/git-tutorial$ git merge another-branch 
Auto-merging styles.css
CONFLICT (content): Merge conflict in styles.css
Automatic merge failed; fix conflicts and then commit the result.

می‌بینیم با توجه به این که پیش از این فایل styles.css توسط بِرَنچ master آپدیت شده بود اما بِرَنچ another-branch از آن بی‌خبر بود، متن پیام فوق حاکی از آن است که به تداخل برخورده‌ایم و اگر به فایل styles.css مراجعه کنیم، خواهیم دید:

body {
    background: #ffde57;
<<<<<<< HEAD
    font-size: 12px;
=======
    padding: 10px;
>>>>>>> another-branch
}

در تفسیر آنچه در بالا مشاهده می‌کنیم می‌توان گفت که خط سوم حاکی از آن است که کد مذکور پیش از این اضافه شده بوده است و خط پنجم شروع کدهای جدیدی که باعث کانفلیک شده‌اند را نشان می‌دهد و خط هفتم نیز پایان نقطه‌ای است که تغییرات صورت‌گرفته توسط شاخهٔ another-branch اِعمال شده‌اند. کاری که در این مرحله می‌توان انجام داد آن است که اگر کدها مورد تأیید هستند، خطوط سوم، پنجم و هفتم را به صورت زیر حذف می‌کنیم:

body {
    background: #ffde57;
    font-size: 12px;
    padding: 10px;
}

در این مرحله چنانچه کدها رضایت‌بخش بودند،‌ مجدد نیاز داریم تا تغییرات را کامیت کنیم:

/var/www/git-tutorial$ git add styles.css 
/var/www/git-tutorial$ git commit 

همان‌طور که ملاحظه می‌شود، از آپشن m- برای دستور commit استفاده نکرده و اینتر می‌کنیم:

Merge branch 'another-branch'

# Conflicts:
#       styles.css
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#       .git/MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#       modified:   styles.css

می‌بینیم به صورت خودکار این پیام در معرض دیدمان قرار می‌گیرد و طبق روال گذشته دکمه‌های Ctrl + X را می‌زنیم.

جمع‌بندی
مفهوم شاخه‌ها در گیت را به نوعی می‌توان به عنوان یکی از کلیدی‌ترین خصیصه‌های این سیستم ورژن کنترل تلقی کرد چرا که اساساً این امکان در اختیار تیم‌های مهندسی قرار می‌گیرد تا بتوانند به هر تعداد که بخواهند شاخهٔ جدید ایجاد کرده و افراد متعددی در آنِ واحد روی پروژه کار کنند. در عین حال، احتمال رخداد کانفلیکت در چنین شرایط بسیار زیاد خواهد بود و یک توسعه‌دهنده‌ای که ادعا می‌کند به گیت مسلط است حتماً می‌باید با راه‌کارهای مختلف رفع این تداخل‌ها آشنا باشد.

online-support-icon