نکات و ترفندهای گیت | به زبان ساده


با این که بارها گفته شده است، اما اگر یک بار دیگر نیز تکرار کنیم، خالی از لطف نخواهد بود که همه توسعهدهندگان نرمافزار باید از یک ابزار «کنترل نسخه» (Version Control) استفاده کنند. چه بهتر که این ابزار کنترل نسخه که استفاده میکنید، یکی از محبوبترین ابزارها در سراسر دنیا یعنی Git باشد که همه افراد نام آن را شنیده و با آن آشنا هستند. در این مقاله با نکات و ترفندهای گیت (Git) آشنا خواهیم شد.
در صورتی که علاقه ندارید از سرورهای مشهور میزبانی گیت مانند GitHub ،GitLab یا Bitbucket استفاده کنید، یا این کار برای شما مناسب نیست، میتوانید یک سرور ریپازیتوری را به صورت خصوصی روی سرورهای خودتان میزبانی کنید.
مبانی Git
در این بخش برخی مفاهیم ابتدایی در خصوص Git و به طور کلی کنترل نسخه مطرح میشوند.
منظور از کنترل نسخه چیست؟
کنترل نسخه را میتوان به عنوان نقاط ذخیرهسازی کد توصیف کرد. فرض کنید یک فیچر جدید را به تازگی برای یک محصول که در حال استفاده است به اتمام رسانده و همه چیز را مستندسازی کردهاید و اینک میخواهید کد را به مدل پروداکشن اضافه کنید. به این منظور باید یک «مرور کد» (Code Review) اضافه شود تا بتوانید کد را به کنترل سورس اصلی اضافه (Merge) کنید. اگر شرکتی که در آن کار میکنید از کنترل نسخه استفاده نکند، شما مجبور خواهید بود تغییرات را به صورت دستی در پروژه سورس وارد کنید. همه اینها در حالی است که یک نفر باید پشت میز شما بنشیند و تغییراتی را که شما ایجاد کردهاید به صورت دستی بازبینی کند.
در اینجا است که کنترل نسخه وارد بازی میشود. به جای این که همه فرایند ادغام کد به صورت دستی انجام یابد، کنترل نسخه همه مراحل را به جای شما بر عهده میگیرد. کافی است کد خود را روی یک شاخه مجزا ذخیره کنید و زمانی که کار پایان یافت، شاخهها و تغییراتی که ایجاد شده را در هم ادغام کنید.
به این ترتیب صرفهجویی زیادی در زمان و تلاش شما ایجاد میشود و در واقع یک ابزار کاملاً ضروری محسوب میشود، زیرا به مرور تایملاین پروژه شتاب میگیرد و اندازه تیم برنامهنویسی نیز افزایش خواهد یافت.
چرا باید از کنترل نسخه استفاده کنیم؟
اگر تا کنون با مشکل از دست دادن فایل مواجه شدهاید، یا اگر تا کنون درست پیش از انتهای موعد زمانی مجبور شدهاید کد را ریفکتور کنید، چون کامپایل نشده است و اگر تا به حال به صورت تصادفی هارد درایو خود را فرمت کردهاید، پیشنهاد میکنیم از کنترل سورس استفاده کنید.
دلیل اصلی استفاده از ابزار کنترل نسخه این است که در صورت استفاده از یک ریپازیتوری ریموت که به صورت خصوصی یا عمومی نگهداری میشود، کار از حالت متمرکز خارج میشود و حالت «نقطه منفرد شکست» از فرایند گردش کار حذف میشود. همچنین میتوانید تغییرات و پیشرفت پروژه را ردگیری کنید. به این ترتیب میتوانید میزان رشد پروژه را از ابتدا مشاهده کنید.
پسزمینه Git
Git از سوی خالق لینوکس، «لینوس تروالدز» (Linus Torvalds) در سال 2005 معرفی شده است. هر ریپازیتوری (به اختصار ریپو یا repo) دارای امکان ردگیری کامل تاریخچه و همچنین کنترل نسخه است که مستقل از هر سرور مرکزی عمل میکند. افراد دیگر میتوانند در صورت اجازه شما، کد را مستقیماً از رایانه شما دریافت کنند، اما ما عموماً از یک سرور مرکزی برای اشتراک و میزبانی فایلها برای تیم کاری استفاده میکنیم.
برای کسب اطلاعات بیشتر در مورد گیت و ابزارهای مربوطه میتوانید از مطالب زیر استفاده کنید:
- راهنمای پیشرفته Git برای مبتدیان — به زبان ساده
- ۱۰ دستور گیت (Git) که باید آنها را بدانید — فهرست کاربردی
- سیستم کنترل نسخه گیت (Git) — راهنمای جامع
ریپو چیست؟
ریپو اختصاری برای عبارت «ریپازیتوری» (Repository) و یک ساختمان داده است که متادیتایی در مورد فایلها یا پوشههای خاص نگهداری میکند. بدین ترتیب میتوانیم تغییرها را ثبت کنیم و به صورت مستقل از هم ارسال کنیم و دیگر نیازی به ارسال کل فایل در زمان تغییر یافتن یک بخش کوچک وجود ندارد. سیستمهای کنترل نسخه با استفاده از ریپازیتوریها، فایلها را در زمان رشد پروژه میسازند و کامیتها (تغییرات در فایلها) حذف و اضافه میشوند.
مقداردهی یک ریپو
مقداردهی اولیه یک ریپو که Initializing نامیده میشود، میتواند از خط فرمان یا اغلب ابزارهای ارتباط ریموت انجام گیرد. گیتهاب ابزاری به نام repo.new link دارد که با استفاده از دستورات آن میتوان پوشه مورد نظر را مقداردهی کرد:
/home/[username]/Documents/my-project $ git init
شما اکنون درون این پوشه my-project، یک پوشه به نام git. دارید چیزی را تغییر ندهید، مگر این که بدانید چه کار میکنید. به هم ریختن این پوشه میتواند به قیمت از دست رفتن ریپوی لوکال تمام شود.
کلون کردن ریپو
یک روش عالی برای ورود به گیت از طریق کامیت کردن یک پروژه قبل ایجاد شده از طریق کلون کردن یکی از پروژههای روی گیتهاب، گیتلب یا هر میزبان ریموت دیگر با دستور زیر است:
$ git clone https://github.com/[username]/my-project.git
به این ترتیب ریپویی که در آن لینک گیتهاب قرار دارد و در دایرکتوری جاری زیر پوشه ./my-project کلون میشود. اگر تداخل نام پیش آید، از طریق خط فرمان به اطلاع خواهد رسید.
کلون کردن موجب میشود که همه دادههای پروژه در رایانه لوکال قرار گیرد و یک درخت کاری لوکال ایجاد شود. تغییراتی که در این پروژه لوکال انجام میشوند تأثیری روی ریپوی ریموت نخواهند داشت، مگر این که از دستور git push به شاخه مرتبط ریپوی ریموت استفاده کنید.
کامیت
کامیت به روش ذخیرهسازی تغییرات جاری در پوشه کاری گفته میشود. زمانی که کار خود را به پایان رساندید، مثلاً یک فایل README.md برای توصیف پروژه اضافه کردید، باید کار خود را ذخیره کنید. البته کار را میتوانید هر زمان که دوست داشتید ذخیره کنید. زمانی که در نهایت کامیت کردید، همواره از یک پیام کامیت استفاده کنید که تغییرات انجام یافته درون کامیت را توصیف کند.
پیش از اجرای کامیت باید فایلهایی که تغییر یافتهاند را به دایرکتوری staging جاری استفاده کنید. به این منظور از دستور زیر استفاده میکنیم:
$ git add –all
با استفاده از فلگ all– همه فایلهای تغییر یافته درون پروژه git کنونی اضافه میشوند. برای اجرای عملی دستور کامیت باید دستور زیر را در کنسول اجرا کنید:
$ git commit -m "[commit message]"
ایجاد یک ژورنال کنترل شده نسخه شخصی
در این بخش یک پروژه جالب میسازیم تا با کارکردهای گیت و مفاهیمی که تا به این جا معرفی کردیم، بیشتر آشنا شویم. به این منظور یک ژورنال روی رایانه شخصی خود خواهیم ساخت. یک ژورنال ساده در بخش یادداشتهای رایانه ایجاد میکنیم. لزومی ندارد که آن را روی یک ریپوی ابری ذخیره کنیم، کافی است آن را روی رایانه خود داشته باشیم.
یک پنجره ترمینال (اعلان فرمان) را باز کنید. به دلخواه خود به یک دایرکتوری بروید. مثلاً میتوانید به صورت زیر عمل کنید:
1. $ cd /home/$USERNAME/Documents/my-journal 2 $ cd /$USERNAME/Documents/my-journal 3. $ cd C:/Users/
اکنون اپلیکیشن را با دستور زیر مقداردهی میکنیم:
$ git init
ایجاد سند
سپس یک سند جدید به دلخواه ایجاد میکنیم. این سند میتواند یک سند ورد، Vim ،Nano ،Pages ،Gedit ،PyCharm ،notes و یا هر چیز دیگری باشد که بتوان چیزی درون آن نوشت. هر چه که به ذهنتان میرسد در این سند متنی بنویسید. زمانی که این متن را نوشتید، باید آن را ذخیره کنیم. به منظور کامیت کردن تغییرات باید از دستورهای زیر در ترمینال استفاده کنیم:
$ git add. $ git commit -m “[type]: [message]” $ git push origin [master|main|mainline|whatever master is now]
اکنون که نخستین کامیت خود را دارید، چه به طور مرتب مطالبی به آن اضافه کنید و چه هیچ گاه آن را ویرایش نکنید، در هر صورت یک ابزار قدرتمند و زیبا در اختیار دارید. در ادامه با برخی نکات و ترفندهایی که این کنترل نسخه میتواند برای توسعهدهندگان اپلیکیشنهای بزرگ-مقیاس داشته باشد، توضیح خواهیم داد.
نکات کنترل نسخه
درختکاری
منظور از «درختکاری» (Working Tree) حالت فایلها در یک دایرکتوری است. برای نمونه پروژه میتواند از یک ریپوی ریموت کلون شده باشد. در این صورت درخت کاری و نقطه Head بدون هیچ تغییری به صورت همان کامیت است. به محض این که فایلها تغییر یابند، دیگر در همان HEAD نخواهند بود. زمانی که تغییرات کامیت و پوشش شوند، درخت لوکال و ریموت شما دوباره با همان ارجاع کامیت HEAD تطبیق مییابند. برای کسب اطلاعات بیشتر به مستندات (+) مراجعه کنید.
شاخهسازی
استفاده از «شاخه» (branch) در ریپوی گیت امری ضروری است. با این که اساساً ما به یک شاخه (یا main یا هر نام دیگر) نیاز داریم، اما استفاده از بیش از یک شاخه در زمان کار در یک تیم امری ضروری است. به خصوص در صورتی که نمیخواهید به طور مداوم تداخلهای هر کامیت را رفع کنید، باید از این روش استفاده کنید.
شاخهها را میتوان مانند قطارهای مختلف فکری تصور کرد. هر شاخه یا برنچ یک قطار متفاوتی از افکار، یک فیچر متفاوت، اصلاحیه، اثبات مفهوم (proof-of-concept) و یا هر چیز دیگر است. استفاده از شاخهها به این روش کاملاً ضرورت دارد، تا زمانی که ایده پایان یافت، بتوان به سرعت و به طرز مناسبی به منبع اصلی (شاخه پیشفرض) اضافه کرد.
برای آغاز کار با شاخهها در یک ریپازیتوری انتخابی، دستور زیر را برای بررسی شاخههایی که هم اینک موجود هستند، اجرا کنید:
$ git branch
فهرست شاخهها
به این ترتیب فهرستی از شاخهها دیده میشوند که هم اینک بخشی از ریپازیتوری هستند. این فهرست از نام ریموت (معمولاً origin) پیش از ایجاد شاخه استفاده میکند. پیش از آن که با روش ایجاد شاخه آشنا شویم، با روش سوئیچ کردن بین شاخهها آشنا خواهیم شد. برای استفاده از یک شاخه دیگر (مانند dev) کافی است دستور زیر را اجرا کنید:
$ git checkout dev
یا از دستور زیر استفاده کنید:
$ git switch dev
در زمان ایجاد یک شاخه جدید سه گزینه در اختیار داریم:
1. $ git checkout -b new-feature 2. $ git branch new-feature 3. $ git switch -c new-feature
- Checkout
چکاوت با فلگ b- برای برنچ موجب بهروزرسانی درخت کاری برای تطبیق با نسخه مفروض در اندیس یا درخت مشخص شده میشود و سپس یک برنچ از نسخه میسازد. چکاوت ما را مطمئن میسازد که هرگز شاخه جدید را به وسیله یک هد جدا شده نساختهایم و از بروز بسیاری از مشکلات جلوگیری میکند.
- Branch
نکته جالب اینجا است که Branch گزینه نخست ما نیست؛ بلکه همواره باید نخست از چکاوت استفاده کنیم. با این حال Branch صرفاً برنچ را ایجاد میکند و مانند checkout یا switch به صورت خودکار به برنچ سوئیچ نمیکند. همچنین با استفاده از دستور برنچ میتوانیم دو شاخه را در زمان استفاده از مرجعهای شاخه با دستور زیر ادغام کنیم:
$ git branch master...dev
اما این کار به تمیزی دستور چکاوت انجام نمییابد.
- Switch
استفاده از گزینه Switch با فلگ c- برای «ایجاد» موجب ایجاد یک شاخه جدید و سوئیچ به شاخه میشود. سوئیچ کردن الزامی برای ایجاد یک ریپازیتوری تمیز ندارد و میتواند به صورت detach-شده از شاخه اصلی باشد. همچنین سوئیچ کردن به صورت خودکار از ریپازیتوری ریموت انجام مییابد.
گردش گیت
دستور Git Flow شاخههای گیت را مدیریت میکند. Flow یک سیستم برای مدیریت شیوه ساخت شاخهها از سوی توسعهدهندگان ارائه میکند و از این رو دیگر شاهد شاخههایی نخواهیم بود که نامتمرکز هستند و یا روی یک فیچر منفرد آغاز شده باشند، اما سپس به اشتباه به شاخه main تبدیل شوند.
تعریف کردن یک ساختار برای شاخهها موجب حذف نیاز به overbear روی آن چیزی که پروژه متمرکز شده است میشود. برای نمونه Flow-یی که مناسب است و بهتر است در اغلب پروژهها استفاده کنید از اصولی که در ادامه ارائه میکنیم پیروی میکند.
گردش گیت ریپازیتوری
گردش گیت ریپو در واقع شیوه ساخت و استفاده از شاخههای پروژههای را تعیین میکند که همان شیوه گردش کار برای ساخت پروژهها است.
به طور کلی چهار نوع شاخه برای یک پروژه میتوان تعریف کرد:
- - master
- - release
- - hotfix/*
- - feature/*
شاخه master
شاخه مستر یک شاخه کاملاً خاص است. این شاخه شامل نسخه کنونی «پایدار» (stable) از پروژه است. این شاخه در برابر push-های اجباری حفاظت میشود، یعنی کسی نمیتواند یک کامیت یا merge را به آن اضافه کند یا پوش نماید. هر چیزی که به مستر اضافه میشود، باید از طریق یک درخواست pull باشد تا کد بتواند مرور، تست و پذیرفته شود. فیچرهای جدید باید از master انشعاب بگیرند، اما این کار الزامی نیست.
شاخه Release
شاخه release یا «انتشار» جایی است که نسخه پایدار پروژه میزبانی خواهد شد. زمانی که پروژه به نقطه خاصی برسد و آماده انتشار برای عموم باشد، نسخه پروژهای که توزیع میشود، نسخه کنونی شاخه master است که از طریق درخواست pull در شاخه release ادغام میشود. درخواست pull آخرین کاری است که پیش از آغاز به کار پایپلاین CI/CD برای توزیع نسخه روی استریمهای مختلف انجام مییابد.
شاخههای */Hotfix
شاخههای Hotfix (به این جهت از لفظ شاخهها استفاده میکنیم که Hotfix/ یک ساختار پوشه است) برای ایجاد یک اصلاحیه باگ از شاخه master مورد استفاده قرار میگیرد. هاتفیکسها به طور خاص برای باگ یا مشکل ساخته شدهاند و زمانی که باگ رفع شود، مجدداً به درخواست pull مستر اضافه شده و مستقیماً در آن ادغام میشوند. به این ترتیب شاخه متمرکز و کوچکی ایجاد میشود که تداخلی با شاخههای فیچر ندارد.
شاخههای */Feature
شاخههای Feature/* نیز تا حدود زیادی شبیه به شاخههای hotfix هستند، با این حال گستره آنها کمی وسیعتر است و شامل یک فیچر جدید در خود پروژه میشوند. شاخههای فیچر باید دامنه کوچکی داشته باشند. برای نمونه feature/multiplayer بسیار وسیع است، feature/matchmaking کمی بهتر است، feature/server-and-connection کاملاً مناسب است. کافی است تلاش کنید خاص و متمرکز روی یک موضوع باشد که آماده ادغام در شاخه مستر (محیط پروداکشن) است.
روششناسی فوق در زمانی که روی پروژههای تیمی کار میکنید، کارایی خود را بیشتر نشان میدهد. همواره از شاخه release هر چند در پروژههای ساده استفاده کنید. همچنین به خاطر بسپارید که شاخه master|main باید تنها شاخه پایدار release در هر زمان باشد. این بدان معنی است که وقتی فیچرها به پروژه اضافه میشوند، فیچرهای کاملی هستند و دست کم مقداری تست روی آنها اجرا شده است.
اکنون که با گیت بیشتر آشنا شدید، شاید حس کنید که درک کامل آن، کاری خستهکننده است. بنابراین پیشنهاد میکنیم از ابزاری به نام GitKraken (+) استفاده کنید تا به سادگی پروژهها را در نگاه نخست تحلیل نمایید.
سازماندهی کامیتها
استفاده از یک ساختار استاندارد برای پیام کامیت موجب میشود که ابزار مهمی برای مستندسازی تغییرات در کامیت داشته باشید و همچنین توسعهدهندگان بیشتر و بهتر روی آن چیزی که کار میکنند، متمرکز شوند.
نکات و ترفندهای گیت
در این بخش برخی ترفندهای پیشرفته در خصوص گیت را با هم مرور میکنیم.
Git Blame
زمانی که متوجه بشویم خطا در کدام خط قرار دارد، چه اتفاقی میافتد؟ هیچ اصلاحیهای وجود ندارد و تنها با خطاها سروکار داریم. هر بار که برنامه را کامپایل و اجرا میکنیم، از کار میافتد. با خود فکر میکنید که تغییری در کد ایجاد نکردهاید، فقط تغییرات را pull کردهاید، ادغام انجام یافته است و اینک شما نمیتوانید تغییراتی را که یک توسعهدهنده دیگر انجام داده است، بررسی کنید.
حال فرض کنید یک توسعهدهنده پنج تغییر و توسعهدهنده دیگر دو تغییر در کد ایجاد کردهاند. بدون بررسی تکتک خطوط کدهای کامیت شده چطور میتوان مشکل را رفع کرد؟ در این حالت کافی است دستور Git Blame را اجرا کنید. به این ترتیب تمام خطوطی که در کامیت آخر تغییر یافتهاند نمایان میشوند و به این ترتیب مشخص میشود که چه کسی را باید برای ایجاد خطا سرزنش (Blame) کرد. همچنین میتوانید alias را با استفاده از دستور زیر تغییر دهید:
$ git config --global alias.praise blame
Git Bisect
فرض کنید یک باگ بین 5 کامیت دارید. کامیت 1 آخرین موردی است که به درستی کار میکرد و میدانید که کامیت 2 و کامیت 4 باگ دارند، اما در مورد کامیتهای 4 و 5 مطمئن نیستید. با استفاده از زیردستور Git Bisect میتوانید در میان کامیتها پیمایش کنید و بفهمید که کدام یک به درستی بیلد نمیشوند. به طور خاص میتوانید کامیتی که باگ را وارد برنامه کرده است پیدا کنید. فرض کنید پروژهای که از آن صحبت کردیم، یک پروژه npm است:
با استفاده از کد فوق میتوانیم بفهمیم که تست کجا fail میشود و فایلهایی که با git diff تغییر یافتهاند را بررسی کنیم. بدین ترتیب یک ایده کلیدی مهم دیگر مشخص میشود. مطمئن شوید که در پروژه خود از تست استفاده کردهاید تا سیستم کنترل نسخه در زمان شما صرفهجویی کرده و باگها را پیدا کند.
Git Commit Amend
فرض کنید به تازگی چیزی را کامیت کردهاید و یک فایل بهروزرسانی شده است. اکنون میخواهید آن را پیش از پوش کردن به کامیت آخر اضافه کنید. در این حالت کافی است از فلگ –amend استفاده کنید.
برای اجرای این کار باید از دستور زیر استفاده کنید:
git add --all; git commit –amend
به این ترتیب فایلها اضافه میشوند و مدیریت ادغام در $EDITOR پیکربندیشده شما از CLI اجرا میشود. اگر از VIM استفاده میکنید با وارد کردن :wq از آن خارج میشوید.
مدیریت اطلاعات احراز هویت Git
گیتهاب اخیراً مقالهای (+) در خصوص یک ابزار مدیریت اطلاعات احراز هویت سراسری منتشر ساخته است که روی پلتفرمهای مختلف از قلیل ویندوز، لینوکس و مک اجرا میشود و به کاربران مکان میدهد که اطلاعات چند حسابی خود را روی رایانه خودشان ذخیره کرده و با سرعت بیشتری اپلیکیشنها را بیلد و توزیع نمایند. برای کسب اطلاعات بیشتر به این صفحه (+) مراجعه کنید.
سخن پایانی
از این که این مقاله را برای مطالعه انتخاب کردید متشکریم. امیدواریم هم اینک بتوانید مفاهیم مقدماتی گیت را بهتر درک کرده و با برخی ترفندهای پرکاربرد آن آشنا شده باشید.