گیت چیست ؟
گیت یک نوع سیستم کنترل ورژن (VCS) است که با آن میتوانید تغییرات اعمال شده در فایلها را سادهتر پیگیری کنید. مثلاً، اگر فایلی را ویرایش کنید، گیت میتواند دقیقاً به شما بگوید که چه چیزی تغییر کرده است، چه کسی آن را تغییر داده است و دلیلِ این تغییر چه بوده است.
چرا از گیت استفاده کنیم ؟
زمانی که لینوس توروالدز داشت روی پروژه ی توسعه سیستمعامل متنباز لینوکس به همراه گروهش کار میکرد، افراد مختلفی در آن پروژه مشارکت می کردند. در آن زمان هر کسی که لینوکس را توسعه میداد نسخه ای از کد را ایجاد میکرد که در نهایت، دنبال کردن این نسخه ها کار دشواری بود. از این رو، توروالدز تصمیم گرفت تا یک ابزاری را برای مدیریت بهتر کدها و کارهاشون ابداع کند.
معمولا در پروژه ها نیاز داریم تا تغییراتی که داده ایم را مشاهده کنیم و گاهی به عقب برگردیم . در واقع اگر بتوانیم این کار را بکنیم، از نسخه های مختلف پروژه بکاپ لازم داریم.
برای پروژه های گروهی لازم است که بعد از اعمال تغییرات در کد یک فرد خاص، در سیستم های اعضای دیگر گروه نیز این تغییرات آورده و اعمال شود.
معمولا در پروژه ها نیاز داریم تا تغییراتی که داده ایم را مشاهده کنیم و گاهی به عقب برگردیم . در واقع اگر بتوانیم این کار را بکنیم، از نسخه های مختلف پروژه بکاپ لازم داریم.
برای پروژه های گروهی لازم است که بعد از اعمال تغییرات در کد یک فرد خاص، در سیستم های اعضای دیگر گروه نیز این تغییرات آورده و اعمال شود
دستورات مورد نیاز گیت
۱. پیکربندی گیت
بعد از نصب گیت، اولین کاری که باید انجام دهید پیکربندی گیت است. برای یک پیکربندی اولیه، دو دستور گیت وجود دارد که باید بدانید. اولین دستور مربوط به ثبت نام نویسنده و دومین ثبت ایمیل نویسنده است. از آن به بعد گیت تمام تغییرات را با استفاده از این مشخصات ثبت میکند.
git config --global user.name "matno"
git config --global user.email matno@matno.com
۲. پیادهسازی یک مخزن گیت
بعد از آنکه Git CLI را روی سیستمتان نصب کردید، به دایرکتوری که قصد پیادهسازی پروژه گیت در آن را دارید بروید. وقتی که در آن دایرکتوری قرار گرفتید، دستور زیر را اجرا نمایید:
git init
حال مخزن گیت شما پیادهسازی شد. از این به بعد گیت تمام تغییرات مربوط به این دایرکتوری را ثبت خواهد کرد. اگر به صورت درست تمام دایرکتوریهای موجود در مخزنتان را بررسی نمایید، مشاهده میکنید که یک پوشه .git قرار گرفته است که پیکربندیهای مربوط به گیت شما در آن قرار میگیرد.
۳. بررسی وضعیت مخزن
میتوانید وضعیت مخزن گیت را هر زمان که میخواهید با استفاده از دستور زیر بررسی کنید:
git status
سه وضعیت کلی در پروژههای گیت وجود دارد که شامل موارد زیر میشود:
staged , committed , modified
در واژهشناسی مربوط به گیت، فایلها بعد از اینکه ذخیره و آماده کامیت کردن شدند، در مرحله staged قرار میگیرند. بعد از اینکه فایلها در یک دیتابیس محلی واقع در پوشه .git قرار گرفتند به وضعیت committed تغییر پیدا میکنند و وقتی که تغییراتی در آنها قرار دادید اما آنها(تغییرات) را هنوز کامیت نکردهاید، به وضعیت modified در میآیند.
۴. فایلهای Stage
میتوانید فایلها را به دایرکتوری مربوط به پروژه یا همان مکان Stage با استفاده از دستور زیر وارد کنید:
git add index.html style.css images
این دستور فایلهای index.html و style.css و پوشه images را به وضعیت Stage در میآورد. اگر میخواهید تمام موارد قرار گرفته در پوشهای که در حال کار هستید را به حالت stage در بیاورید، کافی است دستور زیر را وارد کنید:
git add .
اگر یک دایرکتوری سنگین و پر از فایلهای مختلف دارید این دستور بسیار کاربری خواهد بود.
۵. فایلهای Unstage
میتوانید به سادگی فایلها را از قسمت stage نیز حذف کنید:
git rm --cached index.html style.css
اگر میخواهید پوشهها را نیز حذف کنید به یک پرچم -r نیازمندید:
git rm --cached -r images
بعد از اجرای این دستور گیت به شما پیامهای تاییدیه را میدهد، بنابراین شانس حذف اشتباهی فایلها و دایرکتوریها کمتر میشود.
برای اینکه تمام فایلها و دایرکتوریها را یکجا حذف کنید میتوانید به صورت زیر عمل کنید:
git rm --cached -r .
۶. کامیت فایلهای Stage شده
میتوانید از ناحیه stage مربوط به پروژهتان در هر زمان یک ذخیره مانند بگیرید. این حالت را کامیت کردن مینامند و فایلها را به بانک اطلاعاتی ارسال میکنند.
git commit -m "Initial commit"
همواره با ارسال فایلهای stage یک پیغام نیز نوشته میشود. در دستور بالا پیغام Initial commit نوشته شده است. برای اینکه بهتر بتوانید کامیتهایتان را قابل استفاده کنید و افراد مختلف کار آن را درک کنند از این پیغامها استفاده کنید.
۷. نمایش تغییرات Unstaged در جزئیات
برای اینکه بتوانید تمام تغییرات اتفاق افتاده در یک مخزن گیت را مشاهده کنید، میتوانید لیست آنها را از طریق دستور زیر بدست بیاورید:
git diff
این دستور نه تنها نام فایلها را برمیگرداند بلکه تغییرات مربوط به آنها را نیز در قالب متن به شما برگشت میدهد. دستور git diff موارد اضافی را با +++ و موارد حذف شده را با — نمایش میدهد.
۸. نمایش تاریخچه کامل کامیتها
گیت همچنین به شما اجازه میدهد تا تاریخچه کامل کامیتهایتان را در پروسه توسعه مشاهده کنید. برای انجام این کار میتوانید دستور زیر را وارد کنید:
git log
لاگ خروجی شامل آیدی، نویسنده، تاریخ و پیغام مربوط به هر کامیت است.
۹. کلون کردن یک مخزن ریموت – Clone
دستوراتی که همراه با ابزارهای آنلاینی مانند گیتهاب و… استفاده میشوند از جمله کاربردیترین دستورات مربوط به گیت است. برای اینکه یک کپی محلی از یک مخزن گیت آنلاین داشته باشید میتوانید به صورت زیر این کار را انجام دهید:
git clone https://www.github.com/your-online-repo
قبل از اینکه این دستور را انجام دهید، به دایرکتوری که قرار است مخزن در آن قرار بگیرد، بروید.
۱۰. ایجاد ارتباط با مخزن ریموت
جدای از اینکه میتوانید یک مخزن را دریافت کنید، میتوانید به صورت برعکس نیز عمل نمایید. برای کپی کردن یک مخزن محلی در یک سرور آنلاین مانند گیتهاب، ابتدا نیاز است که یک ارتباط را با مخزن آنلاین داشته باشید، پس از آن مخزن محلی را به سرور push کنید:
git remote add origin https://www.github.com/your-online-repo
با استفاده از دستور بالا، میتوانید مخزن آنلاین را به پروژه محلیتان متصل کنید. در آینده دیگر نیازی ندارید که URL را به صورت کامل بنویسید، میتوانید از طریق نام origin ارتباط را برقرار کنید.
همچنین میتوانید با استفاده از دستور زیر برای آدرس جدید تاییدیه بگیرید:
git remote -v
۱۱. Push کردن تغییرات محلی به مخزن آنلاین
بعد از اینکه ارتباط بین مخازن آنلاین و محلی را ایجاد کردید، میتوانید تغییرات را با استفاده از دستور زیر push کنید:
git push origin master
کلمه کلیدی origin برای اشاره به مخزن آنلاین استفاده میشود، در حالیکه master برای برنچ مخزن محلی است.
۱۲. دریافت آخرین تغییرات در مخزن آنلاین
اگر با یک مخزن آنلاین ارتباط دارید و قصد دارید تغییرات آن را مشاهده کنید، نیازی نیست که یک کپی از آن بگیرید، بجای آن میتوانید با استفاده از دستور زیر به صورت بسیار ساده تغییرات را مشاهده کنید:
git fetch origin
دستور git fetch تنها تغییرات را دریافت کرده و آنها را به هیچ جایی منتقل نمیکند.
۱۳. انتقال تغییرات دریافت شده
وقتی که مطمئن شدید تغییرات هیچ مشکلی ندارند، بعد از آن میتوانید تغییرات را به مخزن محلی خود انتقال دهید. برای انجام این کار میتوانید از دستور زیر استفاده کنید:
git merge origin/master
همیشه برای انجام انتقال نیاز است که نام branch مورد نظرتان را معلوم کنید. در دستور بالا ما تغییرات را به branch مربوط به master انتقال دادهایم.
نام گذاری صحیح کامیت
چرا پیام کامیت مهم است؟
موفقیت یک پروژه در بلندمدت به نگهداری و مدیریت آن بستگی دارد که به عهدهی مشارکتکنندگان اصلی آن است. مهمترین ابزاری که آنها در اختیار دارند، لاگ تغییرات کدها است. تنها با وجود پیامهای دقیق و استاندارد است که دستورهای `revert`، `blame`، `git rebase` و `log` کاربرد پیدا میکنند و بررسی کامیتهای دیگر مشارکتکنندگان ممکن میشود. حتی فهمیدن تغییری که ماهها یا سالها پیش افتاده است نه تنها ممکن، بلکه به شکل بهینهای انجام خواهد شد.
قراردادی برای بهتر نوشتن پیام کامیت ها
():
برای مثال:
fix(middleware): ensure Range headers adhere more closely to RFC 2616
Add one new dependency, use `range-parser` (Express dependency) to compute
range. It is more well-tested in the wild.
Fixes #2310
در این قاعده سعی می کنیم قرارداد کنیم که هر خط از پیغام کامیت بیشتر از 100 کاراکتر نباشد. همین باعث می شود که خواندن متن کامیت هم در گیتهاب و هم در سایر ابزار های گیت آسان تر باشد. هر متن کامیت دارای سرآمد (header)، بدنه (body) و بخش زیرین (footer) است که توسط خط خالی (Blank line) از هم جدا می شود.
متن سرآمد
متن قسمت سرآمد یک خط است که به صورت خلاصه وار توضیحاتی را در مورد تغییرات ارایه میدهد و شامل نوع (type)، محدوده [تغییرات] (scope) و موضوع (subject) می باشد.
مقادیر مجاز <type>
نوع تغییرات که کامیت شده را بیان می کند:
- افزودن یک ویژگی جدید به پروژه (feat (feature
- حل یک مشکل (fix (bug fix
- مستندات پروژه (docs (documentation
- فرمت کردن کد (…,style (formatting, missing semicolons
- refactor
- آزمون واحد و یکپارچه سازی (test (when adding missing tests
- کارهایی از قبیل اضافه کردن تسک های gulp و npm و… که تغییری در فایل های آزمون و src ایجاد نمی کنیم ?.(chore (maintain
مقادیر مجاز <scope>
محدوده هر چیزی می تواند باشد که محل انجام تغییرات را بیان می کند که در آن کامیت تغییر یافته اند. برای مثال: login , نام کامپوننت ، middleware، … یا اگر محل مناسبی را برای تغییرات انجام شده نیافتید * می گذاریم.
متن <subject>
یک توضیح بسیار کوتاه در مورد تغییر انجام شده.
- از یک فعل امری و زمان حال استفاده کنید: برای مثال “change” و نه “changed” یا “changes”
- اولین حرف را بزرگ نمی نویسیم.
- آخر جمله . نمی گذاریم.
متن بدنه <body>
- همانند متن موضوع از یک فعل امری و زمان حال استفاده کنید: برای مثال “change” و نه “changed” یا “changes”
- دربرگیرنده انگیزه برای تغییر و بیان تفاوت با رفتار قبلی
متن بخش زیرین <footer>متن بخش زیرین <footer>
ارجاع دادن به یک issue
اشکالات رفع شده (یا issue های بسته شده) باید در یک خط جداگانه در فوتر با پیشوند “Closes” نوشته شود.
Closes #234
یا چندین مورد را به این شکل می نویسیم:
Closes #123, #245, #992
کانفلیکت - Conflict
کانفلیکت چیست و چگونه به وجود می آید؟
فرض کنید که به صورت تیمی بر روی یک پروژه کار می کنید. همکار شما تغییراتی را بر روی یک فایل اعمال کرده و آن را به Remote ارسال و یا Push کرده است، شما هم در همین لحظه در Local خود همان خط از فایل را تغییر دادید و از تغییرات همکار خود خبری ندارید.
بعد از مدتی همکارتان از شما درخواست می کند که اطلاعات جدید را Pull کنید و شما هم دستور git pull را اجرا می کنید تا آخرین تغییرات دریافت شود و پروژه به روز گردد. در این لحظه است که یک Merge conflict رخ می دهد و اصطلاحا Git گیج شده است و نمی داند که تغییراتی که در Local شما وجود دارد را باید نگه دارد یا تغییراتی که همکارتان بر روی خط مورد نظر انجام داده است.
این مشکل لزوما فقط در پروژههای تیمی رخ نمی دهد و اگر بر روی چند Branch هم به صورت فردی کار کنید، گاهی به این مشکل برخواهید خورد و باید برطرف کردن آن را بلد باشید و یک نیاز اساسی به حساب می آید. مثلا فرض کنید که یک فایل را در دو Branch تغییر داده باشید و حالا قصد دارید این دو Branch را با هم Merge و یا ادغام کنید، در این مواقع هم به Merge conflict خواهید خورد.
برطرف کردن یک کانفلیکت – Conflict Resolve
فرض کنید یک ریپوزیتوری داریم و شاخه ای به نام feature/second-edition ایجاد کردیم و قسمتی از کد را در آن تغییر دادیم .حالا بعد از مدتی میخوایم شاخه feature/second-edition را با شاخه master ادغام یا merge کنیم. برای اینکار در شاخه master دستور git merge feature/second-edition را اجرا میکنیم. خروجی به شکل زیر می شود:
همانگونه که مشاهده میکنید بعد از اجرای این دستور، git تلاش می کند که به صورت اتوماتیک تغییرات sample.txt را ادغام یا merge کند. ولی به خاطر اینکه هم در شاخه master و هم در شاخه feature/second-edition تغییراتی بر روی یک خط از یک فایل داده شده است، git نمی داند کدام مورد را در نظر بگیرد و به همین دلیل merge به صورت کامل انجام نمی شود.
در اینجا هست که وارد حالت MERGING شده ایم و به همین دلیل هم شاخه master به master|MERGING تبدیل شده و به این معنی است که شما باید conflict ها را برطرف کنید و مجددا تغییرات را commit کنید.
زمانی که در حالت MERGING هستید، اگر فایل Sample.txt را باز کنید، چنین محتوایی در اون قرار گرفته است:
<<<<<<>>>>>> feature/second-edition
کدهایی که بین خط <<<<<< HEAD و ======= هست، کدهایی هستند که در شاخه فعلی یا master وجود دارد و کدهایی که بین ======= و >>>>>>> feature/second-edition وجود دارد، کدهایی هستند که در شاخه feature/second-edition قرار داشتهاند. این دو خط همان دو خطی هستند که conflict برای اونا رخ داده است.
شما باید بین این دو کد یکی را انتخاب کنید و دیگری را به صورت دستی حذف کنید. همچنین می توانید بسته به شرایط پروژه ی خود، هر دو مورد را حذف یا هر دو مورد را نگه دارید. اگر شما از ویرایشگر Visual Studio Code استفاده می کنید، زمانی که merge conflict رخ میدهد، کدها به صورت زیر می شوند:

می بینید که با استفاده از رنگهای متفاوت مشخص شده که دو چیزی که conflict بر روی آنها رخ داده است، چه چیزهایی هستند. حالا در بالای این کدها، لینک هایی قرار داده شده که میتونید با استفاده از اونها به راحتی merge conflict را برطرف کرده و بین این دو کد همانی که مد نظرتان است را انتخاب کنید.
- Accept current change: با انتخاب این گزینه اون تغییری که در شاخه master یا فعلی است، انتخاب میشه.
- Accept incoming change: با انتخاب این گزینه اون تغییری که در شاخه feature/second-edition است، انتخاب می شود.
- Accept both changes: با انتخاب این گزینه، هر دو تغییر به صورت همزمان نگه داشته می شوند.
- اگر هیچ کدام از موارد را نخواستید، می توانید به راحتی از خط 1 تا خط 5 را به صورت کامل حذف کنید. با این کار هم merge conflict برطرف می شود.
الان فرض کنید که روی Accept incoming change کلیک می کنیم. با این کار محتوای فایل sample.txt به صورت زیر می شود:

خب تا اینجا merge conflict را برطرف کردیم و حالا اگر merge conflict دیگری هم وجود داشته باشد باید بقیه را هم به همین صورت برطرف کرد. زمانی که همه merge conflictها برطرف شدند باید دستور git commit را اجرا کنید تا تغییرات مورد نظر انجام شود و merge به صورت کامل انجام شود و از حالت MERGING خارج شویم.
گیت فلو - Git Flow

برای اینکه جریان کاری توسعه را با برنچ های مختلفی در تیم توسعه کنترل کنید از مدل های مختلف مفهومی ای می توانید الگو برداری کنید که به اونها Git Flow می گویند. یکی از سناریوهای معمول گیت را در ادامه بررسی می کنیم: وقتی با گیت شروع می کنید روی برنچ master هستید و در ادامه می توانید چندین برنچ مختلف برای پروژه ی خودتون بسازید ، مثلا برنچ update یا feature و توی اون branch ها کار کنید و وقتی نیاز داشتنید هم merge میکنید و دوباره به master و یا development میرسید.
سناریو کار گیت در خیلی از شرکت ها به این شکل است که شاخه های مختلفی برای کنترل جریان توسعه می سازند – شاخه هایی نظیر:
شاخه master: که کدهای پروژه (در حال اجرا) قرار دارند و ممکنه همه بهش دسترسی نداشته باشند.
شاخه develop: کار روی پروژه از اینجا شروع میشه و توسعه دهنده ها میتوانند کدهای خود را در این قسمت push کنند اما این همه ی ماجرا نیست. اگه قرار باشه ۵ نفر همزمان روی این شاخه کار کنند ممکنه conflict به وجود بیاد، پس شاخه دیگه ای هم لازم داریم:
شاخه feature: فرض کنید علی قرار است بر روی قسمت login کار کند و محمد بر روی قسمت home. پس به راحتی می توانند هر کدام شاخه های خودشان را داشته باشند و مثلا شاخه هایی به اسم feature/login و feature/home بسازند. در نهایت وقتی کار تمام شد این شاخه با شاخه develop مرج میشه و در صورتی که لازم باشه بعدا با شاخه master هم merge میشه!
شاخه hotfix: فرض کنید محمد و علی روی فیچرهایی که گفته شده کار میکنند که مدیر پروژه متوجه یک مشکل اساسی در پروژه ی در حال اجرا ( که طبیعتا روی شاخه master هست) می شود و می خواهد به سرعت این مشکل حل شود. پس از یکی از توسعه دهنده ها درخواست می کند که این موضوع را به سرعت حل کند!
این جا شاخه ی hotfix به وجود میاد و بدون اینکه با فیچرها دخالتی داشته باشد از master یه شاخه ای گرفته می شود و فرد توسعه دهنده اقدام به رفع مشکل می کند! بعد از اینکه مشکل حل شد با master و یا develop مرج می شود. محمد و علی هم بدون مشکل به کار خود ادامه می دهند!
شاخه release: همانطور که از اسم آن مشخص است مربوط به نسخه های نهایی و عملیاتی است و مثلا وقتی پروژه به جایی رسید که قرار است release شود یک تگ هم به آن برچسب می زنیم مثلا 2.4.1 و … (با Tag یا تگ ها صرفا سلسله کامیت های مشخصی را تا نقطه فعلی می توان نامگذاری کرد)
منابع :
https://virgool.io/@mmdsharifi/how-to-semantic-git-commit-messages-gvmmqatf6acg
https://7learn.com/tutorials/how-to-resolve-merge-conflict-in-git