کتاب جامع Git & GitHub
v1.0 · 1405 · Persian Edition

کتاب جامع Git و GitHub

از مبانی تا موضوعات پیشرفته — یک مرجع کامل برای توسعه‌دهندگان

A-Talebifard
A-Talebifard
Full-Stack Engineer; WebGIS Developer; GeoAI Specialist
Chapter 01

تاریخچه Git #

داستان Git با هسته‌ی لینوکس شروع شد. لینوس توروالدز در سال ۲۰۰۲ تصمیم گرفت پروژه‌ی لینوکس را به BitKeeper بسپارد — یک سیستم کنترل نسخه‌ی تجاری که مالک آن، Larry McVoy، اجازه استفاده رایگان را به پروژه‌های متن‌باز داده بود. این تصمیم در ابتدا کارآمد بود، اما در سال ۲۰۰۵ پس از اینکه برخی توسعه‌دهندگان لینوکس مهندسی معکوسِ پروتکل BitKeeper را انجام دادند، McVoy لیسانس رایگان را لغو کرد. این اتفاق، جامعه‌ی لینوکس را در موقعیتی سخت قرار داد.

لینوس توروالدس در آوریل ۲۰۰۵ شروع به نوشتن سیستمی جدید کرد. هدف او سه چیز بود: سرعت بالا، طراحی توزیع‌شده، و پشتیبانی قوی از شاخه‌ها (branches). پس از تنها ده روز، نسخه اولیه آماده شد. در ژوئیه ۲۰۰۵، مدیریت پروژه به Junio Hamano واگذار شد که تا امروز maintainer اصلی Git است. نام «Git» در زبان بریتانیایی عامیانه به معنی «آدم خنگ» است — انتخابی طنزآمیز از سوی توروالدز.

timeline title Evolution of Git section 2002 - BitKeeper Era Linux kernel uses BitKeeper : Free license for OSS section 2005 - Birth of Git Apr 2005 : License revoked Apr 2005 : Linus starts Git Jul 2005 : Junio Hamano takes over section 2007-2010 - Adoption 2007 : GitHub founded 2008 : GitHub goes public 2010 : Major OSS migration section 2018+ - Dominance 2018 : Microsoft acquires GitHub 2020 : 100M+ developers 2024 : AI-powered workflows
// Timeline: From BitKeeper to AI-powered Git workflows

چرا Git برنده شد؟

Git برنده شد زیرا سه مشکل اصلی سیستم‌های قبلی را حل کرد: سرعت کار با پروژه‌های بزرگ (هسته لینوکس ده‌ها هزار فایل دارد)، توزیع‌شده بودن (هر کلون یک نسخه کامل از تاریخچه است) و شاخه‌های ارزان (ساختن شاخه در Git تقریباً هیچ هزینه‌ای ندارد). این ویژگی‌ها به همراه ظهور GitHub در سال ۲۰۰۸، Git را به استاندارد جهانی کنترل نسخه تبدیل کرد.

ℹ️ اطلاعات کلیدی

Git طوری طراحی شده که «آرزوی واقعی‌ترین داده‌ها در تاریخچه است» — یعنی هیچ commit ای واقعاً از بین نمی‌رود تا زمانی که reflog آن را نگه دارد (پیش‌فرض: ۹۰ روز). این موضوع، امنیت بالایی به توسعه‌دهندگان می‌دهد.

Chapter 02

مقایسه با VCSهای دیگر #

سیستم‌های کنترل نسخه به دو دسته اصلی تقسیم می‌شوند: متمرکز (Centralized) و توزیع‌شده (Distributed). SVN، CVS و Perforce نمونه‌های متمرکز هستند که در آن‌ها یک سرور مرکزی همه چیز را نگه می‌دارد و کلاینت‌ها فقط نسخه‌های اخیر را دارند. در مقابل، Git، Mercurial و Bazaar توزیع‌شده‌اند: هر کلون، تاریخچه‌ی کامل پروژه را در خود دارد.

graph TB subgraph Centralized["Centralized VCS (e.g. SVN)"] S1["Central Server
(Full History)"] C1["Client A
(Working Copy)"] C2["Client B
(Working Copy)"] C3["Client C
(Working Copy)"] S1 <--> C1 S1 <--> C2 S1 <--> C3 end
// Centralized: Single point of failure, requires constant network
graph TB subgraph Distributed["Distributed VCS (e.g. Git)"] R1["Remote Server
(GitHub/GitLab)"] L1["Local Repo A
(Full History)"] L2["Local Repo B
(Full History)"] L3["Local Repo C
(Full History)"] L1 <-->|push/pull| R1 L2 <-->|push/pull| R1 L3 <-->|push/pull| R1 L1 <-.->|direct peer| L2 end
// Distributed: Every clone is a full backup, works offline

جدول مقایسه

ویژگی Git SVN Mercurial Perforce
مدلDistributedCentralizedDistributedCentralized
آفلاین کار می‌کندبلهخیربلهخیر
سرعت branchآنیکندآنیکند
ذخیره‌سازیSnapshotDeltaSnapshotDelta
اندازه repoکوچکمتوسطکوچکمتوسط
یادگیریسختآسانمتوسطسخت
بازار فعلی~۹۰٪کمکمنیچ
✅ نکته عملی

اگرچه Git توزیع‌شده است، اما در عمل معمولاً یک «مبدأ حقیقت» (origin remote) روی GitHub/GitLab داریم. توزیع‌شده بودن به معنای استقلال در کار آفلاین و نداشتن نقطه شکست واحد (single point of failure) است.

Chapter 03

مبانی Git #

برای درک Git، باید سه منطقه‌ی اصلی آن را بشناسید: Working Directory (دایرکتوری کاری)، Staging Area (Index) و Repository. هر فایل در هر لحظه یکی از این چهار وضعیت را دارد: Untracked، Modified، Staged یا Committed. درک این چرخه، پایه‌ی همه کارهای بعدی است.

stateDiagram-v2 [*] --> Untracked : new file Untracked --> Staged : git add Staged --> Modified : edit file Modified --> Staged : git add Staged --> Committed : git commit Committed --> Modified : edit file Committed --> [*] : git rm note right of Staged : Snapshot ready
for commit note right of Committed : Saved in
local history
// File lifecycle: 4 states that every file cycles through

سه منطقه اصلی

flowchart LR WD["Working Directory
(Files on disk)"] -->|git add| SA["Staging Area
(Index)"] SA -->|git commit| LR["Local Repository
(.git folder)"] LR -->|git push| RR["Remote Repository
(GitHub)"] RR -->|git fetch/pull| LR LR -->|git checkout| WD style WD fill:#f38ba8,stroke:#1e1e2e,color:#1e1e2e style SA fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style LR fill:#a6e3a1,stroke:#1e1e2e,color:#1e1e2e style RR fill:#89b4fa,stroke:#1e1e2e,color:#1e1e2e
// Three areas + remote: data flows in both directions

وضعیت‌های فایل

  • Untracked — فایل جدیدی که Git هنوز آن را track نمی‌کند.
  • Modified — فایل tracked که تغییر کرده اما هنوز stage نشده.
  • Staged — فایل تغییر کرده و برای commit بعدی آماده است.
  • Committed — تغییرات به صورت دائمی در تاریخچه ذخیره شده.
💡 نکته مفهومی

برخلاف SVN که تفاوت‌ها (delta) را ذخیره می‌کند، Git snapshot می‌گیرد. یعنی هر commit، عکس کامل از وضعیت همه فایل‌ها در آن لحظه است. برای فایل‌های تغییر نکرده، فقط یک لینک به snapshot قبلی ذخیره می‌شود. این مدل، عملیات branch و merge را بسیار سریع می‌کند.

Chapter 04

نصب و تنظیم اولیه #

نصب Git روی هر سه سیستم‌عامل اصلی ساده است. پس از نصب، مهم‌ترین قدم، تنظیم نام و ایمیل است؛ زیرا این مقادیر در هر commit ذخیره می‌شوند و تاریخچه‌ی شما را در پروژه‌های متن‌باز شناسایی می‌کنند. در این فصل، نصب روی هر سه پلتفرم، تنظیمات سراسری، و راه‌اندازی SSH برای اتصال امن به GitHub را پوشش می‌دهیم.

نصب روی Windows

ساده‌ترین روش، دانلود «Git for Windows» از سایت رسمی است که شامل Git Bash، یک شبیه‌ساز ترمینال لینوکس، و Git GUI می‌شود. هنگام نصب، گزینه «Use Git from the Windows Command Prompt» را انتخاب کنید تا دستورات Git در PowerShell و CMD هم در دسترس باشند.

powershell
# Download via winget (Windows Package Manager)
winget install --id Git.Git -e --source winget

# Verify installation
git --version
# Output: git version 2.45.0.windows.1

# Optional: install GitHub CLI
winget install --id GitHub.cli
gh auth login

نصب روی macOS

روی مک، ساده‌ترین روش استفاده از Homebrew است. اگر Homebrew نصب نیست، ابتدا آن را از brew.sh نصب کنید. جایگزین، نصب Xcode Command Line Tools است که Git را به همراه می‌آورد.

bash
# Option A: via Homebrew (recommended)
brew install git

# Option B: via Xcode Command Line Tools
xcode-select --install

# Verify
git --version
# Output: git version 2.45.0

نصب روی Linux

bash
# Debian / Ubuntu
sudo apt update && sudo apt install git -y

# Fedora / RHEL
sudo dnf install git -y

# Arch Linux
sudo pacman -S git

# Verify
git --version

تنظیمات اولیه (مهم!)

پس از نصب، باید نام و ایمیل خود را تنظیم کنید. این اطلاعات در metadata هر commit ذخیره می‌شوند و در GitHub برای شناسایی مشارکت‌های شما استفاده می‌شوند. مطمئن شوید ایمیل، همان ایمیل اکانت GitHub شما باشد.

bash
# Set global identity (used for every commit)
git config --global user.name "Abbas Talebifard"
git config --global user.email "abbas@example.com"

# Set default branch name (modern convention)
git config --global init.defaultBranch main

# Set preferred editor
git config --global core.editor "code --wait"        # VS Code
# git config --global core.editor "vim"              # Vim
# git config --global core.editor "nano"             # Nano

# Enable colored output
git config --global color.ui auto

# Set default pull behavior (rebase instead of merge)
git config --global pull.rebase true

# Configure line endings (cross-platform)
# Windows:
git config --global core.autocrlf true
# macOS/Linux:
git config --global core.autocrlf input

# View all settings
git config --list
git config --global --list

# Edit global config file directly
git config --global --edit

راه‌اندازی SSH برای GitHub

SSH Keys اجازه می‌دهند بدون وارد کردن پسورد در هر push/pull، با GitHub ارتباط امن برقرار کنید. این روش ایمن‌تر از HTTPS با Personal Access Token است و برای کار روزمره توصیه می‌شود.

bash
# Step 1: Generate a new SSH key (Ed25519 - modern & secure)
ssh-keygen -t ed25519 -C "abbas@example.com"
# Press Enter to accept default path (~/.ssh/id_ed25519)
# Set a passphrase (optional but recommended)

# Step 2: Start ssh-agent in background
eval "$(ssh-agent -s)"

# Step 3: Add private key to ssh-agent
ssh-add ~/.ssh/id_ed25519

# Step 4: Copy public key to clipboard
cat ~/.ssh/id_ed25519.pub
# macOS: pbcopy < ~/.ssh/id_ed25519.pub
# Windows: clip < ~/.ssh/id_ed25519.pub
# Linux: xclip -sel clip < ~/.ssh/id_ed25519.pub

# Step 5: Add key to GitHub → Settings → SSH and GPG keys → New SSH key

# Step 6: Test connection
ssh -T git@github.com
# Output: Hi A-talebifard! You've successfully authenticated...
⚠️ هشدار امنیتی

هرگز کلید خصوصی (id_ed25519 بدون .pub) را با کسی به اشتراک نگذارید یا در repo قرار ندهید. فقط کلید عمومی (.pub) به GitHub اضافه می‌شود.

ساخت اولین Repository

bash
# Create a new directory and initialize git
mkdir my-first-repo
cd my-first-repo
git init

# Create a README file
echo "# My First Repo" > README.md

# Check status (file is untracked)
git status

# Stage the file
git add README.md

# Commit with a message
git commit -m "Initial commit: add README"

# View commit history
git log --oneline

# Connect to GitHub (create empty repo on GitHub first)
git remote add origin git@github.com:A-talebifard/my-first-repo.git
git branch -M main
git push -u origin main
Chapter 05

دستورات پایه Git #

این فصل، دستورات روزمره‌ی Git را پوشش می‌دهد؛ دستوراتی که در هر ساعت کار با Git از آن‌ها استفاده می‌کنید. درک عمیق این دستورات، پایه‌ی همه کارهای پیچیده‌تر است. هر دستور با مثال عملی و توضیح خروجی نشان داده شده است.

git init — ساخت repository جدید

این دستور یک پوشه‌ی مخفی .git در دایرکتوری فعلی می‌سازد که تمام تاریخچه، تنظیمات و اشیای Git در آن ذخیره می‌شوند. دو حالت دارد: ساخت repo جدید در دایرکتوری موجود، یا clone از remote.

bash
# Initialize a new git repo in current directory
mkdir my-project && cd my-project
git init
# Output: Initialized empty Git repository in /path/.git/

# Initialize with a specific default branch
git init -b main

# Initialize a bare repo (for servers, no working dir)
git init --bare my-project.git

# Clone an existing remote repository
git clone https://github.com/A-talebifard/my-project.git
git clone git@github.com:A-talebifard/my-project.git   # via SSH

# Clone into a specific directory
git clone git@github.com:A-talebifard/my-project.git my-folder

# Clone only the latest commit (shallow, saves bandwidth)
git clone --depth 1 git@github.com:A-talebifard/my-project.git

git add — staging تغییرات

دستور add تغییرات را از Working Directory به Staging Area منتقل می‌کند. این یک «دو مرحله‌ای» بودن Git است که به شما اجازه می‌دهد قبل از commit، دقیقاً انتخاب کنید چه چیزی در commit قرار گیرد.

bash
# Stage a single file
git add README.md

# Stage multiple files
git add file1.txt file2.txt file3.txt

# Stage all changes in current directory (recursive)
git add .
git add --all          # stages deletions too
git add -A             # same as --all

# Stage all .js files
git add "*.js"

# Stage interactively (patch mode - choose hunks)
git add -p
# For each changed hunk, choose: y (yes), n (no), s (split), q (quit)

# Stage a specific directory
git add src/components/

# Stage based on modification type
git add -u             # only modified/deleted, not new files

git commit — ثبت تغییرات

هر commit یک snapshot از وضعیت staged است. پیام commit اهمیت زیادی دارد: باید کوتاه، توصیفی و در زمان حال باشد. استاندارد Conventional Commits برای پروژه‌های حرفه‌ای توصیه می‌شود.

bash
# Basic commit with message
git commit -m "Add user authentication"

# Multi-line commit message (title + body)
git commit -m "Add user authentication

- Implement JWT-based login flow
- Add /api/auth/login and /api/auth/register
- Add password hashing with bcrypt
- Add tests for auth middleware"

# Stage all tracked modifications and commit in one step
git commit -am "Update README"

# Amend the last commit (add changes or fix message)
git commit --amend -m "New message"
git commit --amend --no-edit    # keep message, add changes

# Empty commit (useful for CI triggers)
git commit --allow-empty -m "Trigger CI"

# Sign commit with GPG key
git commit -S -m "Signed commit"

# Conventional Commits format
# <type>(<scope>): <description>
git commit -m "feat(auth): add OAuth2 login support"
git commit -m "fix(api): handle null user in /profile"
git commit -m "docs: update installation guide"
git commit -m "refactor: simplify token validation"
git commit -m "test: add unit tests for user model"
git commit -m "chore: bump dependencies"
✅ Conventional Commits

پنج نوع اصلی: feat (قابلیت جدید)، fix (رفع باگ)، docs (مستندات)، refactor (بازنویسی بدون تغییر رفتار)، test (تست)، chore (کارهای نگهداری). این استاندارد، تولید CHANGELOG خودکار و semantic versioning را ممکن می‌کند.

git status — مشاهده وضعیت

bash
# Show working tree status
git status

# Short format (compact)
git status -s
# Output:
#  M modified-file.txt       (modified, not staged)
# M  staged-file.txt         (staged)
# A  new-staged-file.txt     (added & staged)
# ?? untracked-file.txt      (untracked)

# Show branch info
git status -b

# Show ignored files too
git status --ignored

git log — تاریخچه commits

bash
# Show commit history
git log

# One-line compact format
git log --oneline
# Output:
# a1b2c3d (HEAD -> main, origin/main) Add user auth
# d4e5f6g Update README
# 7h8i9j0 Initial commit

# Graph view with branches
git log --oneline --graph --all --decorate

# Show last N commits
git log -5

# Show commits by a specific author
git log --author="Abbas"

# Show commits since a date
git log --since="2 weeks ago"
git log --since="2024-01-01"

# Show commits for a specific file
git log -- path/to/file.txt

# Show diff for each commit
git log -p

# Show stats per commit
git log --stat

# Show commits in a date range
git log --after="2024-01-01" --before="2024-06-01"

# Search commits by message (regex)
git log --grep="auth"

# Custom format
git log --pretty=format:"%h - %an, %ar : %s"

git diff — مشاهده تفاوت‌ها

bash
# Diff working dir vs staging area (unstaged changes)
git diff

# Diff staging area vs last commit (staged changes)
git diff --staged
git diff --cached     # same as --staged

# Diff working dir vs last commit (all changes)
git diff HEAD

# Diff between two commits
git diff a1b2c3d d4e5f6g

# Diff between two branches
git diff main feature/login

# Diff for a specific file
git diff path/to/file.txt

# Show only file names that changed
git diff --name-only

# Show stats (insertions/deletions)
git diff --stat

# Word-level diff (better for prose)
git diff --word-diff

git remote — مدیریت remoteها

bash
# List remote repositories
git remote -v
# origin  git@github.com:A-talebifard/repo.git (fetch)
# origin  git@github.com:A-talebifard/repo.git (push)

# Add a remote
git remote add origin git@github.com:A-talebifard/repo.git

# Add upstream (for forks)
git remote add upstream git@github.com:original-owner/repo.git

# Change remote URL (e.g., from HTTPS to SSH)
git remote set-url origin git@github.com:A-talebifard/repo.git

# Rename a remote
git remote rename origin github

# Remove a remote
git remote remove origin

# Show details of a remote
git remote show origin

git push و git pull — همگام‌سازی با remote

bash
# Push current branch to origin, set upstream tracking
git push -u origin main
# -u is shorthand for --set-upstream

# After first push, just:
git push
git push origin main

# Force push (DANGEROUS - rewrites remote history)
git push --force-with-lease     # safer than --force
git push -f                     # use only on personal branches!

# Push all branches
git push --all

# Push tags
git push --tags
git push origin v1.0.0

# Delete a remote branch
git push origin --delete feature/old-branch

# Pull = fetch + merge
git pull
git pull origin main

# Pull with rebase (cleaner history)
git pull --rebase origin main

# Fetch without merging (safer)
git fetch origin
git fetch --all --prune
🚨 خطر force push

هرگز git push --force روی شاخه‌های اشتراکی (main، develop) انجام ندهید. این کار تاریخچه‌ی remote را بازنویسی می‌کند و commitهای همکاران را از بین می‌برد. همیشه از --force-with-lease استفاده کنید که در صورت وجود commitهای جدید روی remote، عملیات را متوقف می‌کند.

Chapter 06

مفاهیم داخلی: Objects و Hashes #

برای تسلط واقعی بر Git، باید بدانید درون پوشه‌ی .git چه می‌گذرد. Git یک پایگاه داده کلید-مقدار است که اشیای مختلفی را با هش SHA-1 (یا SHA-256 در نسخه‌های جدید) ذخیره می‌کند. درک این مفاهیم، حل مشکلات پیچیده و استفاده از ابزارهای پیشرفته را آسان می‌کند.

چهار نوع object در Git

نوعتوضیحمحتوای ذخیره شده
blobمحتوای یک فایلمحتوای باینری فایل (بدون نام)
treeیک دایرکتوریلیست blobs و trees با نام و حالت
commitیک snapshottree، parent(s)، author، message
tagتگ annotatedcommit، tagger، message
graph TB C["Commit Object
SHA: a1b2c3d"] T["Tree Object
(root)
SHA: e5f6g7h"] B1["Blob: README.md
SHA: i9j0k1l"] B2["Blob: package.json
SHA: m3n4o5p"] T2["Tree: src/
SHA: q7r8s9t"] B3["Blob: src/index.js
SHA: u1v2w3x"] C -->|points to| T C -->|parent| C2["Parent Commit
SHA: y4z5a6b"] T -->|entry| B1 T -->|entry| B2 T -->|entry| T2 T2 -->|entry| B3 style C fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e style T fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e style T2 fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e style B1 fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style B2 fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style B3 fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style C2 fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e
// Object graph: commit → tree → blobs/subtrees

کاوش اشیای داخلی

bash
# Look inside the .git directory
ls -la .git/
# HEAD  config  description  hooks/  info/  objects/  refs/

# View the HEAD pointer
cat .git/HEAD
# Output: ref: refs/heads/main

# View the type of any object by SHA
git cat-file -t a1b2c3d
# Output: commit

# View the content of an object (raw)
git cat-file -p a1b2c3d
# Output:
# tree e5f6g7h...
# parent y4z5a6b...
# author Abbas <abbas@example.com> 1700000000 +0330
# committer Abbas <abbas@example.com> 1700000000 +0330
#
# Add user authentication

# Hash a file without storing it (see what hash it WOULD get)
git hash-object README.md
# Output: i9j0k1l...

# Write a file to git object database
git hash-object -w README.md

# List all objects in the database
git rev-list --all --objects | head -20

# View tree contents
git ls-tree HEAD
git ls-tree HEAD src/

# Show commit details
git show a1b2c3d

Refs — اشاره‌گرها به commits

Refs نام‌های قابل خواندن برای انسان هستند که به SHA-1 commits اشاره می‌کنند. این‌ها در پوشه‌ی .git/refs ذخیره می‌شوند.

bash
# View all refs
git show-ref

# Local branches
ls .git/refs/heads/
cat .git/refs/heads/main
# Output: a1b2c3d... (SHA of latest commit on main)

# Remote branches
ls .git/refs/remotes/origin/

# Tags
ls .git/refs/tags/

# HEAD points to current branch
cat .git/HEAD
# ref: refs/heads/main

# Special refs
# ORIG_HEAD  - previous HEAD (after reset/merge)
# MERGE_HEAD - commit being merged in
# FETCH_HEAD - result of last fetch

# Symbolic ref (HEAD points to a branch)
git symbolic-ref HEAD
# refs/heads/main

# Detached HEAD (HEAD points to a commit directly)
git checkout a1b2c3d
git symbolic-ref HEAD
# fatal: ref HEAD is not a symbolic ref

git reflog — تاریخچه پنهان

Reflog یکی از قدرتمندترین ویژگی‌های Git است. هر بار که HEAD حرکت می‌کند (commit، checkout، reset، rebase)، یک ورودی در reflog ذخیره می‌شود. این تاریخچه محلی است و در repo به اشتراک گذاشته نمی‌شود، اما برای بازیابی commitهای «گم‌شده» بی‌نظیر است.

bash
# View reflog for HEAD
git reflog
# Output:
# a1b2c3d HEAD@{0}: commit: Add feature X
# y4z5a6b HEAD@{1}: checkout: moving from feature to main
# 7h8i9j0 HEAD@{2}: reset: moving to HEAD~1
# k1l2m3n HEAD@{3}: commit: Important work (was "lost")

# View reflog for a specific branch
git reflog show feature/login

# Recover a "lost" commit
git reset --hard k1l2m3n   # go back to that commit

# Expire old reflog entries (cleanup)
git reflog expire --expire=90.days --all

# Garbage collect (permanently remove unreachable objects)
git gc --prune=now
✅ نجات‌بخش

اگر تا حالا فکر کرده‌اید «یک commit را گم کردم»، اصلاً نگران نباشید. تا ۹۰ روز (پیش‌فرض)، آن commit در reflog وجود دارد و با git reflog و سپس git reset --hard <sha> قابل بازیابی است. این یکی از بزرگترین مزایای Git نسبت به VCSهای دیگر است.

سه حاله‌ی فایل‌ها در .git

  • Loose objects — هر object به صورت فشرده‌شده در یک فایل جدا در .git/objects/ab/cdef... ذخیره می‌شود.
  • Packed objects — هنگام git gc، اشیای پراکنده در یک فایل .pack فشرده می‌شوند تا فضای کمتری بگیرند.
  • Deltas — اشیای مشابه به صورت تفاوت با یک base object ذخیره می‌شوند (بدون تغییر در منطق کاربر).
Chapter 07

Branching (شاخه‌بندی) #

Branching یکی از قدرتمندترین ویژگی‌های Git است. در Git، یک branch فقط یک pointer سبک به یک commit است؛ برخلاف SVN که کل کپی فایل‌ها را کپی می‌کرد. این یعنی ساختن، جابه‌جایی و حذف branch در Git آنی و تقریباً بدون هزینه است. این موضوع، مدل توسعه‌ای که در آن هر قابلیت جدید روی یک branch جدا توسعه می‌یابد، را عملی می‌کند.

gitGraph commit id: "Initial" commit id: "Setup DB" branch feature/login checkout feature/login commit id: "Add form" commit id: "Add validation" checkout main commit id: "Update docs" merge feature/login commit id: "Release v1"
// Branch lifecycle: create → develop → merge → continue

دستورات پایه‌ی Branch

bash
# List all local branches
git branch
# * main
#   feature/login
#   feature/signup

# List all branches (local + remote)
git branch -a

# List branches with last commit info
git branch -v

# List merged branches (into current)
git branch --merged

# List unmerged branches
git branch --no-merged

# Create a new branch (stay on current)
git branch feature/login

# Create and switch in one step
git switch -c feature/login
git checkout -b feature/login    # older syntax

# Switch to an existing branch
git switch main
git checkout main                # older syntax

# Switch to previous branch
git switch -
git checkout -                   # older syntax

# Rename current branch
git branch -m new-name

# Rename another branch
git branch -m old-name new-name

# Delete a fully-merged branch (safe)
git branch -d feature/login

# Force delete a branch (even if not merged)
git branch -D feature/login

# Delete a remote branch
git push origin --delete feature/login

# Track a remote branch
git switch -c feature/login --track origin/feature/login
git checkout -b feature/login origin/feature/login

# Push a new branch to remote and set upstream
git push -u origin feature/login

Merge — ادغام شاخه‌ها

Merge، تغییرات یک branch را به branch فعلی وارد می‌کند. دو نوع اصلی دارد: Fast-forward و Three-way merge.

graph LR subgraph FF["Fast-forward Merge"] A1["C1"] --> A2["C2"] --> A3["C3
(main)"] A3 -.->|fast-forward| A4["C4
(feature)"] end subgraph TW["Three-way Merge"] B1["C1"] --> B2["C2 (main)"] B1 --> B3["C3 (feature)"] B2 --> B4["C4 (main, new)"] B3 --> B4 B4 -.->|merge commit| B5["M1"] end style A4 fill:#a6e3a1,stroke:#1e1e2e,color:#1e1e2e style B5 fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e
// Two merge strategies: fast-forward (linear) vs three-way (merge commit)
bash
# Switch to target branch (e.g., main)
git switch main

# Merge feature branch into main
git merge feature/login

# Fast-forward merge (default when possible)
# If main hasn't changed since branch was created,
# Git just moves the main pointer forward

# Three-way merge (when both branches have new commits)
# Git creates a merge commit with two parents

# Disable fast-forward (always create merge commit)
git merge --no-ff feature/login

# Force fast-forward (fail if not possible)
git merge --ff-only feature/login

# Merge with a message
git merge -m "Merge feature/login into main" feature/login

# Squash merge (combine all commits into one)
git merge --squash feature/login
git commit -m "Add login feature (squashed)"

# Abort a merge in progress
git merge --abort

# Check if a branch is merged
git branch --merged | grep feature/login
✅ چه زمانی کدام؟

Fast-forward: زمانی که main ثابت بوده — تاریخچه خطی تمیز می‌سازد. --no-ff: زمانی که می‌خواهید نشان دهید یک feature در یک بازه زمانی توسعه یافته — مرز واضح بین featureها. Squash: وقتی feature branch دارای commitهای «WIP» یا نامرتب است و می‌خواهید تاریخچه‌ی main تمیز بماند.

عملیات‌های پیشرفته روی Branch

bash
# Show branches that contain a specific commit
git branch --contains a1b2c3d

# Show remote branches that contain a commit
git branch -r --contains a1b2c3d

# Compare branches
git log main..feature/login        # commits in feature, not in main
git log feature/login..main        # commits in main, not in feature
git log --left-right main...feature/login  # both, with markers

# Show diff between branch tips
git diff main feature/login

# Cherry-pick a single commit from another branch
git cherry-pick a1b2c3d

# Move a branch to a different commit
git branch -f feature/login a1b2c3d

# Create a branch from a specific commit
git branch hotfix a1b2c3d

# List branches sorted by last commit date
git for-each-ref --sort=-committerdate refs/heads/ \
  --format='%(committerdate:short) %(refname:short)'
Chapter 08

Rebase در برابر Merge #

یکی از مهم‌ترین تصمیمات در کار با Git، انتخاب بین merge و rebase برای یکپارچه‌سازی تغییرات است. هر دو به یک نتیجه‌ی نهایی مشابه می‌رسند (تغییرات دو branch با هم ترکیب می‌شوند)، اما تاریخچه‌ی متفاوتی تولید می‌کنند. درک این تفاوت، کلید داشتن تاریخچه‌ی تمیز و قابل فهم است.

graph TB subgraph Before["Before Integration"] direction LR M1["main: A → B → C"] F1["feature: A → B → D → E"] end subgraph AfterM["After Merge"] direction LR M2["main: A → B → C → M"] F2["feature: A → B → D → E → M"] end subgraph AfterR["After Rebase"] direction LR M3["main: A → B → C"] F3["feature: A → B → C → D' → E'"] end style M fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e style M2 fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e style M3 fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e
// Merge preserves history; rebase rewrites it linearly

git merge — حفظ تاریخچه

Merge یک commit جدید (merge commit) می‌سازد که دو والد دارد. تاریخچه واقعی preserved می‌شود: می‌توانید ببینید چه زمانی یک branch شروع شد، چه زمانی به هم پیوست و چه کسی این کار را کرد. این روش برای branchهای اشتراکی امن‌تر است زیرا تاریخچه را بازنویسی نمی‌کند.

git rebase — بازنویسی تاریخچه

Rebase commitهای یک branch را برمی‌دارد و آن‌ها را دوباره روی base جدید «دوباره play می‌کند». نتیجه: یک تاریخچه خطی و تمیز. اما این یعنی commitهای جدیدی با SHA جدید ساخته می‌شوند — یعنی تاریخچه بازنویسی شده. این موضوع اگر روی branchهای اشتراکی انجام شود، فاجعه‌بار است.

bash
# Basic rebase: replay feature commits on top of main
git switch feature/login
git rebase main

# Rebase and then fast-forward main (clean alternative to merge)
git switch feature/login
git rebase main
git switch main
git merge --ff-only feature/login   # safe now

# Interactive rebase (most powerful tool!)
git rebase -i HEAD~3
# Opens editor with last 3 commits:
# pick a1b2c3d Commit 1
# pick d4e5f6g Commit 2
# pick 7h8i9j0 Commit 3
#
# Commands you can use:
# pick   = use commit as-is
# reword = use commit, but edit message
# edit   = use commit, but pause to amend
# squash = combine with previous commit
# fixup  = like squash, but discard message
# drop   = remove commit entirely
# reorder = rearrange lines to reorder commits

# Abort a rebase
git rebase --abort

# Continue after fixing conflicts
git rebase --continue

# Skip a commit (if it's empty after rebase)
git rebase --skip

# Rebase onto a different base (advanced)
git rebase --onto main old-base feature/login

مثال: Squash با Interactive Rebase

bash
# Before: 5 messy commits on feature branch
git log --oneline
# f5g6h7i WIP: login form
# j8k9l0m fix typo
# n1p2q3r WIP: validation
# s4t5u6v cleanup
# w7x8y9z Add login feature

# Start interactive rebase for last 5 commits
git rebase -i HEAD~5

# In editor, change to:
# pick   w7x8y9z Add login feature
# squash s4t5u6v cleanup
# squash n1p2q3r WIP: validation
# squash j8k9l0m fix typo
# squash f5g6h7i WIP: login form

# After saving, edit combined message:
# Add login feature
#
# - Form with email/password
# - Client-side validation
# - API integration

# Result: 1 clean commit instead of 5
git log --oneline
# a1b2c3d Add login feature
🚨 قانون طلایی Rebase

هرگز روی commitهای اشتراکی rebase نکنید! یعنی اگر branchی به remote push شده و همکاران از آن استفاده می‌کنند، rebase نکنید. چون rebase، SHAها را عوض می‌کند، برای همکاران شما به نظر می‌رسد تاریخچه از بین رفته. قانون: rebase برای branchهای محلی و شخصی، merge برای branchهای اشتراکی.

جدول مقایسه

معیارMergeRebase
تاریخچهواقعی، با merge commitsخطی، تمیز
SHA commitsحفظ می‌شوندعوض می‌شوند
روی branch اشتراکی✅ امن❌ خطرناک
پیچیدگیسادهنیاز به درک عمیق
Conflictیک‌بار، در mergeممکن است در هر commit
خوانایی logگراف پیچیدهخطی و واضح
پیش‌فرض دربیشتر پروژه‌هاپروژه‌های large-scale
Chapter 09

حل Conflict (تعارض) #

Conflict زمانی رخ می‌دهد که دو نفر همان خط از همان فایل را به روش‌های متفاوت تغییر داده‌اند و Git نمی‌تواند به طور خودکار تصمیم بگیرد کدام را نگه دارد. Conflict طبیعی است و نشانه‌ی بد بودن کد نیست؛ بلکه نشانه‌ی کار همزمان است. در این فصل، نشانه‌ها، روش حل دستی و استفاده از ابزارها را می‌آموزید.

Conflict چه شکلی است؟

text
// Original file (on main):
function greet(name) {
  return "Hello, " + name;
}

// During merge, Git shows conflict like this:
<<<<<<< HEAD
function greet(name) {
  return "Hi, " + name + "!";
}
=======
function greet(name) {
  return `Hello, ${name}!`;
}
>>>>>>> feature/login

// <<<<<<< HEAD : your current branch (HEAD)
// ======= : separator
// >>>>>>> feature/login : incoming branch

مراحل حل Conflict

bash
# Step 1: Identify conflicted files
git status
# Output:
# Unmerged paths:
#   both modified:   src/auth.js
#   both modified:   README.md

# Step 2: Open each conflicted file in your editor
# Look for <<<<<<<, =======, >>>>>>> markers
# Edit to keep the final desired code (remove all markers)

# Step 3: Stage the resolved files
git add src/auth.js README.md

# Step 4: Complete the merge
git commit
# (For rebase: git rebase --continue)

# ===== If you want to abort the merge entirely =====
git merge --abort
# (For rebase: git rebase --abort)

# ===== View conflicts in a visual mergetool =====
git mergetool
# Opens configured merge tool (VS Code, Meld, KDiff3, Beyond Compare)

# Configure default mergetool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

استراتژی‌های merge خودکار

Git برای فایل‌های متفاوت یا خطوط متفاوت، خودکار conflict را حل می‌کند. اما می‌توانید استراتژی پیش‌فرض را تغییر دهید.

bash
# Default strategy: recursive (now called "ort" in modern Git)
git merge feature/login

# Prefer "ours" — keep our version on conflict
git merge -X ours feature/login

# Prefer "theirs" — keep their version on conflict
git merge -X theirs feature/login

# Show common ancestor in conflict markers (helpful!)
git merge -X diff-algorithm=histogram feature/login

# Use a specific strategy
git merge -s recursive feature/login
git merge -s octopus branch1 branch2 branch3  # for 3+ branches
git merge -s ours redundant-branch            # discard their changes, just record merge

# ===== Pull strategies for conflicts =====
# When pulling, prefer rebase to avoid extra merge commits
git config --global pull.rebase true

# Or set per-pull
git pull --rebase origin main
✅ نکات کاهش Conflict

۱) ارتباط مداوم: قبل از شروع کار، pull کنید. ۲) branchهای کوتاه‌مدت: هرچه branch طولانی‌تر باشد، احتمال conflict بیشتر. ۳) فایل‌های کوچک و ماژولار: اگر همه روی یک فایل بزرگ کار کنند، conflict قطعی است. ۴) قراردادهای کدنویسی: فرمت یکسان (Prettier، ESLint) conflictهای مصنوعی را کم می‌کند.

Conflict در عمل: مثال واقعی

bash
# Scenario: You're on feature/login, your colleague pushed to main

# 1. Try to merge latest main into your feature
git switch feature/login
git merge main
# CONFLICT (content): Merge conflict in src/auth.js

# 2. View the conflict
git diff
# Shows the <<<<<<< ======= >>>>>>> markers

# 3. Open in editor, manually resolve
# Before:
<<<<<<< HEAD
const API_URL = "https://api.staging.example.com";
=======
const API_URL = "https://api.example.com";
>>>>>>> main

# After resolution (you decide which, or combine):
const API_URL = process.env.API_URL || "https://api.example.com";

# 4. Stage and commit
git add src/auth.js
git commit -m "Merge main into feature/login, resolve API_URL conflict"
Chapter 10

استراتژی‌های Branching #

استراتژی branching، قواعد نام‌گذاری و workflow شاخه‌ها در یک تیم است. انتخاب استراتژی مناسب، بسته به اندازه تیم، نوع پروژه و فرکانس release متفاوت است. در این فصل، سه استراتژی اصلی را بررسی می‌کنیم: Git Flow (جامع برای نسخه‌گذاری)، GitHub Flow (ساده برای web apps) و Trunk-Based (سریع برای CI/CD).

۱. Git Flow

گسترده‌ترین استراتژی برای پروژه‌های نسخه‌گذاری شده (مثل نرم‌افزارهای دسکتاپ، کتابخانه‌ها). توسط Vincent Driessen در ۲۰۱۰ معرفی شد. شش نوع branch دارد و برای releaseهای برنامه‌ریزی‌شده مناسب است.

gitGraph commit id: "v1.0" branch develop checkout develop commit id: "dev-1" branch feature/A checkout feature/A commit id: "feat-A1" commit id: "feat-A2" checkout develop merge feature/A branch release/v1.1 checkout release/v1.1 commit id: "release-prep" checkout main merge release/v1.1 tag: "v1.1" branch hotfix/v1.1.1 checkout hotfix/v1.1.1 commit id: "critical-fix" checkout main merge hotfix/v1.1.1 tag: "v1.1.1" checkout develop merge hotfix/v1.1.1
// Git Flow: 6 branch types — main, develop, feature, release, hotfix, (support)
Branchمنبعمقصد mergeهدف
mainکد production
developmainmain (via release)تلفیق featureها
feature/*developdevelopقابلیت‌های جدید
release/*developmain + developآماده‌سازی release
hotfix/*mainmain + developرفع باگ production

۲. GitHub Flow

استراتژی ساده و سبک که GitHub پیشنهاد می‌دهد. فقط دو نوع branch: main و feature. مناسب پروژه‌هایی که به طور مداوم deploy می‌شوند (SaaS، web apps). هیچ release branch یا develop branch ندارد.

gitGraph commit id: "deploy-1" branch feature/dark-mode checkout feature/dark-mode commit id: "add toggle" commit id: "style" checkout main merge feature/dark-mode commit id: "deploy-2" branch feature/api checkout feature/api commit id: "endpoint" checkout main merge feature/api commit id: "deploy-3"
// GitHub Flow: main + feature branches, deploy after every merge

۳. Trunk-Based Development

همه روی یک branch اصلی (trunk) کار می‌کنند. feature branches کوتاه‌مدت (یک تا دو روز) هستند. مناسب تیم‌های با CI/CD قوی که می‌خواهند سرعت deploy بالا باشد. گوگل، فیسبوک و Netflix از این مدل استفاده می‌کنند.

gitGraph commit id: "C1" branch short-feature checkout short-feature commit id: "F1" checkout main merge short-feature commit id: "C2" branch short-bugfix checkout short-bugfix commit id: "B1" checkout main merge short-bugfix commit id: "C3"
// Trunk-Based: very short-lived branches, frequent integration

مقایسه استراتژی‌ها

معیارGit FlowGitHub FlowTrunk-Based
پیچیدگیبالاپایینپایین
تعداد branchها۶۲۱-۲
فرکانس releaseهفته‌ای/ماهانهروزانهچند بار در روز
نیاز به CI/CDمتوسطبالابسیار بالا
مناسب براینسخه‌گذاری شدهWeb appsSaaS بزرگ
هزینه آموزشزیادکممتوسط
💡 انتخاب هوشمندانه

برای اکثر پروژه‌های کوچک و متوسط، GitHub Flow بهترین انتخاب است. ساده، قابل فهم و برای عملیات روزانه کافی است. Git Flow را فقط برای پروژه‌هایی با releaseهای رسمی (مثل کتابخانه‌های open source) انتخاب کنید. Trunk-Based را فقط اگر CI/CD قوی دارید و تیم به اندازه کافی بزرگ است، در نظر بگیرید.

Chapter 11

GitHub — معرفی و راه‌اندازی #

GitHub سرویس میزبانی Git مبتنی بر وب است که در سال ۲۰۰۸ تأسیس شد و در ۲۰۱۸ توسط مایکروسافت خریداری شد. با بیش از ۱۰۰ میلیون توسعه‌دهنده، بزرگ‌ترین پلتفرم collaboration برای کد در جهان است. GitHub روی Git ساخته شده و قابلیت‌هایی مثل Pull Request، Issues، Actions و Projects را اضافه می‌کند.

Fork در برابر Clone

graph LR O["Original Repo
(github.com/upstream/repo)"] F["Your Fork
(github.com/A-talebifard/repo)"] L["Local Clone
(your machine)"] O -->|fork| F F -->|clone| L L -->|push| F F -->|PR| O L -.->|fetch upstream| O style O fill:#f38ba8,stroke:#1e1e2e,color:#1e1e2e style F fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e style L fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e
// Fork = server-side copy on GitHub; Clone = local copy
bash
# ===== Scenario: Contributing to someone else's project =====

# Step 1: Fork on GitHub (via web UI: click "Fork" button)
# Now you have: github.com/A-talebifard/their-project

# Step 2: Clone YOUR fork (not the original)
git clone git@github.com:A-talebifard/their-project.git
cd their-project

# Step 3: Add upstream remote (original repo)
git remote add upstream git@github.com:original-owner/their-project.git

# Step 4: Create a feature branch
git switch -c feature/my-contribution

# Step 5: Make changes, commit, push to your fork
git push -u origin feature/my-contribution

# Step 6: Open Pull Request on GitHub (your-fork → upstream)

# Step 7: Keep your fork in sync with upstream
git fetch upstream
git switch main
git merge upstream/main
git push origin main

# ===== Using GitHub CLI (gh) =====
# Install: https://cli.github.com/

gh auth login                          # one-time setup
gh repo clone A-talebifard/their-project
gh repo fork original-owner/repo --clone
gh pr create --title "Add dark mode" --body "Resolves #42"
gh pr status
gh pr checkout 123                     # checkout PR #123 locally
gh pr merge 123 --squash --delete-branch

Personal Access Tokens (PAT)

از آگوست ۲۰۲۱، GitHub دیگر اجازه نمی‌دهد با پسورد اکانت از طریق HTTPS به repository ها push کنید. به جای آن، باید از Personal Access Token استفاده کنید. دو نوع PAT وجود دارد: Classic (با scope‌های دستی) و Fine-grained (با دسترسی دقیق به هر repo).

bash
# Create PAT:
# GitHub → Settings → Developer settings → Personal access tokens → Generate new token

# Classic PAT scopes (for git operations):
# - repo (full control of private repos)
# - workflow (update GitHub Actions workflows)
# - read:org (read org and team membership)

# Use PAT in place of password (HTTPS)
git clone https://github.com/A-talebifard/repo.git
# Username: A-talebifard
# Password: <your-PAT>

# Cache credentials (avoid entering every time)
git config --global credential.helper store        # plain text (not secure)
git config --global credential.helper cache        # in-memory for 15 min
git config --global credential.helper 'cache --timeout=3600'  # 1 hour

# macOS: use Keychain
git config --global credential.helper osxkeychain

# Windows: use Git Credential Manager (default with Git for Windows)
git config --global credential.helper manager

# Embed PAT in URL (NOT recommended, but possible)
git remote set-url origin https://A-talebifard:<PAT>@github.com/A-talebifard/repo.git

README.md — ویترین پروژه

markdown
# Project Name

> Short one-line description of what this project does.

![License](https://img.shields.io/badge/license-MIT-blue)
![Build](https://img.shields.io/github/workflow/status/A-talebifard/repo/CI)
![Stars](https://img.shields.io/github/stars/A-talebifard/repo)

## Features

- ✨ Feature one
- 🚀 Feature two
- 🔒 Feature three

## Installation

```bash
npm install project-name
```

## Quick Start

```javascript
import { doSomething } from 'project-name';

doSomething({ option: true });
```

## Documentation

Full docs at [https://docs.example.com](https://docs.example.com)

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT © [Abbas Talebifard](https://github.com/A-talebifard)
✅ README خوب چه ویژگی دارد؟

۱) یک تگline description در ابتدا. ۲) Badgeهای وضعیت (build، license، version). ۳) بخش Installation واضح. ۴) مثال Quick Start قابل کپی. ۵) لینک به مستندات کامل. ۶) بخش Contributing. ۷) License. README اولین چیزی است که کاربر می‌بیند؛ تا ۳۰ ثانیه اول قانع‌کننده نباشد، کاربر می‌رود.

Chapter 12

Pull Request — گردش کار کامل #

Pull Request (PR) قلب همکاری در GitHub است. PR یک درخواست رسمی برای merge کردن تغییرات شما به یک branch دیگر (معمولاً main) است. این فرآیند، فرصتی برای code review، بحث درباره‌ی تغییرات، اجرای CI و در نهایت ادغام است. در این فصل، چرخه‌ی کامل PR را از ساخت تا merge می‌بینیم.

flowchart TB A["1. Create feature branch
git switch -c feature/X"] B["2. Make changes & commit"] C["3. Push to your fork/origin
git push -u origin feature/X"] D["4. Open Pull Request
on GitHub"] E["5. CI checks run
Tests, lint, build"] F["6. Code review
Comments, suggestions"] G{"Review approved?"} H["7. Address feedback
push more commits"] I["8. Merge to main
squash/merge/rebase"] J["9. Delete feature branch"] K["10. Deploy to production"] A --> B --> C --> D --> E --> F --> G G -->|No| H --> C G -->|Yes| I --> J --> K style G fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style I fill:#a6e3a1,stroke:#1e1e2e,color:#1e1e2e style K fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e
// Complete PR lifecycle: from branch creation to deployment

گردش کار عملی

bash
# ===== Step 1: Sync with main before starting =====
git switch main
git pull origin main

# ===== Step 2: Create a feature branch with descriptive name =====
git switch -c feature/add-jwt-auth
# Naming conventions:
# feature/xxx  - new features
# fix/xxx      - bug fixes
# docs/xxx     - documentation
# refactor/xxx - code refactoring
# chore/xxx    - maintenance tasks

# ===== Step 3: Make changes, commit in logical chunks =====
git add src/auth.js
git commit -m "feat(auth): implement JWT generation"
git add src/middleware.js
git commit -m "feat(auth): add auth middleware"
git add tests/auth.test.js
git commit -m "test(auth): cover token validation"

# ===== Step 4: Push to remote =====
git push -u origin feature/add-jwt-auth

# ===== Step 5: Open PR via GitHub CLI =====
gh pr create \
  --title "feat(auth): Add JWT authentication" \
  --body "## Description
Implements JWT-based authentication for the API.

## Type of Change
- [x] New feature
- [ ] Bug fix
- [ ] Breaking change

## Testing
- [x] Unit tests pass
- [x] Manual testing on staging

## Related Issue
Closes #42

## Checklist
- [x] Code follows style guide
- [x] Self-review completed
- [x] Documentation updated
- [x] No new warnings" \
  --base main \
  --head feature/add-jwt-auth

# ===== Step 6: After review feedback, make more commits =====
git add src/auth.js
git commit -m "fix(auth): handle expired tokens"
git push   # automatically updates the PR

# ===== Step 7: View PR status =====
gh pr view --web
gh pr checks

# ===== Step 8: After approval, merge (choose strategy) =====
gh pr merge 123 --squash --delete-branch   # recommended
gh pr merge 123 --merge --delete-branch    # preserves all commits
gh pr merge 123 --rebase --delete-branch   # linear history

# ===== Step 9: Sync local main =====
git switch main
git pull origin main
git branch -d feature/add-jwt-auth   # cleanup

سه استراتژی Merge در GitHub

استراتژیتوضیحتاریخچه نهایی
Merge commitیک merge commit با همه commitهای branchکامل، با گراف شاخه‌ها
Squashهمه commitها را یکی می‌کندتمیز، یک commit per PR
Rebasecommitها را روی main rebase می‌کندخطی، همه commitها preserved

PR Template

برای استاندارد کردن PRها، یک فایل در .github/PULL_REQUEST_TEMPLATE.md بسازید تا برای هر PR خودکار ظاهر شود.

markdown
## Description

<!-- Brief description of what this PR does -->

## Type of Change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactor (no functional changes)

## Related Issue

Closes #(issue-number)

## Testing

- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed

## Screenshots (if applicable)

<!-- Drag and drop screenshots here -->

## Checklist

- [ ] My code follows the project's style guide
- [ ] I have performed a self-review
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have updated documentation accordingly
- [ ] My changes generate no new warnings
✅ Code Review Etiquette

۱) به کد نقد کنید، نه به نفر. ۲) فرق بین «must fix» و «nit» را مشخص کنید. ۳) پیشنهاد به جای دستور: «چه می‌شود اگر...» به جای «این را عوض کن». ۴) خوبی‌ها را هم بگویید، نه فقط مشکلات. ۵) اگر بحث طولانی شد، به جای کامنت، تماس تصویری بگیرید. ۶) برای کامنت‌های خود، یک reaction (emoji) بگذارید تا مشخص باشد addressed شده.

Chapter 13

Issues و Project Management #

GitHub Issues سیستم ردیابی باگ‌ها، taskها و inquests است که مستقیماً در repo ادغام شده. به‌همراه Projects v2 و Discussions، یک پلتفرم کامل مدیریت پروژه را فراهم می‌کند. در این فصل، بهترین روش‌های استفاده از Issues، Labels، Milestones و Projects را می‌بینیم.

Issues — ساخت و مدیریت

bash
# Create issue via CLI
gh issue create \
  --title "Bug: Login button not working on Safari" \
  --body "## Description
The login button does not respond on Safari 17.

## Steps to Reproduce
1. Go to /login
2. Enter credentials
3. Click 'Sign In'

## Expected
Redirect to dashboard

## Actual
Nothing happens, console shows TypeError

## Environment
- Safari 17.0
- macOS 14.0
- Production: https://app.example.com

## Screenshots
<!-- drag screenshot here -->

## Labels
bug, frontend, safari, P1" \
  --label "bug,P1" \
  --assignee "@me" \
  --project "Q4 Sprint"

# List open issues
gh issue list
gh issue list --state closed --limit 20
gh issue list --assignee "@me" --label "bug"

# View an issue
gh issue view 42
gh issue view 42 --web

# Close/reopen
gh issue close 42
gh issue close 42 --reason "completed"  # or "not planned"
gh issue reopen 42

# Comment on an issue
gh issue comment 42 --body "Fixed in PR #43"

# Add labels, assignees
gh issue edit 42 --add-label "high-priority"
gh issue edit 42 --add-assignee "A-talebifard"

Issue Template

برای استاندارد کردن issueها، تمپلیت‌ها در .github/ISSUE_TEMPLATE/ قرار دهید. این کار، اطلاعات لازم را از کاربر می‌گیرد و کیفیت گزارش‌ها را بالا می‌برد.

yaml
# .github/ISSUE_TEMPLATE/bug_report.yml
name: Bug Report
description: Report a bug to help us improve
labels: ["bug", "triage"]
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!
  - type: textarea
    id: description
    attributes:
      label: Description
      description: A clear description of the bug
    validations:
      required: true
  - type: textarea
    id: steps
    attributes:
      label: Steps to Reproduce
      placeholder: |
        1. Go to '...'
        2. Click on '....'
        3. See error
    validations:
      required: true
  - type: dropdown
    id: browser
    attributes:
      label: Browser
      options:
        - Chrome
        - Firefox
        - Safari
        - Edge
        - Other
  - type: input
    id: version
    attributes:
      label: App Version
      placeholder: "v1.2.3"

Labels — دسته‌بندی

دستهLabels پیش‌فرضهدف
نوعbug, enhancement, featureچه چیزی
وضعیتtriage, in-progress, blockedکجای workflow
اولویتP0, P1, P2, P3چقدر فوری
محدودهfrontend, backend, docs, ciکدام بخش
سختیgood-first-issue, help-wantedبرای newcomers

Milestones — نقاط عطف

Milestone گروهی از issueها و PRها را برای یک هدف مشخص (مثل release v2.0) گرد هم می‌آورد. به شما اجازه می‌دهد پیشرفت به سمت یک هدف را ببینید.

GitHub Projects v2

Projects v2 یک ابزار مدیریت پروژه انعطاف‌پذیر است که Kanban، Table، Roadmap و Timeline viewها را پشتیبانی می‌کند. برخلاف v1، می‌تواند cross-repo باشد و از Issues، PRs و Draft Issues استفاده کند.

graph LR subgraph Project["GitHub Project v2"] T["Backlog
(Drafts)"] U["In Progress
(Issues + PRs)"] R["In Review
(PRs)"] D["Done
(Closed)"] T --> U --> R --> D end Repo1["Repo A Issues"] Repo2["Repo B Issues"] Repo3["Repo C PRs"] Repo1 -.-> T Repo2 -.-> T Repo3 -.-> R style T fill:#45475a,stroke:#c084fc,color:#cdd6f4 style U fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style R fill:#89b4fa,stroke:#1e1e2e,color:#1e1e2e style D fill:#a6e3a1,stroke:#1e1e2e,color:#1e1e2e
// Cross-repo project board: pull issues/PRs from multiple repos

Discussions — گفتگوهای طولانی

برای پرسش‌ها، ایده‌ها و گفتگوهای طولانی که issue نیستند، GitHub Discussions را فعال کنید (Settings → Features → Discussions). مناسب FAQ، Announcements و Community است.

Chapter 14

GitHub Actions — CI/CD #

GitHub Actions پلتفرم CI/CD داخلی GitHub است که در ۲۰۱۹ معرفی شد. به شما اجازه می‌دهد workflowهای خودکاری بسازید که در رویدادهای مختلف (push، PR، release، schedule) اجرا شوند. با هزاران action آماده در Marketplace، تقریباً هر کاری می‌توان خودکار کرد.

flowchart LR subgraph Trigger["Triggers"] T1[push] T2[pull_request] T3[schedule] T4[release] T5[workflow_dispatch] end subgraph Runner["Runner (Ubuntu/Windows/macOS)"] J1["Job 1: Lint"] J2["Job 2: Test"] J3["Job 3: Build"] J4["Job 4: Deploy"] J1 --> J2 --> J3 --> J4 end T1 -.-> J1 T2 -.-> J1 T4 -.-> J4 style T1 fill:#f38ba8,stroke:#1e1e2e,color:#1e1e2e style J4 fill:#a6e3a1,stroke:#1e1e2e,color:#1e1e2e
// GitHub Actions: events trigger jobs that run on runners

ساختار یک Workflow

yaml
# .github/workflows/ci.yml
name: CI

# When should this workflow run?
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  # Schedule: every day at 3 AM UTC
  schedule:
    - cron: "0 3 * * *"
  # Manual trigger
  workflow_dispatch:
    inputs:
      debug:
        description: 'Enable debug mode'
        type: boolean
        default: false

# Environment variables available to all jobs
env:
  NODE_VERSION: '20'
  CI: true

jobs:
  # ===== Job 1: Lint =====
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci   # clean install (faster than npm install)

      - name: Run ESLint
        run: npm run lint

  # ===== Job 2: Test =====
  test:
    runs-on: ubuntu-latest
    needs: lint   # wait for lint job
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test
        env:
          COVERAGE: true

      - name: Upload coverage
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.os }}-${{ matrix.node-version }}
          path: coverage/

  # ===== Job 3: Build & Deploy =====
  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npm run build
        env:
          API_KEY: ${{ secrets.API_KEY }}

      - name: Deploy to production
        run: |
          echo "Deploying..."
          ./scripts/deploy.sh

Secrets و Variables

yaml
# Steps to add a secret:
# Repo → Settings → Secrets and variables → Actions → New repository secret

# Use in workflow:
steps:
  - name: Use secret
    run: |
      curl -X POST https://api.example.com \
        -H "Authorization: Bearer ${{ secrets.API_TOKEN }}"

  - name: Use variable (non-sensitive)
    run: echo "Environment is ${{ vars.ENVIRONMENT }}"

# Organization-level secrets (shared across repos):
# Org → Settings → Secrets → Actions

# Environment secrets (per-deployment):
# Repo → Settings → Environments → production → Add secret
jobs:
  deploy:
    environment: production   # requires approval
    steps:
      - run: ./deploy.sh
        env:
          PROD_KEY: ${{ secrets.PROD_KEY }}

Workflow پیشرفته: Release خودکار

yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - 'v*'   # triggers on tags like v1.0.0, v2.1.3

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write   # required to create release
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # full history for changelog

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install & build
        run: |
          npm ci
          npm run build

      - name: Generate changelog
        id: changelog
        uses: mikepenz/release-changelog-builder-action@v5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          body: ${{ steps.changelog.outputs.changelog }}
          files: |
            dist/*.zip
            dist/*.tar.gz
            CHANGELOG.md
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
✅ بهترین روش‌های Actions

۱) همیشه actions/checkout@v4 را pin کنید (نه @main). ۲) از npm ci به جای npm install استفاده کنید (سریع‌تر و قابل پیش‌بینی). ۳) Caching را فعال کنید (می‌تواند CI را ۵۰٪ سریع‌تر کند). ۴) Secrets را هرگز در log چاپ نکنید. ۵) Job parallelism را با strategy.matrix افزایش دهید. ۶) از Environment protection rules برای production استفاده کنید (approval لازم).

Chapter 15

GitHub Pages — هاست رایگان #

GitHub Pages سرویس هاستینگ استاتیک رایگان GitHub است که اجازه می‌دهد سایت خود را مستقیماً از repo deploy کنید. مناسب برای portfolio، blog، مستندات پروژه و landing page است. هر اکانت GitHub یک سایت کاربر (username.github.io) و unlimited سایت پروژه (username.github.io/repo) رایگان دارد.

ساخت User Page

bash
# Step 1: Create a special repo named exactly: username.github.io
# For example: A-talebifard.github.io

# Step 2: Clone and add content
git clone git@github.com:A-talebifard/A-talebifard.github.io.git
cd A-talebifard.github.io
echo "<h1>Hello World</h1>" > index.html
git add .
git commit -m "Initial site"
git push

# Step 3: Visit https://A-talebifard.github.io (live in ~1 min)

ساخت Project Page

bash
# Any repo can have a Pages site

# Option A: From /docs folder on main branch
mkdir docs
echo "<h1>My Project</h1>" > docs/index.html
git add docs/
git commit -m "Add docs site"
git push

# Then: Repo → Settings → Pages → Source: main /docs folder

# Option B: From gh-pages branch
git switch --orphan gh-pages
git rm -rf .
echo "<h1>My Project</h1>" > index.html
git add .
git commit -m "Initial gh-pages"
git push origin gh-pages

# Site URL: https://username.github.io/repo-name/

Deploy با GitHub Actions

yaml
# .github/workflows/deploy-pages.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run build

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy
        id: deployment
        uses: actions/deploy-pages@v4

Custom Domain

bash
# Step 1: Add CNAME file in repo root or /docs
echo "www.example.com" > CNAME
git add CNAME
git commit -m "Add custom domain"
git push

# Step 2: Configure DNS
# For subdomain (www.example.com):
#   CNAME www -> username.github.io
# For apex (example.com):
#   A @ -> 185.199.108.153
#   A @ -> 185.199.109.153
#   A @ -> 185.199.110.153
#   A @ -> 185.199.111.153

# Step 3: Enable HTTPS
# Repo → Settings → Pages → Custom domain → Enforce HTTPS ✓

# Step 4: Verify in 24-48 hours
curl -I https://www.example.com
💡 Jekyll —Static Site Generator

GitHub Pages به طور پیش‌فرض از Jekyll (Ruby) پشتیبانی می‌کند. کافیست فایل‌های Markdown بسازید و Jekyll خودکار آن‌ها را به HTML تبدیل می‌کند. برای پروژه‌های مدرن، می‌توانید از Next.js، Astro، Hugo یا VitePress هم استفاده کنید و خروجی build را deploy کنید.

Chapter 16

Undo و Reset #

یکی از پرکاربردترین موضوعات Git، «برگرداندن» تغییرات است. اما کلمه‌ی «undo» در Git چند معنی دارد: می‌توانید یک commit را برگردانید، فایل را به حالت قبلی برگردانید، یا تاریخچه را بازنویس کنید. در این فصل، تفاوت‌های ظریف بین reset، revert و checkout را می‌آموزید.

سه حالت‌ی git reset

graph TB subgraph Before["Before Reset"] B1["HEAD"] --> B2["Commit C (latest)"] B2 --> B3["Commit B"] B3 --> B4["Commit A"] end subgraph Soft["reset --soft HEAD~1"] S1["HEAD"] --> S2["Commit B"] S2 --> S3["Commit A"] S4["Staging: changes of C
(still staged)"] end subgraph Mixed["reset --mixed HEAD~1 (default)"] M1["HEAD"] --> M2["Commit B"] M2 --> M3["Commit A"] M4["Working dir: changes of C
(unstaged)"] end subgraph Hard["reset --hard HEAD~1"] H1["HEAD"] --> H2["Commit B"] H2 --> H3["Commit A"] H4["Changes of C: GONE"] end style S4 fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style M4 fill:#f9e2af,stroke:#1e1e2e,color:#1e1e2e style H4 fill:#f38ba8,stroke:#1e1e2e,color:#1e1e2e
// Three reset modes: soft (keep staged), mixed (unstage), hard (discard)
bash
# ===== git reset --soft =====
# Moves HEAD only; staging area and working dir unchanged
git reset --soft HEAD~1
# Use case: "I want to re-commit my last commit with a different message
# or split it into multiple commits"

# ===== git reset --mixed (default) =====
# Moves HEAD + unstages changes (but keeps them in working dir)
git reset HEAD~1
git reset --mixed HEAD~1
# Use case: "I committed too early, want to re-stage selectively"

# ===== git reset --hard =====
# Moves HEAD + discards all changes (DANGEROUS!)
git reset --hard HEAD~1
# Use case: "I want to completely discard my last commit and changes"

# ===== Reset to a specific commit =====
git reset --hard a1b2c3d

# ===== Reset a single file to HEAD =====
git checkout HEAD -- path/to/file.txt
git restore path/to/file.txt   # modern syntax (Git 2.23+)

# ===== Reset staging area (unstage everything) =====
git reset

# ===== Unstage a specific file =====
git reset path/to/file.txt
git restore --staged path/to/file.txt   # modern

git revert — undo ایمن

برخلاف reset که تاریخچه را بازنویسی می‌کند، revert یک commit جدید می‌سازد که تغییرات commit قبلی را معکوس می‌کند. این روش برای branchهای اشتراکی ایمن است زیرا تاریخچه را تغییر نمی‌دهد.

bash
# Revert a single commit (creates a new commit)
git revert a1b2c3d
# Opens editor with default message: "Revert: <original message>"

# Revert without auto-commit (combine multiple reverts)
git revert --no-commit a1b2c3d
git revert --no-commit d4e5f6g
git commit -m "Revert: remove broken auth changes"

# Revert a range of commits
git revert --no-commit HEAD~3..HEAD

# Revert a merge commit
git revert -m 1 a1b2c3d
# -m 1 means: keep parent 1 (the branch you merged INTO)

# Revert last commit but keep changes staged
git revert -n HEAD

# ===== Difference: reset vs revert =====
# reset: rewrites history (use on local/personal branches)
# revert: adds new commit that undoes (use on shared branches)

# ===== Scenario: Bad commit already pushed to main =====
# DON'T: git reset --hard HEAD~1 && git push -f
# DO:
git revert HEAD
git push
🚨 خطر reset --hard

git reset --hard تغییرات uncommitted را برای همیشه پاک می‌کند (شامل staging area و working dir). فقط commitها از طریق reflog قابل بازیابی هستند. هرگز این دستور را وقتی تغییرات مهم uncommitted دارید، اجرا نکنید. اگر فقط می‌خواهید فایل‌ها را برگردانید، از git restore استفاده کنید.

git checkout و git restore — بازیابی فایل‌ها

bash
# Restore a file from latest commit (discard local changes)
git checkout -- path/to/file.txt
git restore path/to/file.txt          # modern (Git 2.23+)

# Restore a file from a specific commit
git checkout a1b2c3d -- path/to/file.txt
git restore --source=a1b2c3d path/to/file.txt

# Restore multiple files
git restore file1.txt file2.txt

# Restore all files in current directory
git restore .

# Restore staged changes (unstage)
git restore --staged path/to/file.txt
git restore --staged .

# Restore a deleted file (not yet committed deletion)
git restore path/to/deleted.txt

# Restore a deleted file (committed deletion)
git checkout HEAD~1 -- path/to/deleted.txt

# ===== View a file from a specific commit without restoring =====
git show a1b2c3d:path/to/file.txt

git clean — حذف فایل‌های untracked

bash
# Show what would be deleted (dry run)
git clean -n
git clean --dry-run

# Delete untracked files
git clean -f

# Delete untracked files and directories
git clean -fd

# Delete ignored files too (be careful!)
git clean -fdx

# Interactive clean
git clean -i
Chapter 17

Stash و Cherry-pick #

دو دستور پرکاربرد اما کمتر شناخته‌شده: stash برای موقتاً کنار گذاشتن تغییرات، و cherry-pick برای انتخاب یک commit از branch دیگر. هر دو در کار روزمره به شدت مفیدند.

git stash — ذخیره موقت تغییرات

وقتی روی چیزی کار می‌کنید و باید به یک branch دیگر switch کنید اما نمی‌خواهید commit ناقص بسازید، stash به کمک می‌آید. تغییرات شما در یک stack ذخیره می‌شود و بعداً می‌توانید برگردانید.

bash
# Stash all tracked changes (modified + staged)
git stash
git stash push -m "WIP: working on login form"

# Stash including untracked files
git stash -u
git stash --include-untracked

# Stash only staged changes (keep unstaged in working dir)
git stash --keep-index

# Stash a specific file
git stash push -m "Just auth.js" -- path/to/auth.js

# List all stashes
git stash list
# Output:
# stash@{0}: On feature/login: WIP: working on login form
# stash@{1}: On main: quick fix
# stash@{2}: WIP on main: a1b2c3d Add README

# Show what's in a stash
git stash show stash@{0}
git stash show -p stash@{0}    # full diff

# Apply most recent stash (keeps it in stack)
git stash apply

# Apply a specific stash
git stash apply stash@{2}

# Apply and remove from stack (most common)
git stash pop

# Drop a stash
git stash drop stash@{0}

# Clear all stashes (DANGEROUS)
git stash clear

# Create a branch from a stash
git stash branch new-branch stash@{0}
✅ Stash Workflow رایج

۱) روی feature کار می‌کنید. ۲) باگ urgent روی main می‌آید. ۳) git stash کنید. ۴) به main بروید، hotfix branch بسازید، درست کنید، push کنید. ۵) به feature برگردید. ۶) git stash pop کنید. این روش از ساخت commitهای ناقص («WIP»، «temporary») جلوگیری می‌کند.

git cherry-pick — انتقال یک commit

cherry-pick یک commit خاص را از یک branch به branch فعلی اعمال می‌کند. برخلاف merge که کل تاریخچه را می‌آورد، cherry-pick فقط یک commit را. مفید برای: انتقال hotfix بین branchها، یا جدا کردن یک قابلیت از یک branch شلوغ.

bash
# Cherry-pick a single commit
git cherry-pick a1b2c3d

# Cherry-pick multiple commits
git cherry-pick a1b2c3d d4e5f6g 7h8i9j0

# Cherry-pick a range (exclusive of start)
git cherry-pick a1b2c3d..d4e5f6g

# Cherry-pick without committing (stage changes only)
git cherry-pick --no-commit a1b2c3d
git cherry-pick -n a1b2c3d

# Cherry-pick and edit commit message
git cherry-pick --edit a1b2c3d

# Cherry-pick but keep original message format
git cherry-pick -x a1b2c3d
# Adds: (cherry picked from commit a1b2c3d...)

# ===== Common scenario: hotfix from main to develop =====
# A bug was fixed on main, need same fix on develop
git switch develop
git cherry-pick a1b2c3d   # the hotfix commit
git push

# ===== Resolve conflicts during cherry-pick =====
git cherry-pick a1b2c3d
# CONFLICT...
# Resolve, then:
git add .
git cherry-pick --continue

# Abort cherry-pick
git cherry-pick --abort

git bisect — پیدا کردن commit مخرب

وقتی یک باگ ظاهر شده و نمی‌دانید کدام commit آن را وارد کرده، bisect با binary search روی تاریخچه، commit مقصر را پیدا می‌کند.

bash
# Start bisect session
git bisect start

# Mark current commit as bad (has the bug)
git bisect bad

# Mark a known-good commit (e.g., from a month ago)
git bisect good v1.0.0
# or: git bisect good a1b2c3d

# Git checks out a middle commit.
# Test it, then mark as good or bad:
git bisect good   # or git bisect bad

# Continue until Git identifies the first bad commit
# Output: "a1b2c3d is the first bad commit"

# End bisect session (return to original branch)
git bisect reset

# ===== Automated bisect (with a test script) =====
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run npm test    # auto-runs tests until failure found
git bisect reset
✅ bisect کاربردی

اگر تستی دارید که با fail شدنش، باگ را شناسایی می‌کند، git bisect run کل فرآیند را خودکار می‌کند. حتی اگر ۱۰۰۰ commit قبل از current باشد، در ~۱۰ مرحله (log2(1000)) پیدا می‌شود. این یکی از بهترین ویژگی‌های Git برای debug است.

Chapter 18

Submodules و Worktrees #

گاهی اوقات نیاز به ساختارهای پیشرفته‌تری داریم: پروژه‌ای که شامل پروژه‌ی دیگر است (submodule)، یا کار همزمان روی چند branch بدون نیاز به stash (worktree). در این فصل، هر دو را می‌بینیم.

git submodule — repo در repo

Submodule اجازه می‌دهد یک Git repo را درون repo دیگر قرار دهید. مفید برای: shared libraries، monorepoهای ترکیبی، یا وقتی می‌خواهید یک repo را در چندین پروژه استفاده کنید بدون اینکه کد را کپی کنید.

graph TB P["Parent Repo
(your-project)"] S1["Submodule: shared-lib
(separate Git repo)"] S2["Submodule: theme
(separate Git repo)"] P -->|.gitmodules| S1 P -->|.gitmodules| S2 style P fill:#c084fc,stroke:#1e1e2e,color:#1e1e2e style S1 fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e style S2 fill:#2dd4bf,stroke:#1e1e2e,color:#1e1e2e
// Submodule: parent repo references specific commit of another repo
bash
# ===== Add a submodule =====
git submodule add git@github.com:shared/lib.git libs/shared-lib
git commit -m "Add shared-lib as submodule"

# This creates:
# 1. .gitmodules file (tracks submodule URL & path)
# 2. libs/shared-lib/ directory (the submodule content)
# 3. A gitlink entry (pointer to specific commit in submodule)

# ===== Clone a repo WITH its submodules =====
git clone --recurse-submodules git@github.com:A-talebifard/project.git

# If you forgot --recurse-submodules, initialize after clone:
git submodule update --init --recursive

# ===== Update all submodules to latest commit =====
git submodule update --remote
git add .
git commit -m "Update submodules to latest"

# ===== Update a specific submodule =====
cd libs/shared-lib
git switch main
git pull
cd ../..
git add libs/shared-lib
git commit -m "Update shared-lib to latest main"

# ===== View submodule status =====
git submodule status

# ===== Make changes INSIDE a submodule =====
cd libs/shared-lib
# Make changes, commit, push as normal
git add .
git commit -m "Fix bug in shared-lib"
git push origin main
cd ../..
git add libs/shared-lib
git commit -m "Bump shared-lib to latest with bug fix"

# ===== Remove a submodule =====
git submodule deinit -f libs/shared-lib
git rm -f libs/shared-lib
git commit -m "Remove shared-lib submodule"
⚠️ چالش‌های Submodule

Submoduleها قدرتمندند اما چالش‌برانگیز: ۱) کاربران تازه‌کار یادشان می‌رود --recurse-submodules را اضافه کنند. ۲) Conflict در submodule references رایج است. ۳) CI باید submodules را init کند. ۴) اگر به submodules علاقه‌مندید، جایگزین‌های مدرن‌تر مثل Git Subtree یا monorepo tools (Nx، Turborepo، Lerna) را هم بررسی کنید.

git worktree — کار همزمان روی چند branch

worktree اجازه می‌دهد چند working directory برای همان repo داشته باشید. یعنی می‌توانید همزمان روی feature/login و main کار کنید بدون نیاز به stash یا clone جدید.

bash
# Create a new working tree for an existing branch
git worktree add ../project-feature feature/login
# Now you have:
# /path/to/project          -> main branch (original)
# /path/to/project-feature  -> feature/login (new worktree)

# Create worktree with a NEW branch
git worktree add -b feature/api ../project-api

# List all worktrees
git worktree list
# Output:
# /path/to/project          a1b2c3d [main]
# /path/to/project-feature  d4e5f6g [feature/login]
# /path/to/project-api      7h8i9j0 [feature/api]

# Remove a worktree (just delete the directory)
git worktree remove ../project-feature

# Prune stale worktree entries
git worktree prune

# ===== Common use cases =====
# 1. Working on a feature when a hotfix is needed:
#    - Open new worktree on main, fix, push, remove worktree
# 2. Running tests on one branch while coding on another
# 3. Comparing two versions side by side in two editors

Partial Clone و Sparse-Checkout

برای repoهای بزرگ، می‌توانید فقط تاریخچه‌ای که نیاز دارید دانلود کنید.

bash
# ===== Partial clone: only download commits, fetch blobs on demand =====
git clone --filter=blob:none git@github.com:large/repo.git
# Faster clone, downloads file contents only when you read them

# Even more aggressive: no blobs, no trees
git clone --filter=tree:0 git@github.com:large/repo.git

# ===== Sparse checkout: only check out specific directories =====
git clone --no-checkout git@github.com:large/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set src/components src/utils
git checkout main
# Now only src/components/ and src/utils/ are on disk

# Add more directories later
git sparse-checkout add docs

# Disable sparse checkout
git sparse-checkout disable
Chapter 19

Hooks و تنظیمات پیشرفته #

Git Hooks اسکریپت‌هایی هستند که به‌طور خودکار قبل یا بعد از رویدادهای مهم (commit، push، receive) اجرا می‌شوند. با ترکیب hooks، .gitignore هوشمند و GPG signing، می‌توانید کیفیت کد و امنیت پروژه را به طور چشمگیری افزایش دهید.

ساختار Hooks

Hooks در .git/hooks/ قرار دارند و به صورت پیش‌فرض sample هستند (با پسوند .sample). برای فعال‌سازی، پسوند را حذف کنید و فایل را executable کنید.

Hookزمان اجراکاربرد رایج
pre-commitقبل از ساخت commitLint، format، block sensitive data
prepare-commit-msgقبل از باز شدن editor پیامافزودن issue number خودکار
commit-msgبعد از نوشته شدن پیاماعتبارسنجی فرمت پیام (Conventional Commits)
post-commitبعد از کامل شدن commitاعلان، backup
pre-pushقبل از pushاجرای تست، block push به main
pre-rebaseقبل از rebaseجلوگیری از rebase روی main
post-mergeبعد از mergeنصب خودکار dependencies

مثال: pre-commit hook

bash
#!/bin/bash
# File: .git/hooks/pre-commit (make executable with: chmod +x)

# Exit on any error
set -e

echo "▶ Running pre-commit checks..."

# 1. Block commits with console.log in JS files
if git diff --cached --name-only | grep -E "\.(js|ts|jsx|tsx)$"; then
  FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E "\.(js|ts|jsx|tsx)$")
  for FILE in $FILES; do
    if grep -n "console\.log" "$FILE"; then
      echo "❌ Found console.log in $FILE. Remove before committing."
      exit 1
    fi
  done
fi

# 2. Block commits with TODO comments
if git diff --cached | grep -E "^\+.*TODO"; then
  echo "⚠️  Warning: commit contains TODO comments"
  # exit 1   # uncomment to make this blocking
fi

# 3. Check for secrets (basic patterns)
if git diff --cached | grep -iE "(api_key|password|secret)\s*=\s*['\"]"; then
  echo "❌ Possible secret detected! Please review."
  exit 1
fi

# 4. Run linter on staged files
if [ -f "package.json" ]; then
  npx lint-staged
fi

echo "✅ Pre-commit checks passed"
exit 0

مثال: commit-msg hook (Conventional Commits)

bash
#!/bin/bash
# File: .git/hooks/commit-msg
# Ensures commit messages follow Conventional Commits format

MSG_FILE="$1"
MSG=$(cat "$MSG_FILE")

# Regex: type(scope): description  or  type: description
PATTERN="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9-]+\))?!?: .{1,80}$"

# Skip merge commits
if echo "$MSG" | grep -q "^Merge "; then
  exit 0
fi

# Skip revert commits
if echo "$MSG" | grep -q "^Revert "; then
  exit 0
fi

# Check first line
FIRST_LINE=$(echo "$MSG" | head -1)

if ! echo "$FIRST_LINE" | grep -qE "$PATTERN"; then
  echo "❌ Invalid commit message format!"
  echo ""
  echo "Expected: type(scope): description"
  echo "Examples:"
  echo "  feat(auth): add JWT login"
  echo "  fix: handle null user"
  echo "  docs: update README"
  echo ""
  echo "Got: $FIRST_LINE"
  exit 1
fi

exit 0

حرفه‌ای: Husky + lint-staged

برای پروژه‌های Node.js، ابزار Husky مدیریت hooks را در repo به اشتراک می‌گذارد (hooks پیش‌فرض در .git/hooks فقط محلی هستند).

bash
# Install Husky
npm install --save-dev husky lint-staged

# Initialize Husky (creates .husky/ directory)
npx husky init

# Add pre-commit hook
echo "npx lint-staged" > .husky/pre-commit

# Configure lint-staged in package.json
# This runs specific commands on staged files only
json
{
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [
      "eslint --fix",
      "prettier --write",
      "git add"
    ],
    "*.{css,scss}": [
      "stylelint --fix",
      "git add"
    ],
    "*.{md,json,yaml}": [
      "prettier --write",
      "git add"
    ]
  }
}

.gitignore — نادیده گرفتن فایل‌ها

gitignore
# ===== A comprehensive .gitignore =====

# Dependencies
node_modules/
.pnp/
.pnp.js

# Build output
dist/
build/
out/
.next/
.nuxt/
.cache/
.parcel-cache/

# Environment variables (NEVER commit!)
.env
.env.local
.env.*.local
*.env

# Secrets
secrets.json
*.pem
*.key
!public.key

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# OS files
.DS_Store
Thumbs.db
desktop.ini

# IDE / Editor
.vscode/
!.vscode/settings.json
!.vscode/extensions.json
.idea/
*.swp
*.swo
*~
.project
.classpath
.settings/

# Test coverage
coverage/
.nyc_output/

# Misc
*.pid
*.seed
*.pid.lock
.tmp/
tmp/

# Negation: include a file that would be ignored
!tests/fixtures/.env
✅ gitignore.io

برای شروع سریع، به gitignore.io بروید، زبان/فریم‌ورک/OS خود را وارد کنید و یک .gitignore کامل دریافت کنید. GitHub هم در github/gitignore تمپلیت‌های رسمی برای هر زبان دارد.

global .gitignore

bash
# Create a global gitignore for OS/IDE files
echo "# OS
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/
*.swp" > ~/.gitignore_global

# Tell Git to use it
git config --global core.excludesfile ~/.gitignore_global

# Now you don't need to add these to every project's .gitignore

GPG Signing — امضای commits

GPG signing به commits شما امضای دیجیتال اضافه می‌کند تا قابل تأیید باشد که واقعاً شما آن را ساخته‌اید. GitHub commits امضاشده را با علامت "Verified" نشان می‌دهد.

bash
# Step 1: Generate GPG key
gpg --full-generate-key
# Choose: (1) RSA and RSA
# Key size: 4096
# Validity: 1y (or 0 for no expiry)
# Real name: Abbas Talebifard
# Email: abbas@example.com (same as GitHub)

# Step 2: List GPG keys
gpg --list-secret-keys --keyid-format=long
# Output:
# sec   rsa4096/ABC123DEF456 2024-01-01 [SC]
# Copy the KEY_ID (after the /): ABC123DEF456

# Step 3: Export public key
gpg --armor --export ABC123DEF456
# Copy the entire output (-----BEGIN PGP PUBLIC KEY BLOCK----- ...)

# Step 4: Add to GitHub → Settings → SSH and GPG keys → New GPG key

# Step 5: Configure Git to use GPG
git config --global user.signingkey ABC123DEF456
git config --global commit.gpgsign true   # sign all commits by default

# Step 6: Sign a commit
git commit -S -m "Signed commit"

# Sign a tag
git tag -s v1.0.0 -m "Signed release v1.0.0"

# Verify a signature
git verify-commit HEAD
git tag -v v1.0.0

.gitattributes

gitattributes
# .gitattributes - per-file settings

# Normalize line endings (auto-convert on checkout/commit)
* text=auto

# Specific file types
*.txt text
*.jpg binary
*.png binary
*.pdf binary

# Force LF for shell scripts
*.sh text eol=lf

# Force CRLF for Windows batch files
*.bat text eol=crlf

# Mark generated files as linguist-vendored (excluded from GitHub stats)
docs/*.md linguist-vendored
minified/*.js linguist-generated=true

# Diff settings
*.md diff=markdown
*.json diff=json
Chapter 20

Troubleshooting — حل مشکلات رایج #

حتی بهترین توسعه‌دهندگان هم به مشکل می‌خورند. این فصل، رایج‌ترین مشکلات Git و راه‌حل آن‌ها را پوشش می‌دهد. هر مشکل با سناریوی واقعی و دستورات بازیابی نشان داده شده است.

مشکل ۱: «یک commit را گم کردم!»

bash
# Scenario: Did git reset --hard, lost my work!

# Step 1: Check reflog (record of every HEAD movement)
git reflog
# Output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# d4e5f6g HEAD@{1}: commit: My important work  ← this is what you want!

# Step 2: Recover by resetting to that commit
git reset --hard d4e5f6g

# Or cherry-pick just that commit
git cherry-pick d4e5f6g

مشکل ۲: «در حالت Detached HEAD هستم»

bash
# Scenario: Checked out a commit (not a branch), now commits go nowhere

# Symptoms:
# "You are in 'detached HEAD' state..."

# Solution 1: Create a new branch from current position
git switch -c new-branch-name

# Solution 2: If you already made commits, save them first
git branch temp-branch        # mark current position
git switch main
git merge temp-branch         # bring commits to main
git branch -d temp-branch

# Solution 3: If you don't want those commits
git switch main               # return to main, commits are "lost" but in reflog

مشکل ۳: «push رد می‌شود (non-fast-forward)»

bash
# Error: "Updates were rejected because the remote contains work
# that you do not have locally"

# Cause: Someone else pushed to the same branch

# Solution 1: Pull first, then push
git pull --rebase origin main    # rebase your commits on top of remote
git push

# Solution 2: If you want to merge instead of rebase
git pull origin main
# (this creates a merge commit)
git push

# Solution 3: Force push (ONLY for personal branches!)
git push --force-with-lease

مشکل ۴: «فایل در .gitignore است اما هنوز track می‌شود»

bash
# Cause: .gitignore only affects untracked files.
# If a file was already tracked, adding to .gitignore doesn't remove it.

# Solution: Remove from tracking but keep on disk
git rm --cached path/to/file    # for a single file
git rm -r --cached path/to/dir  # for a directory

# Then commit
git commit -m "Stop tracking file (now in .gitignore)"

# ===== Remove all files that should be ignored =====
git rm -r --cached .
git add .
git commit -m "Apply .gitignore to all files"

مشکل ۵: «فایل‌های حساس را commit کردم!»

bash
# Scenario: Committed .env with API keys!

# Step 1: If recent commit (not pushed yet)
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit --amend --no-edit

# Step 2: If already pushed (BAD! keys are exposed)
# - IMMEDIATELY rotate/revoke the exposed keys
# - Then clean history with BFG Repo-Cleaner or git-filter-repo

# Using git-filter-repo (modern, recommended):
pip install git-filter-repo
git filter-repo --path .env --invert-paths

# Force push rewritten history
git push --force --all
git push --force --tags

# Step 3: Notify collaborators - they need to re-clone
🚨 نشت اطلاعات حساس

اگر secretها (API keys، passwords، private keys) را به GitHub push کرده‌اید، قبل از هر چیز آن‌ها را revoke و جدید بسازید. پاک کردن history هیچ فایده‌ای ندارد اگر کسی قبلاً clone کرده باشد. GitHub حتی اگر history را rewrite کنید، forkها و cacheها همچنان secret را دارند.

مشکل ۶: «repo خیلی بزرگ شده»

bash
# Step 1: Check what's taking space
git count-objects -vH

# Step 2: See largest files in history
git rev-list --objects --all | \
  git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
  awk '/^blob/ {print substr($0,6)}' | \
  sort -k2 -n -r | head -20

# Step 3: Run garbage collection
git gc --aggressive --prune=now

# Step 4: For large files in history, use BFG Repo-Cleaner
# Download from: https://rtyley.github.io/bfg-repo-cleaner/
java -jar bfg.jar --strip-blobs-bigger-than 50M my-repo.git
cd my-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# Step 5: Consider Git LFS for large binary files going forward
git lfs install
git lfs track "*.psd" "*.mp4" "*.zip"
git add .gitattributes

مشکل ۷: «merge را خراب کردم»

bash
# Scenario: Started merge but conflicts are too complex

# Abort the merge (return to pre-merge state)
git merge --abort

# If you already committed the merge:
git reset --hard ORIG_HEAD
# ORIG_HEAD points to where you were before the merge

# For rebase:
git rebase --abort

مشکل ۸: «اسم/ایمیل اشتباه در commits قبلی»

bash
# For future commits: update config
git config --global user.name "Correct Name"
git config --global user.email "correct@example.com"

# For past commits (last N commits), use interactive rebase:
git rebase -i HEAD~5
# Mark commits as "edit", then for each:
git commit --amend --author="Correct Name <correct@example.com>"
git rebase --continue

# For ALL commits in repo (DANGEROUS, rewrites entire history):
git filter-repo --commit-callback '
    commit.author_email = b"correct@example.com"
    commit.author_name = b"Correct Name"
    commit.committer_email = b"correct@example.com"
    commit.committer_name = b"Correct Name"
'

# Force push
git push --force --all
Chapter 21

Best Practices و Markdown #

این فصل، مجموعه‌ای از بهترین روش‌ها برای کار با Git و GitHub را ارائه می‌دهد؛ از کیفیت commitها تا طراحی پروژه‌های متن‌باز. رعایت این اصول، تفاوت بین یک کاربر آماتور و یک توسعه‌دهنده‌ی حرفه‌ای است.

قوانین commit messages

  • خط اول: حداکثر ۵۰ کاراکتر، در زمان حال، با حرف بزرگ.
  • خط دوم: خالی.
  • خط سوم به بعد: توضیحات با حداکثر ۷۲ کاراکتر در هر خط.
  • از Conventional Commits استفاده کنید: feat, fix, docs, refactor, test, chore.
  • به جای «what»، «why» را توضیح دهید: کد خودش می‌گوید چه شده، پیام باید بگوید چرا.
text
// ❌ Bad commit messages:
- "fix"
- "update"
- "wip"
- "fixed the bug"
- "asdf"
- "Changes from meeting"

// ✅ Good commit messages:
- "fix(auth): handle expired JWT tokens gracefully"
- "feat(api): add /users endpoint with pagination"
- "docs: add installation instructions for Windows"
- "refactor(auth): extract token validation to middleware"

// ✅ With body:
feat(auth): add OAuth2 login with Google

- Add /api/auth/google endpoint
- Implement OAuth2 callback handler
- Store refresh tokens in database
- Add middleware to validate OAuth sessions

Resolves: #42
Breaking change: removes old /api/login endpoint

قوانین branch

  • نام‌گذاری معنادار: feature/add-jwt-auth به جای my-changes.
  • کوتاه‌مدت نگه دارید: هرچه طولانی‌تر، احتمال conflict بیشتر.
  • یک feature per branch: مخلوط کردن چند قابلیت، review را سخت می‌کند.
  • قبل از merge، rebase روی main: تاریخچه‌ی تمیز و آخرین تغییرات.
  • بعد از merge، حذف کنید: branchهای قدیمی شلوغ می‌کنند.

قوانین PR

  • کوچک نگه دارید: حداکثر ۴۰۰ خط تغییر، review ساده‌تر.
  • توضیح واضح: چرا، چه چیزی، چطور.
  • خود-review کنید: قبل از assign به دیگران.
  • آزمایش‌ها را به‌روز کنید: پوشش کد نباید افت کند.
  • صبور باشید: review زمان می‌برد؛ فشار نیاورید.

Markdown — راهنمای سریع

markdown
# H1 Heading
## H2 Heading
### H3 Heading

**Bold text**
*Italic text*
~~Strikethrough~~
`inline code`

[Link text](https://example.com)
![Alt text](image.png)

- Unordered list item
- Another item
  - Nested item

1. Ordered list
2. Second item
3. Third item

> Blockquote
> More quote

```javascript
// Code block with syntax highlighting
function hello() {
  console.log("Hello");
}
```

| Column 1 | Column 2 |
|----------|----------|
| Cell 1   | Cell 2   |
| Cell 3   | Cell 4   |

---

Horizontal rule above

- [x] Task list (completed)
- [ ] Task list (pending)

<details>
<summary>Click to expand</summary>
Hidden content here
</details>

<!-- HTML comment -->

Footnote[^1]

[^1]: Footnote definition

## GitHub Flavored Markdown (GFM)
- @mentions (notify users)
- #123 (link to issue/PR)
- emoji :smile: :rocket: :+1:
- SHA references (a1b2c3d)

کانال‌های ارتباطی پروژه‌های Open Source

یک پروژه‌ی متن‌باز خوب، این فایل‌ها را دارد:

فایلهدف
README.mdمعرفی، نصب، استفاده
CONTRIBUTING.mdچطور مشارکت کنیم
CODE_OF_CONDUCT.mdقوانین رفتار جامعه
LICENSEلیسانس قانونی
CHANGELOG.mdتاریخچه‌ی تغییرات
SECURITY.mdگزارش آسیب‌پذیری‌ها
.github/ISSUE_TEMPLATE/تمپلیت issue
.github/PULL_REQUEST_TEMPLATE.mdتمپلیت PR
.github/FUNDING.ymlدکمه Sponsor

لیسانس‌های رایج

لیسانساجازه商用تغییر لازممحبوبیت
MIT✅ (اعتبار)بسیار زیاد
Apache 2.0✅ + patent grantزیاد
BSD 3-Clauseمتوسط
GPL v3❌ باید GPL بماندمتوسط
AGPL v3❌ برای SaaS همکم
Unlicenseکم
✅ انتخاب لایسنس

برای اکثر پروژه‌ها MIT بهترین انتخاب است: ساده، مجاز به همه‌چیز، فقط اعتبار لازم. اگر نگران patent هستید، Apache 2.0. اگر می‌خواهید derivativeها هم open source بمانند، GPL v3. از سایت choosealicense.com کمک بگیرید.

Chapter 22

Cheat Sheet کامل #

این فصل، یک مرجع سریع برای تمام دستورات مهم Git است. برای دسترسی سریع در حین کار طراحی شده است. هر دستور با توضیح کوتاه و مثال آمده است.

Setup & Config

دستورتوضیح
git config --global user.name "Name"تنظیم نام
git config --global user.email "email"تنظیم ایمیل
git config --global init.defaultBranch mainbranch پیش‌فرض
git config --global core.editor "code --wait"ادیتور پیش‌فرض
git config --global pull.rebase truepull با rebase
git config --listنمایش تنظیمات

Repository Operations

دستورتوضیح
git initساخت repo جدید
git clone <url>کپی از remote
git clone --depth 1 <url>shallow clone
git clone --recurse-submodules <url>با submodules
git statusوضعیت فعلی
git status -sوضعیت کوتاه

Staging & Committing

دستورتوضیح
git add <file>stage یک فایل
git add .stage همه
git add -pstage تعاملی
git add -ustage فقط modifiedها
git commit -m "msg"commit
git commit -am "msg"stage + commit tracked
git commit --amendاصلاح آخرین commit
git commit --amend --no-editاضافه تغییر بدون تغییر پیام

Branching & Merging

دستورتوضیح
git branchلیست branchها
git branch <name>ساخت branch
git switch <name>تعویض branch
git switch -c <name>ساخت + تعویض
git branch -d <name>حذف branch (safe)
git branch -D <name>حذف branch (force)
git merge <branch>merge
git merge --no-ff <branch>merge با merge commit
git merge --squash <branch>squash merge
git merge --abortلغو merge

Rebasing

دستورتوضیح
git rebase <branch>rebase روی branch
git rebase -i HEAD~Nrebase تعاملی
git rebase --continueادامه rebase
git rebase --abortلغو rebase
git rebase --skipرد کردن commit

Remote Operations

دستورتوضیح
git remote -vلیست remoteها
git remote add <name> <url>افزودن remote
git remote remove <name>حذف remote
git fetch <remote>دریافت بدون merge
git pullfetch + merge
git pull --rebasefetch + rebase
git pushارسال به remote
git push -u origin <branch>push + set upstream
git push --force-with-leaseforce push امن
git push origin --delete <branch>حذف remote branch

Undo & Recovery

دستورتوضیح
git reset --soft HEAD~1undo commit، keep staged
git reset --mixed HEAD~1undo commit + unstage (default)
git reset --hard HEAD~1undo commit + discard
git revert <commit>ساخت commit معکوس
git restore <file>بازگرداندن فایل
git restore --staged <file>unstage
git reflogتاریخچه‌ی HEAD
git clean -fdحذف untracked

Stash & Cherry-pick

دستورتوضیح
git stashذخیره موقت
git stash -uشامل untracked
git stash listلیست stashها
git stash popapply + drop
git stash applyapply (keep in stack)
git cherry-pick <sha>انتقال یک commit
git cherry-pick --abortلغو cherry-pick

Inspection & Diff

دستورتوضیح
git logتاریخچه
git log --oneline --graphگراف فشرده
git log -plog با diff
git log --author="name"فیلتر بر اساس نویسنده
git diffتفاوت unstaged
git diff --stagedتفاوت staged
git diff HEADتفاوت با آخرین commit
git show <sha>نمایش یک commit
git blame <file>آخرین تغییر هر خط
git bisectbinary search برای باگ

Tags & Releases

دستورتوضیح
git tag v1.0.0tag سبک
git tag -a v1.0.0 -m "msg"annotated tag
git tag -s v1.0.0 -m "msg"signed tag
git tagلیست tags
git push origin v1.0.0push یک tag
git push --tagspush همه tags
git tag -d v1.0.0حذف tag محلی
git checkout v1.0.0checkout یک tag

GitHub CLI (gh)

دستورتوضیح
gh auth loginورود به GitHub
gh repo clone <owner>/<repo>clone
gh repo fork <owner>/<repo>fork
gh repo create <name> --publicساخت repo
gh pr createساخت PR
gh pr listلیست PRها
gh pr checkout <num>checkout PR
gh pr merge <num> --squashmerge PR
gh issue createساخت issue
gh issue listلیست issueها
gh workflow runاجرای workflow
gh run listلیست runها
💡 میانبرهای صفحه‌کلید

این کتاب از Ctrl+K برای جستجو، Esc برای بستن جستجو، و / برای ناوبری بین فصل‌ها پشتیبانی می‌کند. برای کپی کردن کد، روی دکمه‌ی Copy در بالای هر باکس کد کلیک کنید.

Glossary

واژه‌نامه #

اصطلاحات تخصصی Git و GitHub با توضیح کوتاه برای مرجع سریع.

اصطلاحتوضیح
HEADاشاره‌گر به commit فعلی روی branch جاری
ORIG_HEADموقعیت HEAD قبل از آخرین عملیات بزرگ (merge، reset)
MERGE_HEADcommit ای که در حال merge شدن به HEAD است
FETCH_HEADنتیجه‌ی آخرین fetch
originنام پیش‌فرض remote repository
upstreamremote ای که از آن fork کرده‌اید
mainنام پیش‌فرض branch اصلی (به جای master)
masterنام قدیمی branch اصلی (تا ۲۰۲۰)
fast-forwardmerge ای که فقط pointer را جلو می‌برد، بدون merge commit
three-way mergemerge با ساختن commit جدید با دو والد
detached HEADوقتی HEAD به commit خاصی اشاره می‌کند، نه به branch
working directoryفایل‌های روی دیسک که شما ویرایش می‌کنید
staging area (index)منطقه‌ی بین working dir و repository برای آماده‌سازی commit
blobobject ذخیره‌ی محتوای فایل در Git
treeobject ذخیره‌ی ساختار دایرکتوری
commitsnapshot از staged files + metadata (author، message، parent)
refنام قابل خواندن که به SHA یک commit اشاره می‌کند (branch، tag)
reflogتاریخچه‌ی محلی حرکات HEAD (برای recovery)
shallow cloneclone فقط با آخرین commit (با --depth)
shallow cloneclone فقط با آخرین commit (با --depth)
forkکپی server-side از repo روی حساب شما
cloneکپی local از repo روی دیسک شما
Pull Request (PR)درخواست merge از یک branch به دیگر
issueگزارش باگ یا درخواست قابلیت در GitHub
milestoneگروهی از issues/PRs برای یک هدف
labelبرچسب برای دسته‌بندی issue/PR
Actionsپلتفرم CI/CD داخلی GitHub
workflowیک فایل YAML در .github/workflows/
runnerماشینی که workflow روی آن اجرا می‌شود
Pagesهاستینگ استاتیک رایگان GitHub
LFSLarge File Storage، برای ذخیره‌ی فایل‌های بزرگ
submodulerepo داخل repo (reference به commit خاص)
worktreeworking directory اضافی برای همان repo
squashترکیب چند commit در یکی
cherry-pickاعمال یک commit خاص از branch دیگر
bisectbinary search برای پیدا کردن commit مخرب
blameمشاهده‌ی اینکه کدام commit هر خط را تغییر داده
hookاسکریپتی که قبل/بعد از یک رویداد Git اجرا می‌شود
Conventional Commitsاستاندارد پیام commit: type(scope): description
GPG signingامضای دیجیتال commits برای تأیید هویت
PATPersonal Access Token، جایگزین پسورد HTTPS
SSH keyکلید عمومی/خصوصی برای auth بدون پسورد
Git Flowاستراتژی branching با ۶ نوع branch
GitHub Flowاستراتژی ساده با main + feature
Trunk-Basedاستراتژی با branchهای کوتاه‌مدت