گیت (Git) یک سامانهی کنترل نسخه است: ابزاری که تاریخچهی تغییرات فایلهای یک پروژه را نگه میدارد تا بتوانید ببینید چه چیزی، کی و چرا عوض شده، به هر نقطهی قبلی برگردید و همزمان با دیگران روی یک کد کار کنید بیآنکه کار هم را خراب کنید. هر کپی از مخزن گیت کل تاریخچه را با خودش دارد، برای همین بیشتر کارها بدون اینترنت و خیلی سریع انجام میشود.
گیتهاب (GitHub) و سرویسهای مشابه مثل GitLab چیز دیگریاند: جایی برای نگهداشتن نسخهی مشترک مخزن روی اینترنت، بههمراه امکاناتی مثل Pull Request، بررسی کد و CI. گیت ابزار است و روی سیستم خودتان اجرا میشود؛ گیتهاب میزبانی است که مخزن گیت شما را نگه میدارد. در ادامه دستورات مهم گیت را به ترتیبی که در کار روزمره به آنها نیاز پیدا میکنید مرور میکنیم.
پیش از شروع: نصب و معرفی خودتان
روی Ubuntu 24.04 گیت با یک دستور نصب میشود. بعد باید نام و ایمیلتان را تنظیم کنید، چون روی هر commit ثبت میشوند:
sudo apt install git
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
خط آخر باعث میشود شاخهی اصلی مخزنهای تازه main نام بگیرد، که امروز رایجترین نام است.
سه بخش گیت را بشناسید
بیشتر سردرگمیهای گیت از نشناختن این سه بخش است:
- پوشهی کاری (working tree): فایلهایی که میبینید و ویرایش میکنید.
- ناحیهی آمادهسازی (staging area یا index): تغییراتی که برای commit بعدی انتخاب کردهاید.
- مخزن (repository): تاریخچهی commitها که در پوشهی
.gitنگهداری میشود.
چرخهی کار همیشه همین است: فایل را عوض میکنید، با add آن را به staging میبرید و با commit در تاریخچه ثبتش میکنید.
دستورات روزمرهی گیت
شروع پروژه: init یا clone
اگر پروژه از صفر شروع میشود، داخل پوشهاش مخزن بسازید:
mkdir my-project && cd my-project
git init
اگر مخزن از قبل جایی مثل گیتهاب وجود دارد، آن را کپی کنید. این کار کل تاریخچه را میآورد و remote به نام origin را هم خودکار تنظیم میکند:
git clone git@github.com:user/my-project.git
status: همیشه اول ببینید کجایید
git status
این دستور میگوید روی کدام شاخهاید، کدام فایلها تغییر کردهاند، کدامها در staging هستند و کدامها هنوز اصلاً زیر نظر گیت نیستند. عادت خوبی است پیش از هر add و commit یک بار اجرایش کنید.
add و commit: ثبت یک قدم
git add index.php # یک فایل
git add src/ # یک پوشه
git add -p # تکهبهتکه، با پرسیدن دربارهی هر تغییر
git commit -m "Validate email before saving the contact form"
git add -p کمتر شناخته شده اما بسیار مفید است: وقتی در یک فایل دو کار نامرتبط کردهاید، میتوانید هر کدام را در commit جدا ثبت کنید.
پیام commit را برای کسی بنویسید که یک سال بعد آن را میخواند: چه چیزی عوض شد و چرا. «fix» و «update» چیزی به او نمیگویند.
log و diff: دیدن تاریخچه و تفاوتها
git log --oneline # هر commit در یک خط
git log --oneline --graph # همراه با نمودار شاخهها
git diff # تغییراتی که هنوز add نشدهاند
git diff --staged # تغییراتی که add شدهاند و در commit بعدی میروند
git diff main..feature # تفاوت دو شاخه
پیش از هر commit یک git diff --staged بزنید. بارها جلوی رفتن یک dd() یا رمز آزمایشی به مخزن را میگیرد.
branch و switch: کار موازی بدون دردسر
شاخه (branch) یک خط کار جداست. برای هر قابلیت یا رفع باگ یک شاخه بسازید تا main همیشه سالم بماند:
git branch # فهرست شاخهها
git switch -c feature/login # ساخت شاخهی تازه و رفتن به آن
git switch main # برگشت به main
git branch -d feature/login # حذف شاخهای که merge شده
دستور switch در نسخههای جدید گیت جای کاربرد شاخهای checkout را گرفته و خواناتر است. checkout هنوز کار میکند، اما چند کار متفاوت انجام میدهد و همین آن را گیجکننده میکند.
merge: یکیکردن شاخهها
وقتی کار روی شاخه تمام شد، به main برگردید و آن را merge کنید:
git switch main
git merge feature/login
اگر هر دو شاخه یک خط از یک فایل را عوض کرده باشند، conflict پیش میآید. گیت فایل را با نشانههای <<<<<<<، ======= و >>>>>>> علامت میزند؛ آن را دستی درست کنید، نشانهها را پاک کنید و بعد:
git add path/to/file
git commit
remote، push و pull: کار با گیتهاب
git remote -v # remoteهای تعریفشده
git remote add origin git@github.com:user/repo.git # افزودن remote به مخزنی که با init ساختهاید
git push -u origin main # اولین push و وصلکردن شاخه به origin
git push # pushهای بعدی
git pull # گرفتن و ادغام تغییرات دیگران
git pull در واقع دو کار است: fetch (گرفتن تغییرات) و بعد merge آنها. اگر میخواهید اول ببینید چه چیزی آمده، git fetch بزنید و با git log --oneline main..origin/main آن را مرور کنید.
برای اتصال به گیتهاب با آدرسهای git@github.com:… به کلید SSH نیاز دارید؛ ساختنش را در کلید SSH و اتصال به سرور توضیح دادهایم.
برگرداندن تغییرات، بدون از دست دادن کار
گیت تقریباً هر اشتباهی را قابلجبران میکند، به شرطی که دستور درست را بزنید. این بخش را با دقت بخوانید.
restore: دور ریختن تغییرات یک فایل
git restore index.php # برگرداندن فایل به آخرین commit (تغییرات پاک میشوند)
git restore --staged index.php # بیرون آوردن از staging؛ تغییرات در فایل میمانند
دقت کنید: git restore بدون --staged تغییرات commitنشده را برای همیشه پاک میکند و گیت راهی برای برگرداندنشان ندارد.
reset --soft در برابر reset --hard
فرض کنید commit آخر را زود زدید و میخواهید پیامش را عوض کنید یا فایلی به آن اضافه کنید:
git reset --soft HEAD~1
commit حذف میشود اما همهی تغییراتش در staging باقی میمانند. کاملاً امن است.
اما این یکی را با احتیاط بزنید:
git reset --hard HEAD~1
--hard هم commit را حذف میکند، هم همهی تغییرات commitنشدهی پوشهی کاری را دور میریزد. دو قاعده:
- پیش از
reset --hardیکgit statusبزنید و مطمئن شوید چیزی commitنشده ندارید که لازمش دارید. - روی commitهایی که push کردهاید reset نزنید. تاریخچهی شما با نسخهی دیگران ناسازگار میشود و برای push مجبور به
--forceمیشوید که کار دیگران را پاک میکند.
اگر commitی را با reset از دست دادید، git reflog فهرست جاهایی را که HEAD اخیراً بوده نشان میدهد و معمولاً میشود از آنجا برش گرداند.
revert: راه امن برای commitهای pushشده
revert تاریخچه را پاک نمیکند؛ یک commit تازه میسازد که دقیقاً اثر commit قبلی را خنثی میکند:
git log --oneline
git revert a1b2c3d
git push
روی شاخهی مشترک، این همیشه انتخاب درست است.
stash: کنار گذاشتن موقت کار نیمهتمام
وسط کارید و باید سریع به شاخهی دیگری بروید:
git stash push -m "half-done login form"
git switch main
# ... کار فوری ...
git switch feature/login
git stash pop
git stash list همهی موارد کنارگذاشته را نشان میدهد. stash را انبار بلندمدت نکنید؛ اگر کار بیش از یک روز طول میکشد، یک commit موقت روی شاخهی خودش امنتر است.
فایل gitignore: چه چیزهایی نباید در مخزن برود
فایل .gitignore در ریشهی پروژه به گیت میگوید کدام فایلها را نادیده بگیرد. برای یک پروژهی Laravel نمونهی معقولی این است:
# وابستگیها؛ با composer و npm دوباره ساخته میشوند
/vendor/
/node_modules/
# اطلاعات محرمانه و تنظیمات محلی
.env
.env.*
!.env.example
# خروجیها و فایلهای موقت
/public/build/
/storage/*.key
*.log
# فایلهای ویرایشگر و سیستمعامل
.idea/
.vscode/
.DS_Store
دو نکتهی مهم:
.gitignoreفقط روی فایلهایی اثر دارد که هنوز track نشدهاند. اگر.envقبلاً commit شده، باید باgit rm --cached .envاز مخزن بیرونش بیاورید.- اگر رمز یا کلیدی یک بار commit و push شده، حذفش از commit بعدی کافی نیست؛ در تاریخچه باقی است. آن رمز را عوض کنید.
جدول خلاصهی دستورات گیت
| کار | دستور |
|---|---|
| ساخت مخزن تازه | git init |
| کپی مخزن موجود | git clone <url> |
| دیدن وضعیت | git status |
| افزودن به staging | git add <file> یا git add -p |
| ثبت commit | git commit -m "پیام" |
| تاریخچهی خلاصه | git log --oneline --graph |
| تغییرات addنشده / addشده | git diff / git diff --staged |
| ساخت و رفتن به شاخه | git switch -c <name> |
| رفتن به شاخهی موجود | git switch <name> |
| ادغام شاخه در شاخهی فعلی | git merge <name> |
| فهرست و افزودن remote | git remote -v / git remote add origin <url> |
| فرستادن و گرفتن | git push / git pull |
| دور ریختن تغییرات یک فایل | git restore <file> |
| بیرون آوردن از staging | git restore --staged <file> |
| لغو commit آخر، حفظ تغییرات | git reset --soft HEAD~1 |
| لغو commit و حذف تغییرات (خطرناک) | git reset --hard HEAD~1 |
| خنثیکردن commit pushشده | git revert <hash> |
| کنار گذاشتن و برگرداندن کار | git stash push / git stash pop |
| پیدا کردن commit گمشده | git reflog |
جمعبندی
برای کار روزمره با گیت به دهدوازده دستور بیشتر نیاز ندارید: status، add، commit، log، diff، switch، merge، pull و push. آنچه گیتکار مطمئن را از تازهکار جدا میکند، شناختن راههای برگشت است: restore و reset --soft برای کار محلی، revert برای چیزی که push شده، و احتیاط همیشگی با reset --hard. commitهای کوچک با پیام روشن بزنید، برای هر کار شاخه بسازید و .env را از همان روز اول در .gitignore بگذارید.
اگر تازه سرور گرفتهاید و میخواهید پروژه را از گیت روی آن بیاورید، دستورات ضروری لینوکس برای سرور قدم بعدی خوبی است.