คู่มือนี้ครอบคลุมการใช้งาน Git ตั้งแต่พื้นฐานการควบคุมเวอร์ชัน ไปจนถึงเทคนิคขั้นสูงสำหรับทีมระดับองค์กร เนื้อหาเขียนเป็นภาษาไทยพร้อมศัพท์เทคนิคภาษาอังกฤษ มีตัวอย่างโค้ด แผนภาพ และตารางเปรียบเทียบประกอบทุกหัวข้อ เหมาะสำหรับนักพัฒนาทุกระดับที่ต้องการใช้ Git อย่างมืออาชีพและมีประสิทธิภาพ
ระบบควบคุมเวอร์ชัน (Version Control System — VCS) คือซอฟต์แวร์ที่บันทึกการเปลี่ยนแปลงของไฟล์หรือชุดไฟล์ตลอดเวลา เพื่อให้สามารถเรียกคืนเวอร์ชันใดก็ได้ในอนาคต
เหตุผลที่จำเป็น:
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'secondaryColor': '#3c3836', 'tertiaryColor': '#504945', 'background': '#282828', 'mainBkg': '#3c3836', 'nodeBorder': '#fabd2f', 'clusterBkg': '#282828', 'titleColor': '#fabd2f', 'edgeLabelBackground': '#282828', 'fontFamily': 'monospace'}}}%%
flowchart TD
subgraph ERA1["🕰️ ยุคที่ 1: Local VCS (1970s–1980s)"]
direction LR
L1["RCS\nRevision Control System"]
L2["SCCS\nSource Code Control System"]
L3["💾 ฐานข้อมูล Patch\nบน Machine เดียว"]
L1 --> L3
L2 --> L3
end
subgraph ERA2["🏢 ยุคที่ 2: Centralized VCS (1990s–2000s)"]
direction LR
C1["CVS\nConcurrent Versions System"]
C2["SVN\nApache Subversion"]
C3["🖥️ Central Server\nเก็บประวัติทั้งหมด"]
C1 --> C3
C2 --> C3
end
subgraph ERA3["🌐 ยุคที่ 3: Distributed VCS (2005–ปัจจุบัน)"]
direction LR
D1["Git\n(Linus Torvalds, 2005)"]
D2["Mercurial\n(hg)"]
D3["🗂️ ทุก Node มีประวัติ\nครบถ้วน (Full Clone)"]
D1 --> D3
D2 --> D3
end
ERA1 -->|"ข้อจำกัด: ทำงานคนเดียว"| ERA2
ERA2 -->|"ข้อจำกัด: Single Point of Failure"| ERA3
style ERA1 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style ERA2 fill:#3c3836,stroke:#83a598,color:#ebdbb2
style ERA3 fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
เปรียบเทียบสามยุค:
| คุณสมบัติ | Local VCS | Centralized VCS (SVN) | Distributed VCS (Git) |
|---|---|---|---|
| การทำงานออฟไลน์ | ✅ | ❌ | ✅ |
| Single Point of Failure | ❌ | ✅ (Server down = ทำงานไม่ได้) | ✅ ไม่มี |
| ความเร็ว | เร็ว | ช้า (Network) | เร็วมาก (Local) |
| Branch | ยาก | ยาก/ช้า | เร็ว/ง่ายมาก |
| Merge | ยาก | ปานกลาง | ยอดเยี่ยม |
| พื้นที่ดิสก์ | น้อย | น้อย (Client) | มากกว่า (Full History) |
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'secondaryColor': '#3c3836', 'background': '#282828', 'mainBkg': '#3c3836', 'nodeBorder': '#fabd2f', 'fontFamily': 'monospace'}}}%%
flowchart LR
WD["📁 Working Directory\n(พื้นที่ทำงาน)\nไฟล์ที่เราแก้ไขโดยตรง"]
SA["📋 Staging Area\n(Index / พื้นที่พักไฟล์)\nเตรียมไฟล์ก่อน Commit"]
REPO["🗄️ Repository\n(.git directory)\nฐานข้อมูลประวัติทั้งหมด"]
REMOTE["☁️ Remote Repository\n(GitHub/GitLab)\nเซิร์ฟเวอร์กลาง"]
WD -->|"git add"| SA
SA -->|"git commit"| REPO
REPO -->|"git push"| REMOTE
REMOTE -->|"git fetch / pull"| REPO
REPO -->|"git checkout / restore"| WD
style WD fill:#cc241d,stroke:#fb4934,color:#fbf1c7
style SA fill:#d79921,stroke:#fabd2f,color:#282828
style REPO fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style REMOTE fill:#076678,stroke:#83a598,color:#fbf1c7
Git ใช้ระบบ Snapshot ไม่ใช่ Delta:
Delta: v1 → Δ1 → Δ2 → Δ3 (ต้อง replay ทุก delta เพื่อได้ v4)
Snapshot: v1 v2 v3 v4 (เข้าถึงทุก version ได้โดยตรง)
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
graph TD
TAG["🏷️ Tag Object\nv1.0.0\n(SHA: a1b2c3)"]
COMMIT2["📦 Commit Object\n2nd commit\n(SHA: f3e4d5)"]
COMMIT1["📦 Commit Object\n1st commit\n(SHA: 9a8b7c)"]
TREE2["🌳 Tree Object\nroot/\n(SHA: 1c2d3e)"]
TREE1["🌳 Tree Object\nroot/\n(SHA: 4f5e6d)"]
BLOB1["📄 Blob Object\nmain.py\n(SHA: 7a8b9c)"]
BLOB2["📄 Blob Object\nREADME.md\n(SHA: 2b3c4d)"]
BLOB3["📄 Blob Object\nmain.py v2\n(SHA: 5e6f7a)"]
TAG --> COMMIT2
COMMIT2 --> COMMIT1
COMMIT2 --> TREE2
COMMIT1 --> TREE1
TREE2 --> BLOB3
TREE2 --> BLOB2
TREE1 --> BLOB1
TREE1 --> BLOB2
style TAG fill:#b16286,stroke:#d3869b,color:#fbf1c7
style COMMIT1 fill:#076678,stroke:#83a598,color:#fbf1c7
style COMMIT2 fill:#076678,stroke:#83a598,color:#fbf1c7
style TREE1 fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style TREE2 fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style BLOB1 fill:#3c3836,stroke:#a89984,color:#ebdbb2
style BLOB2 fill:#3c3836,stroke:#a89984,color:#ebdbb2
style BLOB3 fill:#3c3836,stroke:#a89984,color:#ebdbb2
Object ทั้ง 4 ประเภท:
# วิธีที่ 1: ใช้ winget (Windows Package Manager)
winget install --id Git.Git -e --source winget
# วิธีที่ 2: ใช้ Chocolatey
choco install git
# วิธีที่ 3: ดาวน์โหลด Installer จาก https://git-scm.com/download/win
# เลือก Options ที่แนะนำ:
# - "Git from the command line and also from 3rd-party software"
# - "Use bundled OpenSSH"
# - "Use the OpenSSL library"
# - "Checkout Windows-style, commit Unix-style line endings" (CRLF → LF)
# - "Use Windows' default console window" หรือ MinTTY
# วิธีที่ 1: Homebrew (แนะนำ)
brew install git
# วิธีที่ 2: Xcode Command Line Tools
xcode-select --install
# วิธีที่ 3: MacPorts
sudo port install git
# ตรวจสอบเวอร์ชัน
git --version
# git version 2.44.0
# Ubuntu / Debian
sudo apt update && sudo apt install git -y
# Fedora / RHEL / CentOS
sudo dnf install git -y
# Arch Linux / Void Linux / Manjaro
sudo pacman -S git # Arch/Manjaro
sudo xbps-install -S git # Void Linux
# Alpine Linux
sudo apk add git
# ตรวจสอบเวอร์ชัน
git --version
# ===== ตั้งค่า Global (ใช้กับทุก Repository) =====
# ชื่อผู้ใช้ (จะปรากฏใน Commit)
git config --global user.name "Jonathan Quatermain"
# อีเมล (ควรตรงกับ GitHub/GitLab)
git config --global user.email "jonnyq@bigtech.com"
# Text Editor เริ่มต้น
git config --global core.editor "vim" # Vim
git config --global core.editor "nano" # Nano
git config --global core.editor "code --wait" # VS Code
# Default Branch Name (แนะนำ: main แทน master)
git config --global init.defaultBranch main
# ดูการตั้งค่าทั้งหมด
git config --global --list
# ดูไฟล์ config โดยตรง (~/.gitconfig)
cat ~/.gitconfig
ตัวอย่าง ~/.gitconfig ที่สมบูรณ์:
[user]
name = Jonathan Quatermain
email = jonnyq@bigtech.com
signingkey = ABCDEF1234567890
[core]
editor = code --wait
autocrlf = input # Linux/macOS: input, Windows: true
whitespace = fix
excludesfile = ~/.gitignore_global
[init]
defaultBranch = main
[pull]
rebase = false # merge (ค่าเริ่มต้น)
[push]
default = current # push branch ปัจจุบันไป remote เสมอ
[commit]
gpgsign = true # เซ็น GPG ทุก Commit
[alias]
st = status
co = checkout
sw = switch
br = branch
lg = log --oneline --graph --decorate --all
unstage = restore --staged
last = log -1 HEAD
# ===== 1. สร้าง SSH Key Pair =====
ssh-keygen -t ed25519 -C "jonnyq@bigtech.com"
# หรือ RSA 4096 bits (สำหรับระบบเก่า)
ssh-keygen -t rsa -b 4096 -C "jonnyq@bigtech.com"
# บันทึกที่: ~/.ssh/id_ed25519 (private key)
# ~/.ssh/id_ed25519.pub (public key)
# ===== 2. เพิ่ม Key เข้า ssh-agent =====
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# ===== 3. คัดลอก Public Key =====
cat ~/.ssh/id_ed25519.pub
# นำไปวางที่ GitHub: Settings → SSH and GPG keys → New SSH key
# ===== 4. ทดสอบการเชื่อมต่อ =====
ssh -T git@github.com
# Hi attapon! You've successfully authenticated...
# ===== 5. Clone ด้วย SSH =====
git clone git@github.com:username/repo.git
# สร้าง PAT ที่: GitHub → Settings → Developer settings → Personal access tokens
# เลือก Scope: repo, workflow, read:org
# ===== วิธีที่ 1: เก็บ Credential ด้วย Git Credential Manager =====
# ติดตั้ง git-credential-manager
git config --global credential.helper manager
# ===== วิธีที่ 2: เก็บไว้ใน Keychain (macOS) =====
git config --global credential.helper osxkeychain
# ===== วิธีที่ 3: Cache ชั่วคราว (1 ชั่วโมง) =====
git config --global credential.helper 'cache --timeout=3600'
# ===== วิธีที่ 4: ฝัง Token ใน URL (ไม่แนะนำ ใช้เฉพาะ CI/CD) =====
git clone https://<TOKEN>@github.com/username/repo.git
# Clone ด้วย HTTPS + PAT
git clone https://github.com/username/repo.git
# Username: attapon
# Password: <PAT_TOKEN>
.gitattributes# ===== .gitattributes สำหรับโปรเจกต์ข้ามแพลตฟอร์ม =====
# กำหนด line ending อัตโนมัติ
* text=auto
# ไฟล์ Text: ให้ Git จัดการ line ending
*.py text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.jsx text eol=lf
*.tsx text eol=lf
*.html text eol=lf
*.css text eol=lf
*.md text eol=lf
*.json text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.sh text eol=lf
# ไฟล์ Windows Script: ใช้ CRLF
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# ไฟล์ Binary: ไม่แก้ไข line ending
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
*.tar binary
*.gz binary
*.7z binary
*.mp4 binary
*.mp3 binary
# Git LFS (Large File Storage)
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
# Export-ignore (ไม่รวมใน git archive)
.gitattributes export-ignore
.gitignore export-ignore
.github/ export-ignore
tests/ export-ignore
# ===== Alias ที่มีประโยชน์ =====
# แสดง log แบบสวยงาม
git config --global alias.lg \
"log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# Status แบบย่อ
git config --global alias.st "status -sb"
# Undo last commit (เก็บไฟล์ไว้)
git config --global alias.undo "reset HEAD~1 --mixed"
# List all aliases
git config --global alias.aliases "config --get-regexp alias"
# Push current branch
git config --global alias.pushup "push -u origin HEAD"
# Delete merged branches
git config --global alias.cleanup \
"!git branch --merged | grep -v '\\*\\|main\\|develop' | xargs -n 1 git branch -d"
# ===== git init: สร้าง Repository ใหม่ =====
mkdir my-project && cd my-project
git init
# Initialized empty Git repository in /path/to/my-project/.git/
# สร้างพร้อมกำหนด branch name
git init --initial-branch=main
# ===== git clone: คัดลอก Repository จาก Remote =====
# Clone ปกติ
git clone git@github.com:username/repo.git
# Clone ไปยัง Directory ชื่อที่ต้องการ
git clone git@github.com:username/repo.git my-custom-name
# Shallow Clone (เฉพาะ 1 commit ล่าสุด ใช้กับ Repo ขนาดใหญ่)
git clone --depth=1 git@github.com:username/repo.git
# Clone เฉพาะ Branch ที่ต้องการ
git clone --branch develop git@github.com:username/repo.git
# Clone พร้อม Submodules
git clone --recurse-submodules git@github.com:username/repo.git
git status และการอ่านผลลัพธ์# แสดง Status แบบเต็ม
git status
# แสดง Status แบบสั้น (-s = short, -b = branch)
git status -sb
ตัวอย่างผลลัพธ์และความหมาย:
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed: ← ไฟล์ใน Staging Area (พร้อม Commit)
(use "git restore --staged <file>..." to unstage)
modified: README.md ← M = Modified
new file: src/app.py ← A = Added
Changes not staged for commit: ← ไฟล์เปลี่ยนแปลงแต่ยังไม่ได้ add
(use "git add <file>..." to update what will be committed)
modified: config.json ← แก้ไขแล้วแต่ไม่ได้ stage
Untracked files: ← ไฟล์ใหม่ที่ Git ยังไม่รู้จัก
(use "git add <file>..." to include in what will be committed)
notes.txt
รหัสสถานะแบบย่อ (git status -s):
| รหัส | ความหมาย |
|---|---|
M |
Modified, staged |
M |
Modified, not staged |
A |
Added (new file), staged |
D |
Deleted, staged |
D |
Deleted, not staged |
R |
Renamed, staged |
?? |
Untracked file |
!! |
Ignored file |
git add และ git commit# ===== git add: เพิ่มไฟล์เข้า Staging Area =====
# Add ไฟล์เดียว
git add README.md
# Add ไฟล์หลายไฟล์
git add src/app.py src/utils.py
# Add ทั้ง Directory
git add src/
# Add ทุกไฟล์ (รวม Untracked ใหม่)
git add .
# Add ทุกไฟล์ที่ Git รู้จัก (ไม่รวม Untracked)
git add -u
# ===== Add แบบ Interactive Patch (-p / --patch) =====
# เลือก Hunk (ส่วนย่อย) ของการเปลี่ยนแปลงทีละส่วน
git add --patch src/app.py
# ตัวเลือก: y=yes, n=no, s=split, e=edit, q=quit, ?=help
# ===== git commit: บันทึก Snapshot =====
# Commit พร้อม message
git commit -m "feat: add user authentication module"
# Commit พร้อมเปิด Editor สำหรับ message ยาว
git commit
# Add + Commit ในขั้นตอนเดียว (เฉพาะไฟล์ที่ tracked)
git commit -am "fix: correct typo in README"
# Commit แบบ Verbose (แสดง diff ใน editor)
git commit -v
รูปแบบ Conventional Commits:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
ประเภท (Type) ที่ใช้บ่อย:
| Type | ความหมาย | ตัวอย่าง |
|---|---|---|
feat |
เพิ่ม Feature ใหม่ | feat(auth): add OAuth2 login |
fix |
แก้ไข Bug | fix(api): handle null response |
docs |
แก้ไข Documentation | docs: update README installation |
style |
แก้ไข Formatting (ไม่เปลี่ยน Logic) | style: format with black |
refactor |
Refactor โค้ด | refactor(db): extract query builder |
test |
เพิ่ม/แก้ไข Test | test: add unit tests for auth |
chore |
งาน Maintenance | chore: update dependencies |
perf |
ปรับปรุง Performance | perf: cache database queries |
ci |
แก้ไข CI/CD Config | ci: add deployment workflow |
build |
แก้ไข Build System | build: migrate to webpack 5 |
ตัวอย่าง Commit Message ที่ดี:
feat(user): implement JWT token refresh mechanism
- Add RefreshToken model with expiry tracking
- Implement /auth/refresh endpoint
- Auto-rotate refresh tokens on use (token rotation)
- Add Redis caching for blacklisted tokens
Closes #142
BREAKING CHANGE: RefreshToken endpoint now requires Authorization header
git log และการกรอง# ===== รูปแบบการแสดงผล =====
# Log แบบเต็ม
git log
# Log แบบย่อ (SHA + message)
git log --oneline
# Log แบบ Graph สวยงาม
git log --oneline --graph --decorate --all
# Log พร้อม Stats (จำนวนบรรทัดที่เปลี่ยน)
git log --stat
# Log พร้อม Diff ทุก Commit
git log -p
# ===== การกรอง (Filtering) =====
# กรองตาม Author
git log --author="Attapon"
# กรองตามวันที่
git log --since="2024-01-01" --until="2024-12-31"
git log --since="2 weeks ago"
# กรองตาม Message
git log --grep="feat"
# กรองตาม File
git log -- src/app.py
# ค้นหาว่า Code บรรทัดไหนถูกเพิ่ม/ลบ (Pickaxe)
git log -S "def authenticate"
# แสดงเฉพาะ N commits ล่าสุด
git log -5
# ===== Format ที่กำหนดเอง =====
git log --pretty=format:"%h | %an | %ad | %s" --date=short
ตัวอย่างผลลัพธ์ git log --oneline --graph:
* f3e4d5a (HEAD -> main, origin/main) feat: add dashboard component
* 9a8b7c3 Merge pull request #42 from feature/auth
|\
| * 2b3c4d1 feat(auth): implement JWT refresh
| * 1a2b3c4 feat(auth): add login endpoint
|/
* 8e9f0a1 fix: correct CORS headers
* 7d8e9f0 chore: update dependencies
git diff# ===== ความแตกต่างระหว่างพื้นที่ต่างๆ =====
# Working Directory vs Staging Area (ยังไม่ได้ add)
git diff
# Staging Area vs Last Commit (สิ่งที่จะ commit)
git diff --staged
git diff --cached # เหมือนกัน
# Working Directory vs Last Commit (ทุกการเปลี่ยนแปลง)
git diff HEAD
# เปรียบเทียบระหว่าง 2 Commits
git diff abc1234 def5678
# เปรียบเทียบระหว่าง 2 Branches
git diff main feature/auth
# ดูเฉพาะชื่อไฟล์ที่เปลี่ยน (ไม่แสดง content)
git diff --name-only HEAD~3
# สรุปสถิติการเปลี่ยนแปลง
git diff --stat HEAD~1
.gitignore: ไฟล์ที่ไม่ต้อง Track# ===== ตัวอย่าง .gitignore สำหรับโปรเจกต์ Python/Web =====
# ===== Python =====
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/
.eggs/
*.egg
# Virtual Environments
venv/
env/
.venv/
.env/
# ===== Node.js =====
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# ===== IDEs =====
.vscode/
.idea/
*.swp
*.swo
*~
# ===== OS Files =====
.DS_Store # macOS
Thumbs.db # Windows
desktop.ini # Windows
# ===== Environment Variables (สำคัญมาก!) =====
.env
.env.local
.env.production
*.pem
*.key
# ===== Logs & Database =====
*.log
logs/
*.sqlite
*.db
# ===== Build Output =====
dist/
build/
.next/
.nuxt/
# ตรวจสอบว่าไฟล์ถูก ignore หรือไม่
git check-ignore -v secret.txt
# Global gitignore (ใช้กับทุก Repository บน Machine)
git config --global core.excludesfile ~/.gitignore_global
# Force add ไฟล์ที่ถูก ignore (ไม่แนะนำ)
git add -f important.env
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
gitGraph
commit id: "c1: init"
commit id: "c2: add README"
branch feature/login
checkout feature/login
commit id: "c3: add login form"
commit id: "c4: add auth logic"
checkout main
commit id: "c5: fix typo"
branch hotfix/bug-42
checkout hotfix/bug-42
commit id: "c6: fix null pointer"
checkout main
merge hotfix/bug-42 id: "Merge hotfix"
checkout feature/login
commit id: "c7: add tests"
checkout main
merge feature/login id: "Merge feature"
Branch คือ pointer เบา (lightweight pointer) ที่ชี้ไปยัง Commit ล่าสุด ขนาดเพียง 41 bytes (SHA-1 hash + newline) ทำให้การสร้าง/ลบ Branch ใน Git เร็วมาก
HEAD คือ pointer ที่บอกว่า "เราอยู่ที่ไหน" ในปัจจุบัน โดยปกติชี้ไป Branch ล่าสุด
# ===== ดู Branch =====
git branch # Local branches
git branch -r # Remote branches
git branch -a # All branches
# ===== สร้าง Branch =====
git branch feature/user-profile # สร้างแต่ไม่ switch
git switch -c feature/user-profile # สร้างและ switch (แนะนำ)
git checkout -b feature/user-profile # เหมือนกัน (เก่า)
# ===== Switch Branch =====
git switch main # เปลี่ยนไป main
git checkout main # เหมือนกัน (เก่า)
git switch - # กลับ Branch ก่อนหน้า
# ===== เปลี่ยนชื่อ Branch =====
git branch -m old-name new-name # เปลี่ยนชื่อ Local
git push origin -u new-name # Push branch ใหม่
git push origin --delete old-name # ลบ branch เก่าใน Remote
# ===== ลบ Branch =====
git branch -d feature/done # ลบหลัง Merge แล้ว (safe)
git branch -D feature/abandoned # ลบโดยไม่ต้อง Merge (force)
git push origin --delete feature/done # ลบจาก Remote
Before: After:
main: A─B main: A─B─C─D
→
feature: A─B─C─D (เพียง move pointer, ไม่มี Merge commit)
# Fast-forward merge (เกิดเมื่อ main ไม่มี commit ใหม่หลังแตก branch)
git switch main
git merge feature/simple-add
# บังคับไม่ให้ Fast-forward (สร้าง Merge commit เสมอ)
git merge --no-ff feature/simple-add
Before: After:
A─B─E (main) A─B─E─M (main)
\ → \ /
C─D (feature) C─D
# Three-way merge (เกิดเมื่อทั้งสอง branch มี commits ใหม่)
git switch main
git merge feature/user-auth
# Git จะสร้าง Merge commit อัตโนมัติ
# ===== สถานการณ์: เกิด Merge Conflict =====
git merge feature/profile
# Auto-merging src/user.py
# CONFLICT (content): Merge conflict in src/user.py
# Automatic merge failed; fix conflicts and then commit the result.
# ===== ดูไฟล์ที่มี Conflict =====
git status
# both modified: src/user.py
# ===== เปิดไฟล์และดู Conflict Markers =====
cat src/user.py
โครงสร้าง Conflict Markers:
<<<<<<< HEAD ← โค้ดจาก Branch ปัจจุบัน (main)
def get_user(id):
return db.query(User).filter_by(id=id).first()
======= ← เส้นแบ่ง
def get_user(user_id):
return User.query.get(user_id)
>>>>>>> feature/profile ← โค้ดจาก Branch ที่ Merge
# ===== แก้ไขด้วยมือ: เลือกโค้ดที่ต้องการ =====
# หลังแก้ไข ไฟล์จะมีแค่โค้ดที่ถูกต้อง
# ===== หรือใช้ mergetool =====
git mergetool # เปิด tool ที่ตั้งค่าไว้
git mergetool --tool=vimdiff # ใช้ vimdiff
git mergetool --tool=vscode # ใช้ VS Code
# ===== หลังแก้ไขเสร็จ =====
git add src/user.py
git commit # Git จะสร้าง merge commit message ให้อัตโนมัติ
# ===== ถ้าต้องการยกเลิก Merge =====
git merge --abort
git tag: การจัดการ Release# ===== Lightweight Tag (เหมือน branch ที่ไม่ขยับ) =====
git tag v1.0.0
# ===== Annotated Tag (แนะนำสำหรับ Release) =====
git tag -a v1.0.0 -m "Release version 1.0.0 - Initial stable release"
# Tag Commit ที่ผ่านมา
git tag -a v0.9.0 9a8b7c3 -m "Beta release"
# ดู Tags ทั้งหมด
git tag
git tag -l "v1.*" # กรองด้วย Pattern
# ดูข้อมูล Tag
git show v1.0.0
# Push Tags ไป Remote
git push origin v1.0.0 # Push tag เดียว
git push origin --tags # Push ทุก tag
git push origin --follow-tags # Push tags ที่ annotated พร้อม commit
# ลบ Tag
git tag -d v1.0.0-beta # ลบ Local
git push origin --delete v1.0.0-beta # ลบ Remote
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart TD
subgraph CLOUD["☁️ Remote Repositories"]
GH["GitHub\ngithub.com"]
GL["GitLab\ngitlab.com"]
BB["Bitbucket\nbitbucket.org"]
SELF["Self-hosted\nGitea/Forgejo"]
end
subgraph DEV1["👨💻 Developer 1 (Attapon)"]
L1["Local Repo\n(Full Clone)"]
W1["Working Dir"]
end
subgraph DEV2["👩💻 Developer 2 (Somchai)"]
L2["Local Repo\n(Full Clone)"]
W2["Working Dir"]
end
GH <-->|"push / fetch"| L1
GH <-->|"push / fetch"| L2
L1 <-->|"checkout / commit"| W1
L2 <-->|"checkout / commit"| W2
style CLOUD fill:#282828,stroke:#fabd2f,color:#ebdbb2
style DEV1 fill:#282828,stroke:#83a598,color:#ebdbb2
style DEV2 fill:#282828,stroke:#b8bb26,color:#ebdbb2
# ===== ดู Remote =====
git remote # แสดงชื่อ remote
git remote -v # แสดงชื่อ + URL
# ===== เพิ่ม Remote =====
git remote add origin git@github.com:username/repo.git
git remote add upstream git@github.com:original-owner/repo.git
# ===== เปลี่ยนชื่อ Remote =====
git remote rename origin old-origin
# ===== เปลี่ยน URL =====
git remote set-url origin git@github.com:new-username/repo.git
# ===== ลบ Remote =====
git remote remove upstream
# ===== ดูข้อมูล Remote โดยละเอียด =====
git remote show origin
# ===== git fetch: ดึงข้อมูลมาแต่ไม่ merge =====
git fetch origin # ดึงทุก branch จาก origin
git fetch origin main # ดึงเฉพาะ branch main
git fetch --all # ดึงจากทุก remote
git fetch --prune # ลบ remote-tracking branches ที่ถูกลบแล้ว
# ===== git pull: fetch + merge (หรือ rebase) =====
git pull # pull จาก upstream ที่ตั้งไว้
git pull origin main # ระบุ remote และ branch
git pull --rebase # ใช้ rebase แทน merge
git pull --ff-only # เฉพาะ fast-forward (ปลอดภัยกว่า)
# ===== git push: ส่งโค้ดขึ้น Remote =====
git push origin main # push branch main
git push -u origin feature/auth # push + ตั้ง upstream
git push --force-with-lease # force push อย่างปลอดภัย
git push origin --delete old-branch # ลบ branch ใน remote
ความต่างระหว่าง fetch และ pull:
| คำสั่ง | สิ่งที่เกิดขึ้น | ความปลอดภัย |
|---|---|---|
git fetch |
ดาวน์โหลด commits ใหม่มาเก็บไว้ ไม่แตะ Working Directory | ✅ ปลอดภัยมาก |
git pull |
fetch + merge เข้า branch ปัจจุบัน | ⚠️ อาจเกิด conflict |
git pull --rebase |
fetch + rebase บน commits ใหม่ | ✅ ประวัติสะอาดกว่า |
# ดู Tracking configuration
git branch -vv
# * main f3e4d5a [origin/main] feat: add dashboard
# feature/ui 2b3c4d1 [origin/feature/ui: ahead 2] feat: button
# ตั้งค่า Upstream
git branch --set-upstream-to=origin/main main
git push -u origin feature/auth # -u = --set-upstream
# ดู Remote-tracking branches
git branch -r
# origin/main
# origin/develop
# origin/feature/auth
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
sequenceDiagram
participant Dev as 👨💻 Developer
participant Local as 💻 Local Repo
participant Remote as ☁️ GitHub/GitLab
participant Reviewer as 👀 Code Reviewer
participant CI as 🤖 CI/CD
Dev->>Local: git switch -c feature/new-api
Dev->>Local: [แก้โค้ด + commit หลายครั้ง]
Dev->>Remote: git push -u origin feature/new-api
Dev->>Remote: เปิด Pull Request
Remote->>CI: Trigger: run tests
CI-->>Remote: ✅ Tests Passed
Remote->>Reviewer: แจ้งเตือน Review
Reviewer->>Remote: Comment + Request Changes
Dev->>Local: แก้ไขตาม feedback
Dev->>Remote: git push (update PR)
Reviewer->>Remote: ✅ Approve
Remote->>Remote: Merge PR → main
Remote->>CI: Trigger: deploy to production
# ตัวอย่าง GitHub Branch Protection (main branch)
# Settings → Branches → Add rule
Branch name pattern: main
✅ Require a pull request before merging
✅ Require approvals: 2
✅ Dismiss stale pull request approvals when new commits are pushed
✅ Require review from Code Owners
✅ Require status checks to pass before merging
✅ Require branches to be up to date before merging
Status checks: [ci/tests, ci/lint, security/scan]
✅ Require conversation resolution before merging
✅ Require signed commits
✅ Include administrators
✅ Restrict who can push to matching branches
[DevOps Team, Release Managers]
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
gitGraph
commit id: "init" tag: "v0.1.0"
branch develop
checkout develop
commit id: "setup CI"
branch feature/login
checkout feature/login
commit id: "add login UI"
commit id: "add auth API"
checkout develop
merge feature/login id: "merge login"
branch feature/dashboard
checkout feature/dashboard
commit id: "add dashboard"
checkout develop
merge feature/dashboard id: "merge dashboard"
branch release/1.0.0
checkout release/1.0.0
commit id: "bump version"
commit id: "fix release bugs"
checkout main
merge release/1.0.0 id: "Release 1.0.0" tag: "v1.0.0"
checkout develop
merge release/1.0.0 id: "sync release"
checkout main
branch hotfix/security-patch
checkout hotfix/security-patch
commit id: "patch CVE-2024-001"
checkout main
merge hotfix/security-patch id: "Hotfix" tag: "v1.0.1"
checkout develop
merge hotfix/security-patch id: "sync hotfix"
ประเภท Branch ใน Git Flow:
| Branch | วัตถุประสงค์ | Merge เข้า | Merge จาก |
|---|---|---|---|
main |
Production code | - | release, hotfix |
develop |
Integration branch | - | feature, release, hotfix |
feature/* |
พัฒนา Feature | develop | develop |
release/* |
เตรียม Release | main + develop | develop |
hotfix/* |
แก้ Bug ด่วนใน Production | main + develop | main |
# ===== ใช้งาน git-flow extension =====
# ติดตั้ง: apt install git-flow / brew install git-flow
git flow init # เริ่มต้น Git Flow ใน Repo
git flow feature start user-profile # สร้าง feature branch
git flow feature finish user-profile # Merge กลับ develop
git flow release start 1.2.0 # สร้าง release branch
git flow release finish 1.2.0 # Merge ไป main + develop + tag
git flow hotfix start critical-fix # สร้าง hotfix branch
git flow hotfix finish critical-fix # Merge ไป main + develop + tag
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart LR
A["1️⃣ Create Branch\nจาก main"] --> B["2️⃣ Add Commits\n(พัฒนา Feature)"]
B --> C["3️⃣ Open Pull Request\n(ขอ Review)"]
C --> D{"4️⃣ Review\nผ่าน?"}
D -->|"❌ แก้ไข"| B
D -->|"✅ Approve"| E["5️⃣ Merge to main"]
E --> F["6️⃣ Deploy\n(อัตโนมัติ)"]
style A fill:#076678,stroke:#83a598,color:#fbf1c7
style B fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style C fill:#d79921,stroke:#fabd2f,color:#282828
style D fill:#3c3836,stroke:#a89984,color:#ebdbb2
style E fill:#b16286,stroke:#d3869b,color:#fbf1c7
style F fill:#cc241d,stroke:#fb4934,color:#fbf1c7
กฎของ GitHub Flow:
main พร้อม Deploy เสมอmain (trunk) ─── A ── B ── C ── D ── E ──→
↑ ↑ ↑ ↑ ↑
short-lived branches (< 1 วัน)
หลักการ Trunk-based Development:
main โดยตรง หรือผ่าน Branch อายุสั้นมาก (< 1 วัน)# ตัวอย่าง Feature Flag
import os
FEATURE_FLAGS = {
"new_payment_flow": os.getenv("FF_NEW_PAYMENT", "false") == "true",
"ai_recommendations": os.getenv("FF_AI_RECS", "false") == "true",
}
def process_payment(order):
if FEATURE_FLAGS["new_payment_flow"]:
return new_payment_processor(order)
else:
return legacy_payment_processor(order)
| เกณฑ์ | Git Flow | GitHub Flow | Trunk-based |
|---|---|---|---|
| ความซับซ้อน | สูง | ต่ำ | ต่ำ-กลาง |
| ขนาดทีม | ขนาดกลาง-ใหญ่ | ทุกขนาด | ขนาดกลาง-ใหญ่ |
| Release Frequency | Scheduled | Continuous | Continuous |
| เหมาะกับ | Software แบบ Versioned | Web Apps | Tech Startups/DevOps |
| ความยากในการ Merge | สูง | ต่ำ | ต่ำ (merge บ่อย) |
| Long-lived branches | ✅ | ❌ | ❌ |
| Feature Flags | ไม่จำเป็น | ไม่จำเป็น | จำเป็น |
รูปแบบ: MAJOR.MINOR.PATCH เช่น 2.4.1
# Conventional Commits → SemVer mapping:
# fix: → PATCH (1.0.0 → 1.0.1)
# feat: → MINOR (1.0.0 → 1.1.0)
# BREAKING CHANGE: → MAJOR (1.0.0 → 2.0.0)
git rebase: การจัดเรียง Commit ใหม่Before rebase: After rebase:
feature feature
↓ ↓
A─B─C─E (main) A─B─C─E─D'─F' (main)
↘ (reapplied)
D─F (feature)
# ===== Rebase feature branch บน main =====
git switch feature/user-profile
git rebase main
# ถ้าเกิด Conflict:
# 1. แก้ไข conflict
# 2. git add .
# 3. git rebase --continue
# หรือยกเลิก: git rebase --abort
-i)# Rebase 5 commits ล่าสุดแบบ interactive
git rebase -i HEAD~5
# เปิด Editor:
# pick f3e4d5a feat: add login form
# pick 9a8b7c3 fix typo
# pick 2b3c4d1 fix another typo
# pick 1a2b3c4 fix yet another typo
# pick 8e9f0a1 feat: add dashboard
# คำสั่งที่ใช้บ่อย:
# pick = ใช้ commit นี้ตามเดิม
# reword = ใช้ commit นี้แต่แก้ message
# edit = หยุดเพื่อแก้ไข commit
# squash = รวมกับ commit ก่อนหน้า (เก็บ messages)
# fixup = รวมกับ commit ก่อนหน้า (ทิ้ง message)
# drop = ลบ commit นี้
# ตัวอย่าง: Squash 4 commits ล่าสุดเป็น 1
# แก้ Editor เป็น:
# pick f3e4d5a feat: add login form
# fixup 9a8b7c3 fix typo
# fixup 2b3c4d1 fix another typo
# fixup 1a2b3c4 fix yet another typo
# pick 8e9f0a1 feat: add dashboard
git cherry-pick# นำ commit เดียวมาใช้ใน branch ปัจจุบัน
git cherry-pick abc1234
# Cherry-pick หลาย commits
git cherry-pick abc1234 def5678
# Cherry-pick range ของ commits
git cherry-pick abc1234..def5678
# Cherry-pick โดยไม่ commit ทันที (ให้ไปแก้ก่อน)
git cherry-pick --no-commit abc1234
# ===== เมื่อไรควรใช้ cherry-pick =====
# ✅ นำ hotfix จาก main ไปใส่ใน release branch
# ✅ นำ feature เล็กๆ ข้าม branch
# ✅ กู้คืน commit ที่ถูก revert โดยไม่ต้องการ
#
# ❌ ไม่ควรใช้แทน merge/rebase เมื่อทำงานกับ feature ทั้งหมด
# ❌ หลีกเลี่ยงการ cherry-pick บน shared branch
git stash: พักงานชั่วคราว# ===== บันทึก Stash =====
git stash # stash ทุกอย่าง
git stash push -m "WIP: auth fixes" # stash พร้อม message
git stash --include-untracked # รวม untracked files
git stash --all # รวม ignored files ด้วย
# ===== ดู Stash List =====
git stash list
# stash@{0}: On main: WIP: auth fixes
# stash@{1}: WIP on feature/ui: 9a8b7c3 add button
# ===== นำ Stash กลับมา =====
git stash pop # เอา stash@{0} มา + ลบออกจาก list
git stash apply stash@{1} # เอา stash@{1} มา แต่ไม่ลบ
git stash pop --index # restore staging area ด้วย
# ===== ดูเนื้อหา Stash =====
git stash show stash@{0} # summary
git stash show -p stash@{0} # full diff
# ===== ลบ Stash =====
git stash drop stash@{0} # ลบ stash นี้
git stash clear # ลบทั้งหมด
# ===== สร้าง Branch จาก Stash =====
git stash branch feature/new-idea stash@{0}
git commit --amend# ===== แก้ไข Commit ล่าสุด =====
# แก้ Commit Message อย่างเดียว
git commit --amend -m "feat: add user authentication with JWT"
# เพิ่มไฟล์ที่ลืมไว้ใน Commit ล่าสุด
git add forgotten-file.py
git commit --amend --no-edit # ไม่เปลี่ยน message
# ⚠️ อย่า amend commit ที่ push ขึ้น shared branch แล้ว!
# ถ้าจำเป็นต้อง push: git push --force-with-lease
git bisect: ค้นหา Bug ด้วย Binary Searchโดยที่ n คือจำนวน Commits ระหว่าง good และ bad commit หากมี 1024 commits ใช้เพียง 10 ขั้นตอน
# ===== เริ่ม Bisect =====
git bisect start
# บอก Git ว่า Commit ปัจจุบัน (HEAD) มี Bug
git bisect bad
# บอก Git ว่า Commit นี้ยังดีอยู่ (ก่อนที่ Bug จะเกิด)
git bisect good v1.2.0
# Git จะ checkout ไปยัง Commit กลาง
# ทดสอบ → แจ้งผล:
git bisect good # ถ้า Bug ยังไม่ปรากฏ
git bisect bad # ถ้า Bug ปรากฏ
# ทำซ้ำจนกว่า Git จะบอก commit ที่ทำให้เกิด Bug
# ===== Automated Bisect (ใช้ Script) =====
git bisect start HEAD v1.2.0
git bisect run python test_login.py # script return 0=good, nonzero=bad
# ===== จบ Bisect =====
git bisect reset # กลับสู่ HEAD เดิม
git worktree: ทำงานหลาย Branch พร้อมกัน# สร้าง Working Tree ใหม่สำหรับ Branch อื่น
git worktree add ../hotfix-branch hotfix/critical-fix
# ดู Worktrees ทั้งหมด
git worktree list
# ลบ Worktree
git worktree remove ../hotfix-branch
# ===== ประโยชน์ =====
# - รีวิว PR ใน directory แยก โดยไม่ต้อง stash งานปัจจุบัน
# - Fix hotfix ใน window แยก ขณะที่ยังพัฒนา feature อยู่
# - Build/Test หลาย branch พร้อมกัน
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart TD
Q["ต้องการ Undo อะไร?"]
Q --> A{"ไฟล์ใน\nWorking Dir"}
Q --> B{"ไฟล์ใน\nStaging Area"}
Q --> C{"Commit\nล่าสุด"}
Q --> D{"หลาย Commits\n(Private branch)"}
Q --> E{"Commits บน\nShared branch"}
A --> A1["git restore <file>\ngit checkout -- <file>"]
B --> B1["git restore --staged <file>\ngit reset HEAD <file>"]
C --> C1["git commit --amend"]
D --> D1["git reset --hard HEAD~N\n(ลบ commits ทิ้ง)"]
E --> E1["git revert HEAD\n(สร้าง commit กลับ)"]
style Q fill:#d79921,stroke:#fabd2f,color:#282828
style A1 fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style B1 fill:#427b58,stroke:#8ec07c,color:#fbf1c7
style C1 fill:#076678,stroke:#83a598,color:#fbf1c7
style D1 fill:#cc241d,stroke:#fb4934,color:#fbf1c7
style E1 fill:#b16286,stroke:#d3869b,color:#fbf1c7
git restore# ===== ยกเลิกการแก้ไขไฟล์ใน Working Directory =====
git restore README.md # คืนค่าไฟล์จาก Staging
git restore . # คืนทุกไฟล์
git restore --source=HEAD~2 app.py # คืนเวอร์ชันจาก 2 commits ที่แล้ว
# ===== ยกเลิกการ Stage ไฟล์ =====
git restore --staged README.md # เอาออกจาก Staging Area
git restore --staged . # เอาทุกไฟล์ออกจาก Staging
# ===== ยกเลิกทั้ง Stage และ Working Dir =====
git restore --staged --worktree README.md
git reset# HEAD~1 = 1 commit ก่อน HEAD
# HEAD~3 = 3 commits ก่อน HEAD
# abc1234 = Commit hash ที่ต้องการ
# ===== --soft: ย้าย HEAD แต่เก็บไฟล์ไว้ใน Staging =====
git reset --soft HEAD~1
# → Commit หายไป แต่การเปลี่ยนแปลงยังอยู่ใน Staging (พร้อม Commit ใหม่)
# ===== --mixed: ย้าย HEAD และล้าง Staging (default) =====
git reset HEAD~1
git reset --mixed HEAD~1
# → Commit หายไป การเปลี่ยนแปลงกลับมาอยู่ใน Working Directory
# ===== --hard: ย้าย HEAD, ล้าง Staging, ล้าง Working Directory =====
git reset --hard HEAD~1
# ⚠️ อันตราย! การเปลี่ยนแปลงหายไปหมด ไม่สามารถกู้คืนได้ง่าย
# Reset ไปยัง Commit ที่ระบุ
git reset --hard abc1234
# ===== ตัวอย่างการใช้งาน =====
# Squash 3 commits สุดท้ายเป็น 1:
git reset --soft HEAD~3
git commit -m "feat: complete user authentication system"
git revert# สร้าง Commit ใหม่ที่กลับค่าการเปลี่ยนแปลงของ Commit ที่ระบุ
# ✅ ปลอดภัยสำหรับ Shared/Public branch เพราะไม่เขียนประวัติใหม่
# Revert commit ล่าสุด
git revert HEAD
# Revert commit เฉพาะ
git revert abc1234
# Revert หลาย commits (สร้างทีละ 1 commit)
git revert HEAD~3..HEAD
# Revert แบบ No-commit (จัดกลุ่มหลาย revert เป็น 1 commit)
git revert --no-commit HEAD~3..HEAD
git commit -m "revert: rollback last 3 commits due to breaking change"
# Revert merge commit (ต้องระบุ parent)
git revert -m 1 abc1234 # -m 1 = ใช้ parent แรก (mainline)
git reflog: กู้คืน Commit ที่หายไป# ===== reflog คือ log ของทุกการเคลื่อนไหว HEAD =====
git reflog
# HEAD@{0}: reset: moving to HEAD~3
# HEAD@{1}: commit: feat: add payment module
# HEAD@{2}: commit: feat: add cart feature
# HEAD@{3}: commit: feat: add product listing
# ===== กู้คืน Commit ที่ถูก reset --hard ไป =====
# 1. หา SHA ของ commit ที่ต้องการ
git reflog | grep "feat: add payment"
# 2. สร้าง branch จาก commit นั้น
git branch recovery/payment abc1234
# หรือ reset กลับไปยัง commit นั้น
git reset --hard HEAD@{2}
# ===== กู้คืน Branch ที่ถูกลบ =====
git reflog | grep "feature/deleted-branch"
git checkout -b feature/deleted-branch abc1234
| สถานการณ์ | คำสั่ง | ปลอดภัยใน Shared Branch | หมายเหตุ |
|---|---|---|---|
| ยกเลิกแก้ไขใน Working Dir | git restore <file> |
✅ | การเปลี่ยนแปลงหายถาวร |
| เอาไฟล์ออกจาก Staging | git restore --staged <file> |
✅ | ไม่กระทบ Working Dir |
| แก้ Commit Message ล่าสุด | git commit --amend |
❌ | ห้ามทำบน pushed commit |
| ลบ Commit ล่าสุด (เก็บไฟล์) | git reset --soft HEAD~1 |
❌ | ใช้เฉพาะ Local |
| ลบ Commit ล่าสุด (ทิ้งไฟล์) | git reset --hard HEAD~1 |
❌ | อันตราย! |
| กลับค่า Commit (Public) | git revert <hash> |
✅ | สร้าง commit ใหม่ |
| กู้คืน Commit ที่หายไป | git reflog + git reset |
⚠️ | ใช้ภายใน 30 วัน |
Git Hooks คือสคริปต์ที่ Git รันอัตโนมัติเมื่อเกิด Event บางอย่าง อยู่ที่ .git/hooks/
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart LR
subgraph CLIENT["💻 Client-side Hooks"]
direction TB
H1["pre-commit\n(ก่อน Commit)\nLint, Tests, Format"]
H2["prepare-commit-msg\n(สร้าง Message Template)"]
H3["commit-msg\n(ตรวจสอบ Message Format)"]
H4["post-commit\n(หลัง Commit)\nNotifications"]
H5["pre-push\n(ก่อน Push)\nRun Tests"]
H1 --> H2 --> H3 --> H4
end
subgraph SERVER["🖥️ Server-side Hooks"]
direction TB
S1["pre-receive\n(ก่อนรับ Push)"]
S2["update\n(ต่อ Branch)"]
S3["post-receive\n(หลังรับ Push)\nDeploy, Notify"]
S1 --> S2 --> S3
end
CLIENT -->|"git push"| SERVER
style CLIENT fill:#282828,stroke:#fabd2f,color:#ebdbb2
style SERVER fill:#282828,stroke:#83a598,color:#ebdbb2
#!/bin/bash
# .git/hooks/pre-commit (chmod +x)
# ===== ตรวจสอบ Code Style ก่อน Commit =====
echo "🔍 Running pre-commit checks..."
# 1. ตรวจ Python syntax
if git diff --cached --name-only | grep -q "\.py$"; then
echo " → Checking Python syntax..."
git diff --cached --name-only | grep "\.py$" | xargs python -m py_compile
if [ $? -ne 0 ]; then
echo "❌ Python syntax error found!"
exit 1
fi
fi
# 2. ตรวจ trailing whitespace
if git diff --cached | grep -q "^+.*[[:space:]]$"; then
echo "❌ Trailing whitespace found!"
git diff --cached | grep -n "^+.*[[:space:]]$"
exit 1
fi
echo "✅ Pre-commit checks passed!"
exit 0
#!/bin/bash
# .git/hooks/commit-msg (chmod +x)
# ===== ตรวจสอบ Conventional Commit format =====
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\(.+\))?: .{1,72}"
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
echo "❌ Commit message does not follow Conventional Commits format!"
echo ""
echo "Expected format: <type>(<scope>): <description>"
echo "Example: feat(auth): add JWT token validation"
echo ""
echo "Types: feat, fix, docs, style, refactor, test, chore, perf, ci, build"
exit 1
fi
echo "✅ Commit message format OK"
exit 0
# ===== ติดตั้ง =====
npm install --save-dev husky lint-staged
# เปิดใช้งาน Husky
npx husky init
// package.json
{
"scripts": {
"prepare": "husky"
},
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss}": [
"stylelint --fix",
"prettier --write"
],
"*.py": [
"black",
"flake8"
]
}
}
# .husky/pre-commit
#!/bin/sh
npx lint-staged
# .husky/commit-msg
#!/bin/sh
npx --no -- commitlint --edit $1
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'test', 'chore', 'perf', 'ci', 'build', 'revert'
]],
'subject-max-length': [2, 'always', 72]
}
}
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
PYTHON_VERSION: "3.11"
NODE_VERSION: "20"
jobs:
# ===== Job 1: Code Quality =====
lint:
name: 🔍 Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
pip install black flake8 mypy
pip install -r requirements.txt
- name: Run Black (formatter)
run: black --check .
- name: Run Flake8 (linter)
run: flake8 . --max-line-length=88
- name: Run MyPy (type checker)
run: mypy src/
# ===== Job 2: Tests =====
test:
name: 🧪 Run Tests
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: pip install -r requirements.txt -r requirements-dev.txt
- name: Run tests with coverage
run: |
pytest --cov=src --cov-report=xml --cov-fail-under=80
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
# ===== Job 3: Security Scan =====
security:
name: 🔒 Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Bandit (Python security linter)
run: |
pip install bandit
bandit -r src/ -f json -o bandit-report.json
# ===== Job 4: Deploy (เฉพาะ push ไป main) =====
deploy:
name: 🚀 Deploy to Production
runs-on: ubuntu-latest
needs: [lint, test, security]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- uses: actions/checkout@v4
- name: Deploy to server
run: |
echo "Deploying version ${{ github.sha }}"
# คำสั่ง deploy จริง
# ===== สร้าง GPG Key =====
gpg --full-generate-key
# เลือก: RSA and RSA (default), 4096 bits, 0 (ไม่หมดอายุ)
# กรอก Name, Email (ต้องตรงกับ git config)
# ดู Key ID
gpg --list-secret-keys --keyid-format=long
# sec rsa4096/ABCDEF1234567890 2024-01-01 [SC]
# Export Public Key สำหรับ GitHub
gpg --armor --export ABCDEF1234567890
# ตั้งค่า Git ให้ใช้ GPG Key นี้
git config --global user.signingkey ABCDEF1234567890
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Sign commit ด้วยตนเอง
git commit -S -m "feat: signed commit"
# ตรวจสอบ signature
git log --show-signature -1
git submodule vs git subtree
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart TD
subgraph MAIN["📦 Main Repository (my-app)"]
MC["src/ — Application Code"]
SM["lib/utils → .gitmodules\n(pointer to commit SHA)"]
ST["vendor/ui → copied code\n(embedded in repo)"]
end
subgraph SUB["🔗 Submodule"]
SR["utils-repo\n(แยก Repo แยก URL)"]
end
subgraph TREE["🌲 Subtree"]
TR["ui-library\n(merged history)"]
end
SM -->|"git submodule update"| SR
ST -.->|"git subtree pull"| TR
style MAIN fill:#282828,stroke:#fabd2f,color:#ebdbb2
style SUB fill:#282828,stroke:#cc241d,color:#ebdbb2
style TREE fill:#282828,stroke:#b8bb26,color:#ebdbb2
Submodule:
# ===== เพิ่ม Submodule =====
git submodule add git@github.com:team/utils.git lib/utils
git submodule add --branch stable git@github.com:team/ui.git lib/ui
# ===== Clone Repo ที่มี Submodule =====
git clone --recurse-submodules git@github.com:username/my-app.git
# หรือ (ถ้า clone ปกติแล้วลืม)
git submodule init
git submodule update
# ===== อัปเดต Submodule เป็นเวอร์ชันล่าสุด =====
git submodule update --remote lib/utils
git submodule update --remote --merge # merge การเปลี่ยนแปลง
# ===== ดู Status ของ Submodules =====
git submodule status
Subtree:
# ===== เพิ่ม Subtree =====
git remote add ui-lib git@github.com:team/ui-library.git
git subtree add --prefix=vendor/ui ui-lib main --squash
# ===== ดึง Update จาก Upstream =====
git subtree pull --prefix=vendor/ui ui-lib main --squash
# ===== Push การเปลี่ยนแปลงกลับ Upstream =====
git subtree push --prefix=vendor/ui ui-lib feature/fix-button
| เกณฑ์ | Submodule | Subtree |
|---|---|---|
| ประวัติ | แยกจาก Main Repo | รวมใน Main Repo |
| ความซับซ้อน | สูง | ต่ำกว่า |
| Clone | ต้องใช้ --recurse-submodules |
ปกติ |
| Contributor | ต้องรู้เรื่อง Submodule | ไม่จำเป็น |
| Contribute กลับ | ง่าย | ยากกว่า |
| เหมาะกับ | Dependency แยก Repo | Vendor code |
git lfs (Large File Storage)# ===== ติดตั้ง Git LFS =====
# Ubuntu: sudo apt install git-lfs
# macOS: brew install git-lfs
# Windows: winget install GitHub.GitLFS
git lfs install # เปิดใช้งานใน Git
# ===== Track ไฟล์ขนาดใหญ่ =====
git lfs track "*.psd" # Photoshop files
git lfs track "*.ai" # Illustrator files
git lfs track "*.mp4" # Video files
git lfs track "models/*.bin" # ML Model files
git lfs track "*.parquet" # Data files
# การ track จะสร้าง .gitattributes
git add .gitattributes
git commit -m "chore: add LFS tracking for large files"
# ===== ดู LFS Status =====
git lfs status
git lfs ls-files # ดูไฟล์ที่ track ด้วย LFS
# ===== ดู LFS Statistics =====
git lfs env
# ===== Migration: ย้ายไฟล์ที่มีอยู่เข้า LFS =====
git lfs migrate import --include="*.psd,*.ai" --everything
# ===== Shallow Clone: ดึงแค่ประวัติล่าสุด =====
git clone --depth=1 git@github.com:large-org/monorepo.git
git clone --depth=50 git@github.com:large-org/monorepo.git # 50 commits
# Deepen ภายหลังถ้าต้องการ
git fetch --unshallow
# ===== Sparse Checkout: ดึงเฉพาะส่วนที่ต้องการ (Monorepo) =====
git clone --filter=blob:none --sparse git@github.com:large-org/monorepo.git
cd monorepo
# กำหนด Directory ที่ต้องการ
git sparse-checkout set apps/frontend packages/ui libs/auth
# ดู Sparse Checkout Config
git sparse-checkout list
# เพิ่ม Pattern
git sparse-checkout add packages/shared
# ยกเลิก Sparse Checkout (ดึงทุกอย่าง)
git sparse-checkout disable
# ===== git gc (Garbage Collection) =====
# Git รัน gc อัตโนมัติ แต่สามารถรันเองได้
git gc # Garbage collection ปกติ
git gc --aggressive # Aggressive (ช้าแต่ compress ดีกว่า)
git gc --prune=now # ลบ unreachable objects ทันที
# ===== git prune =====
git prune # ลบ Objects ที่ไม่มีใครอ้างถึง
git prune --expire=now # ลบทันที (ไม่รอ Grace period)
# ===== ดูขนาด Repository =====
git count-objects -vH
# count: 0
# size: 0 bytes
# in-pack: 1234
# packs: 1
# size-pack: 45.23 MiB
# ===== ค้นหาไฟล์ขนาดใหญ่ใน History =====
git rev-list --objects --all |
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
awk '/^blob/ {print substr($0,6)}' |
sort --numeric-sort --key=2 --reverse |
head -20
# ===== ลบไฟล์ขนาดใหญ่ออกจาก History (BFG) =====
# ใช้ BFG Repo-Cleaner (เร็วกว่า git filter-branch)
java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git config --global user.name "Name"
git config --global user.email "email@example.com"
git config --global init.defaultBranch main
git config --global alias.lg "log --oneline --graph --all"
git init # สร้าง Local Repo
git clone <url> # Clone Remote Repo
git status -sb # ดูสถานะ
git add . # Stage ทุกอย่าง
git add -p # Stage แบบ Interactive
git commit -m "type: msg" # Commit
git commit --amend # แก้ Commit ล่าสุด
git push # Push ขึ้น Remote
git pull --rebase # Pull + Rebase
git switch -c feature/x # สร้าง + Switch branch
git switch main # Switch branch
git branch -d feature/x # ลบ branch (after merge)
git merge --no-ff feature/x # Merge พร้อม Merge commit
git rebase main # Rebase บน main
git rebase -i HEAD~5 # Interactive rebase
git log --oneline --graph --all # ดู History แบบ Graph
git diff HEAD # ทุกการเปลี่ยนแปลง
git diff --staged # สิ่งที่จะ Commit
git blame README.md # ดูว่าใครแก้บรรทัดไหน
git bisect start # เริ่มค้นหา Bug
git reflog # ดูทุกการเคลื่อนไหว
git restore <file> # ยกเลิกแก้ไขใน Working Dir
git restore --staged <file> # เอาออกจาก Staging
git reset --soft HEAD~1 # Undo commit (เก็บไฟล์)
git reset --hard HEAD~1 # Undo commit (ลบไฟล์) ⚠️
git revert HEAD # สร้าง Revert commit
git stash push -m "WIP" # พักงานชั่วคราว
git stash pop # ดึงงานที่พักกลับมา
หลักการ: แต่ละ Commit ควรทำสิ่งเดียวที่สมบูรณ์ในตัวเอง
❌ ไม่ดี:
- "fix lots of bugs and add new features and update docs"
✅ ดี:
- "fix(auth): resolve JWT expiry race condition"
- "feat(user): add profile picture upload"
- "docs: update API authentication guide"
feature/<issue-id>-<short-description>
fix/<issue-id>-<short-description>
hotfix/<version>-<short-description>
release/<version>
chore/<short-description>
docs/<short-description>
ตัวอย่าง:
feature/142-user-profile-picture
fix/201-null-pointer-in-auth
hotfix/1.2.1-security-patch
release/2.0.0
✅ ไฟล์ที่ต้องอยู่ใน .gitignore เสมอ:
- Secrets (.env, *.pem, *.key, credentials.json)
- Dependencies (node_modules/, venv/, vendor/)
- Build outputs (dist/, build/, *.pyc)
- IDE settings (.idea/, .vscode/ สำหรับ team projects)
- OS files (.DS_Store, Thumbs.db)
- Log files (*.log, logs/)
- Local config (*.local, *.override)
| Client | Platform | ฟรี/จ่าย | เหมาะกับ |
|---|---|---|---|
| GitKraken | Win/Mac/Linux | Freemium | Team collaboration |
| Fork | Win/Mac | จ่าย | Power users |
| Sourcetree | Win/Mac | ฟรี | Beginners |
| Tower | Win/Mac | จ่าย | Professional |
| GitHub Desktop | Win/Mac | ฟรี | GitHub users |
| VS Code (built-in) | All | ฟรี | Developers |
| IntelliJ/PyCharm | All | Freemium | JetBrains users |
| Lazygit | All | ฟรี | Terminal enthusiasts |
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#282828', 'primaryTextColor': '#ebdbb2', 'primaryBorderColor': '#504945', 'lineColor': '#a89984', 'background': '#282828', 'mainBkg': '#3c3836', 'fontFamily': 'monospace'}}}%%
flowchart TB
subgraph E1["📅 1972–2000: Before Git"]
T1["1972 — SCCS\nBell Labs"]
T2["1982 — RCS\nWalter Tichy"]
T3["1986 — CVS\nConcurrent Versions System"]
T4["2000 — SVN\nApache Subversion\n(ใช้กันแพร่หลาย)"]
T1 --> T2 --> T3 --> T4
end
subgraph E2["📅 2005: The Birth of Git"]
T5["เมษายน 2005\nLinus Torvalds สร้าง Git\n(ในสัปดาห์เดียว!)"]
T6["มิถุนายน 2005\nLinux Kernel ย้ายมาใช้ Git"]
T7["ธันวาคม 2005\nGit v1.0 Release"]
T5 --> T6 --> T7
end
subgraph E3["📅 2008–2015: Ecosystem Growth"]
T8["2008 — GitHub เปิดตัว"]
T9["2011 — GitLab เปิดตัว"]
T10["2012 — Bitbucket รองรับ Git"]
T11["2013 — GitHub ยอดผู้ใช้ 3M"]
T8 --> T9 --> T10 --> T11
end
subgraph E4["📅 2018–ปัจจุบัน: Enterprise & Scale"]
T12["2018 — Microsoft ซื้อ GitHub\n($7.5B)"]
T13["2020 — Default branch\nเปลี่ยนเป็น 'main'"]
T14["2022 — Git v2.39\nSparse Checkout ปรับปรุง"]
T15["2024 — Git 100M+ Users"]
T12 --> T13 --> T14 --> T15
end
E1 --> E2 --> E3 --> E4
style E1 fill:#3c3836,stroke:#a89984,color:#ebdbb2
style E2 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style E3 fill:#3c3836,stroke:#83a598,color:#ebdbb2
style E4 fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
📚 หนังสือ:
🌐 Interactive Learning:
📖 Reference:
🛠️ เครื่องมือเพิ่มเติม: