چگونه از git استفاده کنیم

گیت چیه؟

گیت یک نرم‌افزار مدیریت نسخه است. تاریخچه و پدید آورندگانش به نظر من خیلی اهمیتی نداره ولی اگه کنجکاوید میتونید از ویکی‌پدیا بخونید. (گیت اسم یک روستا در خراسان جنوبی هم هست: + :) )

مدیریت نسخه یعنی چی؟

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

چه جالب! دیگه چه کارهایی می‌کنه؟

با گیت میشه به راحتی روی یک مجموعه فایل به صورت گروهی کار کرد. دیگه لازم نیست فایل‌ها رو روی دراپ‌باکس و paste bin و غیره بزارید یا برای هم با ایمیل بفرستید و تغییرات رو دستی با هم ترکیب کنید، گیت این کارو براتون انجام میده.

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

چطوری نصب میشه؟

اگه از گنو/لینوکس استفاده می‌کنید احتمالا از قبل روی دستگاهتون نصب هست. با وارد کردن git --version در ترمینال می‌تونید چک کنید که نصب شده یا نه. اگر نصب نشده بود بسته‌ی git رو با package manager سیستم‌عاملتون نصب کنید (همون apt-get یا yum و pacman و…) .

اگر از ویندوز استفاده می‌کنید پیشنهاد من و ماکروسافت Git for windows هست. Git extensions هم ابزار خوبیه که هم ویندوزی‌ها و هم گنو/لینوکسی ها هم میتونن ازش استفاده کنن و برای کار با گیت یک محیط گرافیکی فراهم می‌کنه.

گیت به طور کلی یک ابزار تحت خط فرمانه و دستوراتی که در ادامه معرفی می‌کنم رو باید داخل ترمینال (گنو/لینوکس و مک دارها) یا Git bash (ویندوزی‌ها) وارد کنید.

تنظیمات اولیه

گیت تنظیمات زیادی داره که در حالت عادی خیلی‌هاشون رو لازم نیست دست بزنیم. تنها چیزی که دفعه‌ی اول نصب مهمه اینه که خودمون رو به گیت معرفی کنیم! این مرحله برای انجام کار گروهی اهمیت بیشتری داره.

git config --global user.name "Mohammad Jafar Mashhadi"
git config --global user.email "[email protected]"

و اگه افرادی که روی فایل‌ها کار می‌کنن سیستم‌عامل‌های مختلفی دارن (که معمولا اینطور هست):

git config --global core.autocrlf true

علت نیاز به این دستور اینه که توی ویندوز آخر خط‌ها با دو نویسه‌ی ‎\r و ‎\n پشت سرهم مشخص میشه (CR LF) ولی تو سیستم‌عامل‌های دیگه فقط با یک ‎\n ‎  (LF). وقتی‌ به صورت گروهی روی یه سری فایل تغییر ایجاد می‌کنید آخر خط‌های این فایل‌ها بسته به سیستم‌عامل ممکنه CRLF یا LF باشن. ما برای اینکه به گیت بگیم بین LF و CRLF تفاوت قائل نشه و این مورد رو به عنوان «تغییر در محتوای فایل» در نظر نگیره باید این گزینه رو فعال کنیم.

از کجا شروع کنیم؟

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

# Create a git repository
git init 

فرقی نداره که پوشه خالی باشه یا از قبل حاوی تعدادی فایل باشه. از الان به بعد git حواسش به تغییرات فایل‌های این پوشه (از این به بعد بهش مخزن (repository) هم گفته می‌شه) هست. اگر ls –a وارد کنید میتونید پوشه‌ی مخفی‌ای به اسم ‎.git که تازه ساخته شده رو ببینید. داخل این پوشه اطلاعات مربوط به گیت نگه‌داری می‌شن. اگر پاکش کنید گیت دیگه کاری به اون پوشه نداره و مثه بقیه‌ی پوشه‌های عادی سیستم باهاش برخورد میشه.

بعد چطور؟ طور خاصی باید کد بنویسم؟

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

git status

بعد از اینکه کارتون تموم شد باید مجموعه تغییراتی که ایجاد کردید رو به عنوان یه نسخه ثبت (commit) کنید. برای کامیت باید اول به گیت بگید که کدوم فایل‌ها رو می‌خواید داخل کامیتتون داشته باشید. اول یک بار git status بزنید تا یادتون بیاد چه فایل‌هایی تغییر کردند و بعد با git add فایل‌ها رو به کامیت اضافه کنید.

git add /path/to/file # Add one file to commit
git add /a/directory/
git add . # Add all modified and new files to commit

برای اضافه کردن یک تک فایل از دستور اول استفاده کنید، اگر همه‌ی فایل‌های داخل یک پوشه رو میخواید اضافه کنید از دستور دوم و اگر همه‌ی فایل‌هایی که تغییر کردند رو می‌خواید وارد کامیت کنید از دستور سوم استفاده کنید. اگر فایلی رو حذف کردید و می‌خواید این عمل حذف وارد کامیت بشه بجای git add از git rm استفاده کنید. اگر فایلی رو اشتباهی به کامیت اضافه کردید از دستور زیر استفاده کنید تا از کامیت خارج شه:

git rm --cached /path/to/file

بعد از اینکه همه‌ی فایل‌ها رو اضافه کردید با دستور زیر کامیت رو تموم کنید.

git commit -m "توضیحات مربوط به این کامیت، چه چیزی رو اضافه کردید؟ چه چیزی رو اصلاح کردید؟ تو یه خط توضیح بدید"

اگر توضیحاتتون توی یه خط جا نمی‌شه فقط بنویسید git commit . یک ادیتور (معمولا vi) باز می‌شه که میتونید توضیحات چندخطی رو داخلش وارد کنید.

هر کامیت یه رشته‌ی یکتایی به اسم hash داره که به طور خودکار ساخته میشه و برای ارجاع دادن به اون کامیت استفاده میشه. معمولا ۷ حرف اول  hash هر کامیت برای ارجاع دادن کافیه.

Git log on Telegram Android

توی این شکل خروجی دستور git log روی سورس کد پیام رسان تلگرام رو می‌بینید. عبارت زرد رنگی که جلوی کلمه‌ی commit نوشته شده hash کامیت است. در ادامه مشخصات فرد کامیت کننده، تاریخ کامیت کردن و توضیح کامیت (commit message) رو می‌بینید.

چطوری قراره گروهی کد زدن با گیت راحت تر بشه؟

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

فایل‌ها رو باید کجا بزارم که برای بقیه‌ی اعضای پروژه قابل دسترس باشه؟

سایت‌های github، gitlab و bitbucket رو پیشنهاد می‌کنم. اگر سرور شخصی دارید می‌تونید با یه مقدار تلاش و وقت گذاشتن روی سرور شخصیتون هم کار کنید. اگر می‌خواید کدها توسط عموم قابل دیدن نباشه باید از گیت‌لب یا بیت‌باکت استفاده کنید. روند اینطور هست که باید توی یکی از این سایت‌ها عضو شید و یک مخزن (repository) خالی درست کنید. بعد از ایجاد موفق یک مخزن خود این سایت‌ها بهتون دستورات لازم برای ارتباط پیدا کردن مخزن محلی و مخزن روی سرور (remote) رو نشون میدن. اصل کاری بین دستورات متعددی که توی سایت می‌بینید دو خطی هستن که شبیه این‌ها هستند:

git remote add origin ...
git push origin master

خط اول مخزن روی سرور رو به مخزن محلی معرفی می‌کنه؛ آدرسش رو می‌ده و براش یه اسم میزاره (origin). خط دوم هم فایل‌ها رو روی مخزن remote ای به اسم origin آپلود می‌کنه. (بله، میشه یک مخزن محلی بیش از یک remote داشته باشه!)

اگر صحنه‌ای شبیه عکس بالا دیدید یعنی push موفق بوده. برای مطمئن شدن می‌تونید دستور ‎echo‎ ‎$?‎ رو وارد کنید و اگر عدد 0 نوشته شد یعنی push موفق بوده. اگر پوش به ارور بخوره ممکنه مشکل از قطع بودن اینترنت باشه ولی مشکل (؟) معروف‌تری که معمولا با اون مواجه می‌شید ارور non fast-forward هست و عبارت fetch first در متن ارورها قابل مشاهده‌س. اگر به non fast-forward برخورد کردید نگران نباشید، معنیش اینه که افراد دیگه‌ای کامیت‌هاشون رو روی سرور push کردند و شما اون‌ها رو ندارید. همونطور که احتمالا حدس زدید باید کامیت‌های بقیه رو از سرور دریافت کنیم (fetch)، با کامیت‌های خودمون ترکیب کنیم(merge) و دوباره سعی کنیم push کنیم.

git fetch
git merge

چون fetch و merge زیاد پشت سر هم استفاده می‌شن دستور دیگه‌ای تعبیه شده که کارش دقیقا ترکیب این دو تا دستوره. git pull.

pull کردم و به conflict خوردم، بعضی از فایل‌ها خراب شدن، باید چه کنم؟

گیت تا جایی که ممکنه تغییرات همه رو با هم ترکیب می‌کنه اما یه جاهایی هست که چند نفر همزمان روی یک خط تغییر ایجاد کردن و گیت بین این تغییرات اولویتی قائل نیست. فکر کنم نیازی به توضیح نیست که چرا اولویت زمانی درست نیست (یعنی نمیشه کامیت جدیدتر رو به کامیت قدیمی‌تر ترجیح داد) به این شرایط می‌گن conflict و خروج از این شرایط باید به صورت دستی انجام شه. بعد از merge با git status می‌تونید چک کنید که آیا conflict به وجود اومده و اگر اومده کدوم فایل‌ها به conflict برخوردند. ابزارهایی مثل Meld یا git extensions برای رفع conflict وجود دارند. شخصا چون معمولا از IDE های JetBrains استفاده می‌کنم از ابزار رفع کانفلیکت خود IDE استفاده می‌کنم و واقعا راضیم! بعد از رفع کانفلیکت باید فایل‌هایی که مشکل داشتن رو با git add علامت‌گذاری و کامیت کنید. کامیت‌های مربوط به رفع Conflict کامیت‌های خاصی هستن که لازم نیست براشون Commit message تعریف کنید، گیت به طور خودکار messageشون رو ایجاد می‌کنه.

خلاصه‌ای از مراحل آپلود کامیت‌ها

  1. push
  2. اگر ارور نخورد -> پایان
  3. اگر ارور non fast-forward خورد: pull
  4. برو به 1
  5. پایان

سوالات متدوال

اگر بخوایم یه کدی رو از یه مخزن remote، مثلا گیت‌هاب، دانلود کنیم و روش کار کنیم باید چه کار کنیم؟ سعی کردم pull و fetch کنم ولی نشد!

برای دانلود اولیه باید از دستور clone استفاده کنید. مثلاً:

git clone https://github.com/MJafarMashhadi/AndroidDrawableFactory

من یه کامیت کردم بعد git status زدم دیدم یه فایل رو جا انداختم چی کار کنم؟

اگر کامیت رو پوش کردید کاری نمیشه کرد. باید این فایل رو در یک کامیت جدا اضافه کنید وگرنه با آپشن ‎--amend میشه یه فایل رو به آخرین کامیت اضافه کرد.

git add /path/to/the/forgotten/file
git commit —-amend

من یه کامیت کردم، بعد متوجه شدم message رو اشتباه نوشتم، میخوام ویرایش کنم. میشه؟

اگر هنوز push نکردید بله.

git commit --amend

من یه کامیت کردم مسیجش رو عوض کنم ولی کامیتش خخیلی قدیمیه، ‎–amend‎ فقط رو کامیت آخر کار می‌کنه؟

بله فقط رو کامیت آخر کار می‌کنه. کامیت‌هایی که رو سرور push شدن اصلا قابل تغییر نیستن ولی اگه هنوز پوش نشده ممکنه بشه یه کارایی کرد (مثلا با rebase). سرچ کنید

(ویرایش: درسته که کامیت‌های push شده رو نمی‌شه تغییر داد اما با rebase و force push می‌شه تاریخچه رو بازنویسی کرد و بعضی کامیت‌ها رو حذف/ویرایش کرد، صرفاً یه کمی بیشتر کار و دقت و سطح دسترسی لازم داره!)

من یه تعداد فایل و پوشه دارم که نمی‌خوام git اونا رو تحت نظر بگیره. چه کار کنم؟

فایل‌های کامپایل شده و فایل‌های مربوط به IDE نمونه‌های این فایل‌ها هستند. این‌ها اگه وارد git بشن با فایل‌های مشابه بقیه هم گروهی‌ها قاطی می‌شن و اون‌ها دیگه نمی‌تونن  پروژه رو باز کنن. یا مثلا آپلود فایل‌های کامپایل شده کار بیهوده‌ای هست چون از روی سورس‌ها قابل ساخته شدن هستند و حجم مخرن گیت رو بالا می‌برند.

باید فایلی بسازید به اسم .gitignore توی این فایل اسم فایل و پوشه‌هایی که میخواید گیت تغییراتشون رو در نظر نگیره اضافه می‌کنین. مثلاً برای یک پروژه‌ی جاوا احتمالاً می‌نویسید:

*.class
*.jar

باید gitignore رو دستی درست کنم؟ آماده‌ش نیست؟

چرا هست! سایت gitignore.io این کار رو می‌کنه. توش کلمات کلیدی پروژه (مثلا Python Django Pycharm) رو وارد کنید، یه git ignore کامل درست می‌کنه. منظور از کلمات کلیدی اسم IDE و زبان برنامه نویسی و اسم فریم ورک‌ها و…س.

گیت فقط برای سورس کد و کار‌های برنامه نویسی استفاده می‌شه؟

نه. همونطور که اول مطلب گفتم گیت هر نوع فایلی رو میتونه در نظر بگیره و اصلا وابسته به این نیست که فایل‌ها حاوی کد هستند یا چیز دیگه. میشه با گیت ویراست‌های یک کتاب رو ذخیره کرد (به خصوص اگر کتاب با TeX حروف‌چینی شده باشه)؛ میشه فایل‌های config یک سیستم رو با گیت ذخیره کرد و از تغییراتشون با خبر شد و اگر چیزی اشتباه config شده بود با یک خط دستور git به تنظیمات گذشته برگشت؛ میشه مستندات یک سیستم رو با گیت مدیریت کرد و خیلی کاربردهای دیگه.

باز هم ادامه داره؟ من هنوز سوال دارم!

بله :) قسمت دوم رو مطالعه کنید.

Mohammad Jafar Mashhadi

Mohammad Jafar Mashhadi

Your average genius.

comments powered by Disqus
rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora