آموزش گیت – قسمت نهم

نویسنده : سید ایوب کوکبی ۲۶ اردیبهشت ۱۳۹۸
آموزش گیت - قسمت نهم

در درس قبلی توانستیم اطلاعات دو مخزن my-git-repo و marys را بین دو توسعه‌دهنده به اشتراک بگذاریم. این روش در تیم‌های کوچک که روی برنامۀ ساده‌ای کار می‌کنند جواب می‌دهد ولی پروژه‌های بزرگتر به روش نظام‌مندتری نیاز دارند که در این درس به توضیح یکی از این روش‌ها یعنی گردش کار متمرکز یا مرکزی (centralized workflow) در گیت خواهیم پرداخت.

مخزن سومی خواهیم ساخت تا به کمک آن، ما و ماری بتوانیم تغییرات را در مکانی مرکزی به اشتراک بگذاریم. یعنی به جای دریافت مستقیم اطلاعات marys-repo به my-git-repo یا بالعکس می‌توانیم اطلاعات را در یک مخزن مرکزی (central repo) فچ و پوش کنیم. در انتهای این درس، گردش کار ما مشابه تصویر زیر خواهد بود:

گردش کار متمرکز در گیت
گردش کار متمرکز در گیت

معمولاً مخزن مرکزی را در یک سرور ذخیره می‌کنند تا کاربران با استفاده از اینترنت از هر جای دنیا به آن دسترسی داشته باشند. متأسفانه پیکربندی این نوع مخازن از سروری تا سرور دیگر فرق می‌کند و ممکن است زمان زیادی صرف آن شود. به همین خاطر توضیحات این درس را به صورت لوکال شبیه‌سازی می‌کنیم.

در هر حال شما می‌توانید مخزن مرکزی را در سرور بسازید و با مسیر SSH به آن دسترسی پیدا کنید ولی در غیر این صورت با توضیحات همین درس می‌توانید مفاهیم گفته شده را در حالت لوکال بیاموزید. در درس بعدی یاد می‌گیریم چگونه از گیت در محیط شبکه استفاده کنیم.

ساخت مخزن مرکزی

ابتدا بیایید محل ذخیرۀ مرکزی را بسازیم. طبق دستورات پایین این کار را انجام دهید. توجه داشته باشید که به جای مسیر /path/to/my-git-repo/ باید مسیر اصلی مخزن خود را قرار دهید و اگر خواستید از سرور استفاده کنید باید مسیر SSH آن را وارد نمایید.

cd /path/to/my-git-repo
cd ..
git init --bare central-repo.git

دستور git init را به خاطر دارید. ولی اینجا از یک فلگ bare– هم استفاده کرده‌ایم؛ معنی‌اش این است که به working directory نیازی نداریم. این کار جلوی دسترسی اتفاقی و تغییرات ناخواسته در این مخزن را خواهد گرفت. در واقع ناخواسته پوش‌های ارسالی دیگران را از درجۀ اعتبار ساقط نمی‌کنیم. مخزن مرکزی تنها برای تسهیل امر ذخیره‌سازی است و نباید به عنوان مرکزی برای توسعۀ پروژه در نظر گرفت.

اگر به فولدر ساخته شده نگاه کنید متوجه پسوند git. در انتهای آن خواهید شد و اگر به محتوای آن دقت کنید به مشابهت فایل‌ها با محتوای فولدر git. در فولدر my-git-repo پی می‌برید. گیت از پسوند git. در انتهای فولدر ساخته شده استفاده می‌کند تا بداند که این فولدر working directory نیست و کسی به محتوای آن دست نمی‌زند.

بروزرسانی ریموت‌ها (ماری و شما)

تا الان توانستیم مخزن مرکزی را برای اشتراک کدها بین خودما و ماری و سایر توسعه‌دهندگان بسازیم. مرحلۀ بعدی اضافه کردن آدرس مخزن مرکزی (ریموت) به مخزن هر یک از توسعه‌دهندگان است. این کار را هر توسعه‌دهنده‌ای باید به صورت جدا انجام دهد ولی چون هدف ما اینجا آموزش است. خودمان را جای توسعه‌دهنده‌ها می‌گذاریم و از ناحیۀ آن‌ها کار را انجام می‌دهیم. ابتدا از مخزن ماری شروی می‌کنیم:

cd marys-repo
git remote rm origin
git remote add origin ../central-repo.git

و بعد مخزن خودمان:

cd ../my-git-repo
git remote add origin ../central-repo.git
git remote rm mary

توجه کنید که اتصال قبلی دو مخزن my-git-repo و marys-repo را با دستور git remote rm حذف کرده‌ایم چون دیگر نیازی نداریم. در ادامۀ این درس فقط روی مخزن مرکزی کار می‌کنیم. در صورتی که مخزن شما روی سرور قرار داشت، به جای مسیر لوکال باید از آدرس SSH مخزن استفاده کنید مثلاً: ssh://user@example.com/path/to/central-repo.git. یا برای مخازنی که در گیت‌هاب قرار دارند از آدرس HTTPS هم می‌توانید استفاده نمایید.

بخوانید  آموزش گیت - قسمت ششم

پوش کردن شاخۀ مستر به مخزن مرکزی (شما)

ما فقط یک مخزن مرکزیِ خالی ساخته‌ایم و هیچ مخزنی را کلون نکرده‌ایم. این یعنی هیچ تاریخچه‌ای از پروژۀ ما را در بر ندارد. مشکل فوق را می‌توانیم با دستور git push رفع کنیم؛ به این صورت:

git push origin master

اکنون مخزن مرکزی حاوی تمام محتویات شاخۀ مستر ماست. اگر لاگ بگیرید متوجه خواهید شد:

cd ../central-repo.git
git log

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

افزودن یک آپدیت جدید (شما)

با اعمال اندکی تغییرات شما را با گردش کارش متمرکز آشنا می‌کنیم. در مخزن پروژۀ (my-git-repo) به شاخۀ news-item چک‌اوت کنید. چون این شاخه وجود ندارد و از پرچم b- استفاده کرده‌ایم به صورت خودکار ساخته شده و به آن چک‌اوت می‌شود:

cd ../my-git-repo
git checkout -b news-item

فایل جدیدی به نام news-3 با محتوای زیر ایجاد کنید:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Middle East's Silent Beast</title>
  <link rel="stylesheet" href="style.css" />
  <meta charset="utf-8" />
</head>
<body>
  <h1 style="color: #D90">Middle East's Silent Beast</h1>
  <p>Late yesterday evening, the Middle East's largest
  design house—until now, silent on the West's colorful
  disagreement—announced the adoption of
  <span style="color: #D90">Yellow</span> as this year's
  color of choice.</p>
    
  <p><a href="index.html">Return to home page</a></p>
</body>
</html>

و لینک صفحه را به index.html اضافه کنید:

<h2 style="color: #C00">News</h2>
<ul>
  <li><a href="news-1.html">Blue Is The New Hue</a></li>
  <li><a href="rainbow.html">Our New Rainbow</a></li>
  <li><a href="news-2.html">A Red Rebellion</a></li>
  <li><a href="news-3.html">Middle East's Silent Beast</a></li>
</ul>

و نهایتاً تغییرات را استیج و کامیت کنید:

git add news-3.html index.html
git status
git commit -m "Add 3rd news item"

انتشار تغییرات جدید به مخزن مرکزی (شما)

قبلا منظور ما از پابلیش یا انتشار تغییرات، ادغام با شاخۀ مستر بود. اما وقتی پای یک مخزن مرکزی در میان است، شاخۀ مستر ما کماکان خصوصی است و از نظر دیگران مخفی است، یعنی ماری یا هر توسع‌دهندۀ دیگری از تغییرات شاخۀ مستر ما با خبر نیست. به همین خاطر تغییرات را حتماً باید به مخزن مرکزی پوش کنیم:

git checkout master
git merge news-item
git branch -d news-item
git push origin master

بعد از ادغام با شاخۀ مستر همچون روال معمول با دستور git push تغییرات را به شاخۀ مسترِ مخزن مرکزی فرستاده‌ایم. در نهایت وضعیت اینگونه خواهد شد:

پوش کردن شاخۀ مستر به مخزن مرکزی

توجه داشته باشید که این کار دقیقاً مثل آن است که به مخزن مرکزی برویم و دستور fetch و سپس merge را اجرا کنیم؛ تنها تفاوتش اینجاست که از داخل مخزن خودمان یعنی my-git-repo می‌توانیم همۀ این کارها را انجام دهیم. البته زمانی که مخزن مرکزی در مالکیت یک شخص دیگر باشد و شما نتوانید به آن سوئیچ کنید، تنها راه ارسال تغییرات همین دستور push است.

بروزرسانی استایل‌شیت‌ها (ماری)

حالا فرض می‌کنیم شما ماری هستید و قصد دارید تغییراتی اعمال کنید. ابتدا به مخزن ماری سوئیچ می‌کنیم و سپس یک شاخۀ جدید css-edits می‌سازیم:

cd ../marys-repo
git checkout -b css-edits

حالا تغییرات زیر را به انتهای فایل style.css اضافه می‌کنیم:

h1 {
  font-size: 32px;
}

h2 {
  font-size: 24px;
}

a:link, a:visited {
color: #03C;
}

و نهایتاً تغییرات را استیج و کامیت می‌کنیم:

git commit -a -m "Add CSS styles for headings and links"

بروزرسانی مجدد استایل‌شیت‌ها (ماری)

ماری یادش رفته بود که استایل‌های تگ h3 را اضافه کند؛ بنابراین آن را هم به فایل style.css اضافه می‌کند:

h3 {
  font-size: 18px;
  margin-left: 20px;
}

و تغییرات را استیج و کامیت می‌کند:

git commit -a -m "Add CSS styles for 3rd level headings"

پاک‌سازی تاریخچه قبل از انتشار تغییرات (ماری)

ماری قبل از ارسال تغییراتش می‌خواهد از تمییز بودن تاریخچه‌اش اطمینان یابد. این کار حتماً باید توسط خودِ او انجام شود چون تقریباً غیرممکن است بعد از پوش کردن تغییرات بتوان تغییری در تاریخچه ایجاد کرد.

git rebase -i master

این موضوع یکی دیگر از فواید توسعۀ فیچرهای جدید در شاخه‌ای مجزا است. ماری نیازی ندارد به عقب برگردد تا بفهمد چه تغییراتی را باید Rebase کند چون همه چیز در شاخۀ جاری قرار دارد. تنظیمات Rebase را به صورت زیر تغییر می‌دهیم:

pick 681bd1c Add CSS styles for headings and links
squash eabac68 Add CSS styles for 3rd level headings

وقتی گیت منتظر دریافت پیامی برای ادغام دو کامیت شد، همان پیام کامیت اول را برایش انتخاب کنید:

Add CSS styles for headings and links

حالا تصور کنید ماری بعد از Rebase، تغییرات را در مخزن مرکزی پوش می‌کرد؛ چه اتفاقی می‌افتاد؟ این کار باعث می‌شد کامیت‌هایی در مخزن مرکزی بازنویسی شوند که ممکن بود سایر توسعه‌دهندگان، آن کامیت را قبلاً برای پروژۀ خود pull کرده باشند. از نگاه گیت، کامیت بازنویسی شدۀ ماری کاملاً یک کامیت جدید محسوب می‌شود (چرا که یک آیدی جدید دارد). این وضعیت را می‌توانید در تصویر زیر مشاهده کنید:

Squash کردن یک کامیت عمومی

کامیت‌های برچسب‌گذاری شده با ارقام ۱ و ۲ نمایانگر کامیت‌های عمومی (واقع در مخزن مرکزی) هستند که ماری آن‌ها را Rebase می‌کند. بعد از این کار، تاریخچۀ عمومی دقیقاً مانند تاریخچۀ ماری است ولی شاخۀ مستر او از شاخۀ origin/master جدا شده است.

بخوانید  آموزش گیت - قسمت اول

بنابراین برای انتشار شاخۀ مسترِ Rebase شده به مخزن مرکزی، ماری باید با origin/master عمل ادغام را انجام دهد. این ادغام از نوع fast-forward نخواهد بود و نتیجه چیزی نیست جزء سردرگمی توسعه‌دهندگان و ایجاد تداخل در گردش کار آن‌ها.

موضوع یاد شده نکتۀ مهمی را برای ما آشکار می‌کند، اینکه هیچ وقت کامیت‌های پوش شده به مخزن مشترک را Rebase نکنید. در صورت نیاز به تغییر کامیت عمومی، از دستور git revert استفاده کنید. این دستور به جای بازنویسی کامیت‌های قبلی، اصلاحات لازم را در غالب یک کامیت جدید ارسال می‌کند.

انتشار تغییرات CSS (ماری)

بعد از پاکسازی تاریخچه، اکنون ماری می‌تواند تغییراتش را به مخزن مرکزی بفرستد.

git checkout master
git merge css-edits
git branch -d css-edits

ماری نباید شاخۀ css-edits را به سرور پوش کند چرا که دیگر تحت توسعه نیست و سایر توسعه‌دهندگان از محتویات آن باخبر نیستند. با این حال اگر تصمیم گرفته‌اید که روی ویرایش CSS چند نفری کار کنید و این کار را در یک شاخۀ مجزا انجام دهید، انتشار مجزای این شاخه پذیرفتنی است.

کار ماری هنوز تمام نشده، در دستورات بالا، عمل ادغام شاخۀ مستر در مخزن ماری انجام گرفته ولی هنوز تغییرات مستر به مخزن مرکزی پوش نشده است. قبل از اعمال تغییرات، مخزن ما و ماری چنین وضعیتی دارد:

شاید با خودتان بگویید ماری چگونه می‌خواهد تغییرات شاخۀ مسترش را به مخزن مرکزی ارسال کند در حالی که کدهای پروژه در مخزن عمومی جدیدتر از نسخه‌ای است که او آخرین بار فچ کرده است. در واقع ماری بدون اینکه آخرین نسخۀ پروژه را از مخزن مرکزی فچ کرده باشد اقدام به آپدیت و پوش کردن تغییرات می‌کند که این کار گیت را دچار سردرگمی خواهد کرد. اگر دستور زیر را وارد کنید:

git push origin master

عملیات با اعلام چند خط توضیح از سوی گیت ریجکت می‌شود. ظاهراً گیت تغییراتی که به شکل fast-forward در مخزن مرکزی قابل ادغام نباشند را نمی‌پذیرد و ماری هم گیت را در چنین وضعیتی قرار داده است. در آخرین نسخۀ پروژۀ واقع در مخزن عمومی، کامیت Add 3rd news item وجود دارد که در صورت ادغام باید با تغییرات ماری بازنویسی شود تا بتواند وضعیت شاخۀ mary/master را آنطور که هست به همه نشان دهد.

بخوانید  آموزش گیت - قسمت یازدهم

Pull کردن تغییرات (ماری)

ماری می‌تواند مشکل فوق را با دریافت آخرین تغییرات مخزن مرکزی قبل از پوش کردن تغییرات حل کند. او اول باید بروزترین نسخۀ شاخۀ origin/master را دریافت کند.

git fetch origin

به خاطر دارید که با سینتکس پایین می‌توان آنچه را در origin/master هست ولی در master نیست مشاهده کرد:

git log master..origin/master

همچنین بالعکس حالت بالا هم صادق است؛ یعنی کامیت‌های موجود در مستر هست که در origin/master نیست:

git log origin/master..master

از آنجایی که هر دو دستور یک کامیت را نشان می‌دهند می‌توان فهمید که تاریخچۀ ماری دو شاخه شده است. این را می‌توان از دیاگرام پایین به راحتی فهمید:

فچ کردن شاخۀ مستر از مخزن مرکزی

ماری اکنون در وضعیت آشنایی قرار دارد. او می‌تواند از دستور merge استفاده کند که البته از نوع fast-forward نیست. همچنین می‌تواند از دستور Rebase نیز استفاده نماید. معمولاً این طور است که تغییرات را در ادامۀ آخرین کامیت مخزن مرکزی قرار دهید. این را هم می‌دانید که با دستور Rebase می‌توانید کامیت‌های merge اضافی را حذف کنید. به همین خاطر انتخاب ماری همان دستور Rebase است:

git rebase origin/master
git push origin master

بعد از Rebase، شاخۀ مسترِ ماری هر چیزی را که در مخزن مرکزی وجود دارد در بر خواهد گرفت. بنابراین او می‌تواند حالا تغییراتش را به صورت fast-forward به مخزن مرکزی پوش کند.

بروزرسانی شاخۀ مستر در مخزن مرکزی

دریافت تغییرات (شما)

نهایتاً به مخزن خودمان سوئیچ می‌کنیم تا تغییرات جدید ماری در فایل‌های CSS را دریافت کنیم.

cd ../my-git-repo
git fetch origin
git log master..origin/master --stat
git log origin/master..master --stat

لاگِ دوم چیزی برنمی‌گرداند چون هنوز ما هیچ کامیتی بعد از تغییرات جدید ماری ارسال نکرده‌ایم. برای اطمینان بیشتر خوب است که قبل از ادغام تغییرات در شاخۀ ریموت، با دستورات فوق وضعیت فعلی را بررسی کنید تا merge commit های بیهوده ارسال نکنید.

git merge origin/master

اکنون مخزن ما با مخزن مرکزی همگام است. توجه داشته باشید که ماری ممکن است تغییرات جدیدی در مخزن خودش اعمال کرده باشد که ما از آن بی‌اطلاع باشیم. مهم نیست؛ ما فقط به تغییرات ثبت شده در central-repo.git اهمیت می‌دهیم. شاید برای پروژه‌ای با دو برنامه‌نویس، گردش کار متمرکز چندان ضرورت نداشته باشد ولی قطعاً با افزایش تعداد دولوپرها میزان هرج‌ومرج افزایش یافته و لزوم وجود چنین گردش‌کاری بیش از پیش احساس خواهد شد.

گردش کار متمرکز با تعداد زیادی برنامه‌نویس

وجود یک مخزن مرکزی برای ذخیرۀ کدها، جلوی هرج‌ومرج و دخالت در کدها را کاهش داده و همه چیز طبق قاعده و درست پیش خواهد رفت.

جمع‌بندی

در این درس مخزن ریموت جدیدی به پروژه اضافه کردیم تا تمام کدها را در یک ناحیۀ مرکزی ذخیره کنیم و توسعه‌دهندگان نیز تغییرات خود را در همین مخزن قرار دهند یا از آن بگیرند. با چگونگی ساخت bare repository آشنا شدید که مثل همان مخازن معمولی است جزء اینکه working directory ندارند؛ یعنی هیچ کسی به جزء گیت با آن کاری ندارد.

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

در درس بعدی خواهید آموخت که چگونه یک مخزن مبتنی بر شبکه را با استفاده از گیت‌هاب راه‌اندازی و پیکربندی کنید. یاد می‌گیرید که چگونه تغییرات پروژه را به مخزن ریموت روی سرور ارسال یا از آن دریافت کنید. توضیحات این درس زمینه را برای گردش کار توزیع شده که موضع درس آیندۀ ماست فراهم می‌کند.

چکیدۀ دستورات

  • <git init –bare <repository-name : ساخت یک مخزن جدید فاقد working directory؛
  • <git remote rm <remote-name : حذف یک ریموت از اتصالات بوکمارک شده؛

سید ایوب کوکبی

نویسنده و مترجم...

0 دیدگاه

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *