همکاری تیمی – Fork و Pull Request
حالا که با Git محلی و remote راحتیم، میرویم سراغ چیزی که GitHub را خاص میکند: همکاری. در این فصل با Fork، Pull Request، Code Review، Branch Protection و قراردادهای تیمی آشنا میشویم.
حالا که با Git محلی و remote راحتیم، میرویم سراغ چیزی که GitHub را خاص میکند: همکاری. در این فصل با Fork، Pull Request، Code Review، Branch Protection و قراردادهای تیمی آشنا میشویم.
Fork چیست؟
Fork یعنی کپی کردن یک ریپازیتوری دیگران در حساب خودتان. این کپی مستقل است – هر تغییری بدهید، روی اصلی اثر ندارد.
Original Repo Your Fork
(django/django) → (YOU/django)
Linked but independent ─ تغییرات شما فقط در fork شماست
چه زمانی Fork؟
- مشارکت در پروژه open-source که permission ندارید
- سفارشیسازی یک پروژه برای استفاده شخصی
- یادگیری از یک کد بدون آسیب به اصلی
Fork vs Clone
| Fork | Clone |
|---|---|
| کپی در GitHub (روی سرور) | کپی روی کامپیوتر شما |
| نیاز به GitHub | کار روی هر Git host |
| به اصلی متصل (میتوان PR فرستاد) | اتصال خاصی ندارد |
| یک عملیات GitHub | دستور Git |
Fork Workflow
۱. Fork در GitHub
- به ریپو اصلی بروید (مثلاً
github.com/django/django) - روی دکمه Fork در بالا سمت راست کلیک کنید
- حساب خود را انتخاب کنید
- fork ساخته میشود (
github.com/YOU/django)
۲. Clone از Fork خود
git clone git@github.com:YOU/django.git
cd django
# upstream remote - پروژه اصلی
git remote add upstream https://github.com/django/django.git
git remote -v
# origin git@github.com:YOU/django.git (fetch)
# origin git@github.com:YOU/django.git (push)
# upstream https://github.com/django/django.git (fetch)
# upstream https://github.com/django/django.git (push)
۳. ساخت Branch فیچر
git switch main
git pull upstream main # همگام با اصلی
git push origin main # بهروز کردن fork
git switch -c fix/issue-12345
۴. توسعه و Push
code . # ویرایش
git add .
git commit -m "fix: handle null in queryset filter (#12345)"
git push -u origin fix/issue-12345
۵. Pull Request
در GitHub، روی دکمه Compare & pull request کلیک کنید (که خودکار ظاهر میشود).
Pull Request – قلب همکاری
Pull Request (PR) یعنی: “من تغییراتی دارم، لطفاً merge کنید.” این یک پنجره برای بحث، code review و تأیید قبل از ادغام است.
اجزای یک PR خوب
- عنوان: کوتاه، توصیفی، در زمان امری
- توضیحات: چه کاری انجام داده، چرا، چطور تست شده
- Reviewers: افراد مرتبط
- Labels: bug، feature، documentation، …
- Linked Issues:
Closes #123یاFixes #456 - Screenshots (برای تغییرات UI)
قالب PR نمونه
## شرح مشکل
برای نمایش لیست محصولات، query از 50ms کندتر میشد وقتی محصول > 1000.
## راهحل
ایندکس مرکب روی (category_id, created_at DESC) اضافه شد که برای
رایجترین filter استفاده میشود.
## تست
- [x] Unit tests در test_products.py
- [x] Performance benchmark: 50ms → 3ms (16x سریعتر)
- [x] Manual test روی staging
## Related
Closes #234
Refs #189
## Screenshots
(اگر تغییرات UI دارد)
PR Template در ریپو
میتوانید قالب پیشفرض برای همه PRهای ریپو تعریف کنید:
# فایل
.github/pull_request_template.md
# یا چند template
.github/PULL_REQUEST_TEMPLATE/feature.md
.github/PULL_REQUEST_TEMPLATE/bugfix.md
<!-- .github/pull_request_template.md -->
## نوع تغییر
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation
## شرح
(توضیح کاری که انجام دادهاید)
## چکلیست
- [ ] کد lint میشود
- [ ] تستها اضافه/بهروز شده
- [ ] مستندات بهروز شده
- [ ] CHANGELOG.md بهروز شده
## Related Issues
Closes #
Code Review
وقتی کسی PR شما را review میکند:
سطوح review
- Comment: نظر اضافی – merge را block نمیکند
- Approve: تأیید – PR آماده merge
- Request changes: نیاز به تغییر – merge block میشود
انواع کامنت در review
- Inline comment: روی خط خاصی از کد
- Suggestion: پیشنهاد تغییر کد – مولف میتواند یک کلیک accept کند
- Conversation: گفتگو روی یک موضوع
پاسخ به feedback
# تغییرات بر اساس feedback
git add .
git commit -m "fix: address review comments"
git push
# PR خودکار بهروز میشود
# میتوانید کامنتها را resolve کنید
commitها در PR
وقتی PR open است و push میکنید، همه commitها به PR اضافه میشوند. میتوانید قبل از merge، آنها را squash کنید (در فصل ۸).
استراتژیهای Merge در GitHub
GitHub سه روش merge ارائه میدهد:
۱. Create a merge commit (پیشفرض)
main: A ── B ── C ───── M ←── main
╱
D ── E (PR)
یک merge commit ساخته میشود. تاریخچه کامل حفظ میشود اما شلوغ میشود.
۲. Squash and merge
main: A ── B ── C ── F ←── main
(همه commitهای PR به یکی تبدیل شدند)
تاریخچه تمیز – یک commit به ازای هر PR. پیشنهاد برای اکثر تیمها.
۳. Rebase and merge
main: A ── B ── C ── D' ── E' ←── main
(commitها rebase شدند روی main)
تاریخچه خطی، بدون merge commit.
Branch Protection Rules
برای جلوگیری از خرابی main:
- Settings → Branches → Add rule
- Branch name pattern:
main - تنظیمات مهم:
- Require a pull request before merging: نمیتوان مستقیم push کرد
- Require approvals: 2: حداقل 2 نفر تأیید
- Dismiss stale reviews: با push جدید، تأییدها reset شوند
- Require review from CODEOWNERS
- Require status checks: CI تستها قبول شوند
- Require branches to be up to date
- Require signed commits
- Require linear history: فقط squash/rebase merge
- Include administrators: حتی adminها هم تابع باشند
- Restrict who can push
CODEOWNERS
فایلی که میگوید برای تغییرات هر بخش، چه کسی review کند:
# .github/CODEOWNERS
# مالکیت پیشفرض - هر فایل
* @lead-developer
# فقط فایلهای backend
*.py @backend-team
# مسیر خاص
/frontend/ @frontend-team
/docs/ @tech-writers
# چندین reviewer
/security/ @security-team @lead-developer
# با ایمیل
/payments/ payments@example.com
وقتی PR فایلهای مرتبط را تغییر دهد، GitHub خودکار CODEOWNERها را بهعنوان reviewer اضافه میکند.
Draft Pull Request
وقتی هنوز کار تمام نشده اما میخواهید feedback اولیه بگیرید:
- هنگام ساخت PR، روی فلش پایین Create pull request کلیک کنید
- Create draft pull request را انتخاب کنید
این PR قابل merge نیست تا وقتی Ready for review کنید.
حل Conflict در PR
وقتی main تغییر کرده و PR شما با آن تعارض دارد:
روش ۱: در GitHub (برای conflict ساده)
اگر conflict ساده باشد، GitHub دکمه Resolve conflicts نشان میدهد. مستقیم در browser ویرایش کنید.
روش ۲: محلی (برای conflict پیچیده)
git switch feature/my-feature
git fetch origin
git merge origin/main
# حل conflict
nano file.py
git add file.py
git commit
git push
روش ۳: Rebase (تاریخچه تمیزتر)
git switch feature/my-feature
git fetch origin
git rebase origin/main
# اگر conflict شد:
nano file.py
git add file.py
git rebase --continue
git push --force-with-lease # rebase تاریخچه را عوض کرده
بستن PR بدون merge
گاهی PR را نمیخواهید merge کنید (شاید راهحل بهتری پیدا کردید):
- به PR بروید
- پایین صفحه: Close pull request
- اگر بعداً پشیمان شدید: Reopen pull request
Auto-merge
برای PRهایی که در انتظار CI هستند، میتوانید auto-merge فعال کنید – وقتی همه چیز سبز شد، خودکار merge میشود:
- روی Enable auto-merge کلیک کنید
- روش merge را انتخاب کنید
- وقتی همه requirements برآورده شد، خودکار merge میشود
CONTRIBUTING.md
راهنمای مشارکت در پروژه:
# CONTRIBUTING.md
## نحوه مشارکت
1. Fork ریپو
2. Clone fork خود
3. branch جدید بسازید: `git switch -c feature/your-feature`
4. تغییرات را commit کنید با Conventional Commits
5. تستها را اجرا کنید: `pytest`
6. Push کنید
7. Pull Request باز کنید
## استایل کد
- Python: black + flake8
- JS: prettier + eslint
- خط حداکثر: 100 کاراکتر
## تستها
تستهای جدید الزامی برای فیچرهای جدید.
```bash
pytest tests/
```
## گزارش باگ
Issue باز کنید با template "Bug Report".
بهترین شیوههای Review
بهعنوان مولف
- PRهای کوچک (< 400 خط) – راحتتر review میشود
- توضیح کامل در body
- Self-review قبل از درخواست
- پاسخ سریع به کامنتها
- تشکر از reviewer
بهعنوان Reviewer
- طی ۲۴ ساعت review کنید
- کامنتهای دوستانه و سازنده
- اگر احتیاج به تغییر دارد، دلیل را توضیح دهید
- “nit:” برای کامنتهای کوچک اختیاری
- کد را اجرا کنید (نه فقط نگاه کنید)
- به منطق فکر کنید نه فقط syntax
زبان review
❌ "این کد بد است"
✅ "این میتواند خواناتر شود اگر متغیر را به نام پیشنهادی X تغییر دهیم"
❌ "اشتباه است"
✅ "آیا این edge case در نظر گرفته شده؟ مثلاً وقتی list خالی است"
❌ "همش را عوض کن"
✅ "میتوانیم این بخش را به یک تابع جدا منتقل کنیم؟ - فکر میکنم برای استفاده مجدد مفید باشد"
مثال کامل: مشارکت در یک پروژه open-source
# 1. Fork در GitHub (دکمه Fork)
# 2. Clone fork خود
git clone git@github.com:YOU/awesome-project.git
cd awesome-project
# 3. اضافه کردن upstream
git remote add upstream https://github.com/original/awesome-project.git
# 4. همگام با upstream
git fetch upstream
git switch main
git merge upstream/main
# 5. ساخت branch
git switch -c fix/typo-in-readme
# 6. تغییرات
sed -i 's/Wlecome/Welcome/' README.md
git add README.md
git commit -m "docs: fix typo in README"
# 7. Push
git push -u origin fix/typo-in-readme
# 8. در GitHub: Compare & pull request
# Title: docs: fix typo in README
# Description: Fixed "Wlecome" → "Welcome" in line 5
# Submit
# 9. منتظر review، اعمال feedback، تشکر
# 10. وقتی merge شد: حذف branch محلی
git switch main
git pull upstream main
git branch -d fix/typo-in-readme
بهترین شیوهها
- هر PR یک هدف مشخص – نه چند چیز در یک PR
- PRهای کوچک: راحتتر review
- قبل از open کردن PR، کد را خودتان review کنید
- CI/lint قبل از push
- پاسخ سریع به کامنتها
- “Resolve conversation” بعد از حل کامنت
- main را protected نگه دارید
- CODEOWNERS برای پروژههای بزرگ
- CONTRIBUTING.md و PR template
جمعبندی
- Fork: کپی ریپو در حساب خود
- Pull Request: درخواست merge با code review
- سه استراتژی merge: merge commit، squash، rebase
- Branch protection برای امنیت main
- CODEOWNERS برای review خودکار
- Draft PR برای WIP
- Auto-merge بعد از قبول CI
- CONTRIBUTING.md راهنمای مشارکت
در فصل بعد، اشتباهات Git و راههای اصلاح آنها را یاد میگیریم: reset، revert، reflog و cherry-pick.