~/icsd.ir — bash
SYSTEM_ONLINE

همکاری تیمی – 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

  1. به ریپو اصلی بروید (مثلاً github.com/django/django)
  2. روی دکمه Fork در بالا سمت راست کلیک کنید
  3. حساب خود را انتخاب کنید
  4. 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:

  1. Settings → Branches → Add rule
  2. Branch name pattern: main
  3. تنظیمات مهم:
  • 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 اولیه بگیرید:

  1. هنگام ساخت PR، روی فلش پایین Create pull request کلیک کنید
  2. 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 کنید (شاید راه‌حل بهتری پیدا کردید):

  1. به PR بروید
  2. پایین صفحه: Close pull request
  3. اگر بعداً پشیمان شدید: Reopen pull request

Auto-merge

برای PR‌هایی که در انتظار CI هستند، می‌توانید auto-merge فعال کنید – وقتی همه چیز سبز شد، خودکار merge می‌شود:

  1. روی Enable auto-merge کلیک کنید
  2. روش merge را انتخاب کنید
  3. وقتی همه 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.

نمایش سایت

رنگ سایت
حالت نمایش
اندازهٔ متن
خوانایی

این تنظیمات فقط روی مرورگر شما ذخیره می‌شود.