۱۳۹۳/۱۲/۱۷

راهنمای کاربردی git

مقدمه

مدتی بود که قصد نگارش مطلبی برای معرفی و آموزش git (گیت) داشتم. این مطلب بعد از معرفی کلی git و اصطلاحات آن، نمونه‌ای از کاربردهای عملی آن را به روش پرسش و پاسخ، ارائه خواهد کرد. در نظر داشته باشید که git بسیار انعطاف‌پذیر بوده و ابزارهای بسیاری دارد. مطلب زیر مهم‌ترین کاربرد‌های آن را بیان نمونه و مستقیما از دستورات خود git در خط فرمان (و نه محیط‌های گرافیکی) استفاده نموده است.

git چیست؟

git یک نرم‌افزار آزاد و متن‌باز برای بازنگری کد منبع توزیع شده و مدیریت منبع کد است. گیت ابتدا برای توسعهٔ لینوکس توسط لینوس تروالدز به وجود آمد و اکنون پروژه‌های فراوانی از آن الهام گرفته‌اند. هر دایرکتوری کاری در گیت یک مخزن کامل با تاریخچهٔ کامل تغییرات و قابلیت بازنگری تغییرات است و برای کار با آن نیازی به دسترسی به شبکه یا سرور مرکزی وجود ندارد. گیت یک نرم‌افزار آزاد است که تحت عنوان جی‌پی‌ال نسخه ۲ توزیع شده است.
در پوشهٔ پایهٔ هر پروژه که با استفاده از گیت مدیریت می‌شود پوشه‌ای با نام git. (نقطه git) وجود دارد که تمامی اطلاعات مربوط به پروژه (تاریخچه، برچسب‌ها، ...) را در خود نگه می‌دارد. این ساختار بر خلاف ساختار سابورژن است که در هر زیرشاخه یک پوشهٔ svn. (نقطه svn) دارد. از جمله پرونده‌هایی که در پوشهٔ git. وجود دارند، config است که تنظیمات مخزن را در خود نگه می‌دارد.

اصطلاحات و لغات در git

در زیر مهم‌ترین اصطلاحات گیت را مشاهده می‌فرمایید:

مخزن (repository)

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

کامیت (commit)

منظور از کامیت، نسخه‌ای از تغییرات صورت گرفته بر روی اطلاعات و کدهای پروژه است. دستور commit در گیت،  نسخه‌ی از تغییرات در برنامه را ذخیره می‌کند.

شاخه (branch)

منظور از branch، سیر خطی توسعه است. هر پروژه می‌تواند چندین خط توسعه داشته باشد. 

برچسب (tag)

شما می‌توانید با استفاده از برچسب، اشاره‌گری به کامیتی مشخص ذخیره کنید.

مَستر (master)

به صورت پیش فرض، master یک شاخه در مخزن گیت بوده و در بیشتر موارد خط توسعه اصلی مخزن است.تصویر زیر به صورت گویاتر مفهوم مَستر، برچسب و شاخه  را ارائه کرده است:
برچسب‌ها و شاخه‌ها در گیت
مَستر، برچسب‌ها و شاخه‌ها در گیت

هِد (HEAD)

HEAD مشخص کننده checkout فعلی صورت گرفته در پروژه است.

دستور checkout

برای رجوع به برچسب، شاخه و هر وضعیت مشخصی در پروژه باید checkout نمایید.

دستور pull

دستور pull برای گرفتن آخرین تغییرات و وضعیت مخزن از سرور استفاده می‌شود.

دستور push

دستور push تغییرات و کامیت‌های ذخیره شده بر روی محیط لوکال را به سرور منتقل می‌کند.


سناریوهای کاربردی برای git

برای درک بهتر اصطلاحات و کاربردها git سناریوی زیر را در نظر گرفته و راهنمای آن را مشاهده فرمایید. تعدادی از این سناریوها توسط یکی از همکارانم پیشنهاد شده‌اند.

۱- یک پروژه در بر روی سیستم خودم دارم. چطور گیت را به آن اضافه کنم؟

بر روی کامپیوتر کلاینت خود، دستورات زیر را در محیط خط فرمان وارد نمایید:
$ cd my_project
$ git init
$ git add *
$ git commit -m "My initial commit message"
  • دستور git init یک مخزن برای گیت در دایرکتوری جاری ایجاد می‌نماید.
  • دستور git add فایل‌های مورد نظر را به مخزن گیت اضافه می‌کند.
  • دستور git commit، نسخه‌ای از تغییرات صورت گرفته را بر روی شاخه جاری ذخیره می‌کند.

۲- یک پروژه شامل گیت بر روی محیط کلاینتم دارم، چطور آن را به سرور منتقل نمایم؟

ابتدا باید یک مخزن گیت برای پروژه خود بر روی سرور ایجاد نمایید:
$ ssh git@example.com
$ git init --bare --shared my_project.git
$ chgrp -R devteam my_project.git
$ exit
  • دستور ssh برای اتصال سرور و ورود به محیط خط فرمان سرور مورد نیاز است.
  • دستور git init --bare --shared و پارامترهای استفاده شده، یک مخزن برای پروژه‌ای که توسط گروهی از افراد توسعه می‌شود، بر روی سرور ایجاد می‌کند.
  • دستور chgrp، مالکیت گروه دایرکتوری پروژه و محتوای آن را به اعضای گروه devteam منتقل می‌کند.
  • دستور exit برای خروج از سرور و بازگشت به محیط خط فرمان کلاینت مورد نیاز است.
در مرحله بعد با استفاده از دستورات زیر مخزن سرور را به پروژه اضافه نموده و اطلاعات لوکال را به سرور منتقل نمایید:
$ git remote add origin git@example.com:my_project.git
$ git push -u origin master

۳- چطور یک پروژه را از مخزن سرور دریافت کنم؟

روش‌ها و فرمت‌های مختلفی برای گرفتن یک پروژه از مخزن سرور وجود دارد. دستورات زیر روش گرفتن پروژه با استفاده از ssh را نمایش می‌دهد:
$ git clone git@example.com:my_project.git
$ cd my_project

  • دستور git clone یک نسخه از مخزن سرور را به محیط لوکال و سیستم شما منتقل می‌نماید.

۴- پروژه را تغییر داده ام (فایل‌هایی اضافه، حذف یا ویرایش کرده‌ام). چطور به مخزن سرور منتقل نمایم؟

قبل از انتقال تغییرات به سرور، ابتدا تغییرات صورت پذیرفته بر روی پروژه را بررسی نمایید:
$ git ls-files --deleted
$ git ls-files --modified
$ git diff
  • دستور git ls-files برای فهرست کردن فایل‌ها مورد استفاده قرار می‌گیرد. این دستور فیلترهایی برای محدودکردن بر اساس نوع تغییرات صورت گرفته دارد.
  • دستور git diff تغییرات فایل‌ها نسبت به آخرین کامیت را نمایش می‌دهد.
برای کامیت کردن تغییرات و ارسال تغییرات به سرور دستورات زیر را اجرا نمایید:
$ git add .
$ git commit
$ git pull
$ git push
  • دستور git add فایل‌ها جدید ویا تغییر پیدا کرده را برای کامیت کردن، اضافه می‌کند.
  • دستور git commit، نسخه‌ای از تغییرات صورت گرفته را بر روی شاخه جاری ذخیره می‌کند.
  • دستور git pull آخرین تغییرات مخزن سرور را به مخزن لوکال منتقل می‌کند. اجرای این دستور قبل از push کردن کد، در صورتیکه آخرین کامیت سرور بر روی مخزن لوکال وجود نداشته باشد، الزامی است.
  • دستور git push برای ارسال تغییرات از مخزن لوکال به سرور استفاده می‌شود.

۵- چطور یک شاخه (branch) بسازم و آن را در کنار شاخه‌های دیگر توسعه بدهم؟

دستور زیر یک شاخه جدید شامل آخرین تغییرات (حتی کامیت نشده ها) ساخته و آن را شاخه فعال (خط توسعه جاری) قرار می‌دهد:
$ git checkout -b [name_of_your_new_branch]

برای انتقال این شاخه به مخزن سرور دستور زیر را در سیستم لوکال اجرا نمایید:
$ git push -u origin [name_of_your_new_branch]

برای مشاهده تمامی شاخه‌ها می‌توانید از دستور git branch استفاده کنید. شاخه فعال در مخزن با یک * مشخص شده است. همچنین دستور git fetch، آخرین اطلاعات ساختار مخزن و شاخه‌های موجود را از سرور به مخزن لوکال منتقل می‌کند:
$ git branch
$ git fetch
$ git branch -a #show all remote and local branches

برای checkout کردن یک شاخه از سرور از دستور checkout استفاده نمایید. ممکن است قبل از دستور checkout، نیاز به اجرای دستور git fetch داشته باشید:
$ git checkout [branch_name]

۶- من و همکارم همزمان فایلی را ویرایش کرده و بعد از کامیت، در pull و push به مشکل برخورده‌ایم. چطور Conflict ها را رفع کنیم؟

در نمونه زیر، بعد از کامیت و pull کردن از مخزن سرور، git در ترکیب کردن (merge) فایل README.md با مشکل مواجه شده و از کاربر می‌خواهد که بعد از رفع تضادها (Conflict)، کد را دوباره کامیت و سپس push نماید:
$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From repo:/opt/repositories/my_project
   c3e5e32..d773d5d  master       -> origin/master
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
$ vim README.md #edit the file to fix conflicts
$ git add *
$ git commit -m "fix conflicts"
$ git push

  • در نمونه بالا بعد از ویرایش فایل README.md و رفع conflict ها کد را دوباره کامیت و سپس push کرده‌ایم.

۷- چطور دو شاخه را با هم ترکیب کنم؟

برای merge کردن دو شاخه باید از دستور git merge استفاده کنید. در زیر ابتدا به شاخه اصلی (master) رفته و سپس شاخه فرعی quickfix را با آن ترکیب کرده‌ایم:
$ git checkout master
$ git merge quickfix

۸- چطور یک شاخه را از مخزن لوکال ویا سرور حذف کنم؟

سه نوع شاخه مختلف برای حذف وجود دارد: شاخه لوکال (local branch)، شاخه سرور (remote branch) و شاخه سرور موجود بر روی لوکال (local remote-tracking branch). در زیر دستورات مرتبط برای حذف هر کدام از انواع شاخه‌ها را مشاهده می‌فرمایید.

حذف شاخه لوکال (local branch)

$ git branch --delete <branch> # delete local branch
$ git branch -d <branch> # shorter version
$ git branch -D <branch> # force delete un-merged branches

حذف شاخه سرور (remote branch)

$ git push origin --delete <branch> # git version 1.7.0 or newer
$ git push origin :<branch> # git versions older than 1.7.0

حذف شاخه سرور موجود بر روی لوکال (local remote-tracking branch)

$ git branch --delete --remotes <remote>/<branch>
$ git branch -dr <remote>/<branch> # shorter 
$ git fetch <remote> --prune # delete multiple obsolete tracking branches 
$ git fetch <remote> -p # shorter

۹- از تغییراتی که انجام داده‌ام پشیمان شده‌ام. چطور به آخرین نسخه برگردم؟

به منظور حذف تغییرات و بازگشت به آخرین نسخه کامیت شده بر روی مخزن، کافیست از دستور git reset به صورت زیر استفاده نمایید:
$ git reset --hard

۱۰- چطور تاریخچه کامیت‌ها و تغییرات فایل‌ها را مشاهده کنم؟

دستور git log برای مشاهده تاریخچه مخزن، یک فایل و یا نمایش تغییرات یک فایل به صورت زیر استفاده می‌شود:
$ git log # show all commit logs
$ git log [file_path] # show commit logs of the file
$ git log -p [file_path] # show history of the patches of the file

۱۱- چطور یک tag ثبت کنم؟

دستور git tag برای ذخیره برچسب‌ها استفاده می‌شود. git از دو نوع برچسب lightweight و annotated پشتیبانی می‌کند. نوع lightweight یک اشاره‌گر ساده به کامیتی مشخص است و هیچ اطلاعات دیگری مانند ایجادکننده tag را ذخیره نمی‌نماید. نوع annotated همانند یک کامیت عمل کرده و برخلاف نوع lightweight اطلاعات فرد ثبت کننده را ذخیره می‌نماید. در زیر نمونه ای از تعریف برچسب annotated و نحوه انتقال آن از مخزن لوکال به مخزن سرور را مشاهده می‌فرمایید:
$ git tag -a [tag name or version]
$ git show [tag name or version]
$ git push origin [tag name or version] # or git push origin --tags

برای ایجاد یک شاخه براساس یک tag باید از دستور checkout استفاده نمایید. در مثال زیر یک شاخه بر اساس برچسب v2.0.0 ایجاد کرده ایم:
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2' 

بروزرسانی

مطلب دیگری با عنوان راهنمای تکمیلی گیت (Git) نیز در وبلاگ منتشر کرده‌ام که پیشنهاد می‌کنم آن را نیز مطالعه فرمایید.



۸ نظر:

  1. بسیار عالی و کامل بود.
    درضمن فونتت در ویندوز افتضاح هست.
    https://github.com/font-store/font-Iranian

    پاسخحذف
    پاسخ‌ها
    1. سلام،
      خوشحالم که مفید بوده.
      در مورد فونت تا الان توو ویندوز چک نکرده بودم. حتما بررسی میکنم. ممنون بابت تذکر :)

      حذف
  2. سلام آقای زبردست
    ای کاش در یک سرویس ایرانی یا لااقل فیلتر نشده وبلاگ می داشتید تا دسترسی به مطالب خوبتان آسان باشد. البته هر طور صلاح می دونید و صد البته اگر چنین کنید ممنونتان می شوم.

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

      حذف
  3. آقای زبردست خدا خیرت بده .
    گیت هاب کار کرده بودم ولی حداقل 2 تا چیز جدید یاد گرفتم .
    فرهنگ تقسیم دانش با دیگران ، خیلی عالیه . به امید اینکه همه اینگونه باشند .

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

      حذف