Git Handbook

11 · Git Labs

13 bài thực hành theo cấp độ. Các lab ưu tiên local-first để bạn có thể luyện Git thật sự thay vì chỉ đọc lý thuyết.

Workspace gợi ý: tạo thư mục riêng để tránh ảnh hưởng project thật: mkdir -p ~/git-labs && cd ~/git-labs.
Lab 01

Init → Add → Commit

Cơ bản

Mục tiêu: Hiểu ba vùng Working Tree / Index / HEAD.

rm -rf lab01 && mkdir lab01 && cd lab01
git init -b main
printf "# Git Lab
" > README.md
git status
git diff
git add README.md
git diff --staged
git commit -m "docs: add README"
git log --oneline

Kiểm tra kết quả

git status
# expected: working tree clean
Lab 02

.gitignore và tracked file

Cơ bản

Mục tiêu: Phân biệt ignore với untrack.

cd ~/git-labs
rm -rf lab02 && mkdir lab02 && cd lab02
git init -b main
printf "SECRET=demo
" > .env
git add .env && git commit -m "chore: accidentally track env"
printf ".env
" > .gitignore
git status
# .env vẫn tracked!
git rm --cached .env
git add .gitignore
git commit -m "chore: stop tracking env"

Kiểm tra kết quả

git status --ignored
# .env phải hiện ignored, không tracked
Lab 03

Branch + Fast-forward + Merge commit

Cơ bản

Mục tiêu: Nhìn commit graph và phân biệt hai kiểu merge.

cd ~/git-labs
rm -rf lab03 && mkdir lab03 && cd lab03
git init -b main
echo base > app.txt
git add . && git commit -m "init"
git switch -c feature/a
echo feature-a >> app.txt
git commit -am "feat: A"
git switch main
git merge feature/a

git switch -c feature/b
echo feature-b > b.txt
git add . && git commit -m "feat: B"
git switch main
echo main-change > main.txt
git add . && git commit -m "chore: main change"
git merge --no-ff feature/b -m "merge feature/b"
git log --oneline --graph --decorate --all

Kiểm tra kết quả

git log --graph --oneline --all
# tìm một fast-forward và một merge commit
Lab 04

Tạo và resolve merge conflict

Trung bình

Mục tiêu: Tự tay tạo conflict, đọc markers và resolve.

cd ~/git-labs
rm -rf lab04 && mkdir lab04 && cd lab04
git init -b main
echo "MODE=base" > config.env
git add . && git commit -m "init config"
git switch -c feature/config
echo "MODE=staging" > config.env
git commit -am "feat: staging mode"
git switch main
echo "MODE=production" > config.env
git commit -am "chore: production mode"
git merge feature/config
# conflict expected
cat config.env
# sửa file thành giá trị bạn quyết định
echo "MODE=production" > config.env
git add config.env
git commit -m "merge: resolve config mode"

Kiểm tra kết quả

git status
git log --graph --oneline --all
Lab 05

Collaboration local: bare remote + 2 developer

Trung bình

Mục tiêu: Luyện fetch, push rejection và integrate mà không cần GitHub.

cd ~/git-labs
rm -rf lab05 && mkdir lab05 && cd lab05
git init --bare central.git
git clone central.git developer-a
git clone central.git developer-b

cd developer-a
git switch -c main
echo "A init" > shared.txt
git add . && git commit -m "init by A"
git push -u origin main

cd ../developer-b
git fetch origin
git switch -c main --track origin/main
echo "B change" >> shared.txt
git commit -am "feat: change by B"
git push

cd ../developer-a
echo "A second" >> shared.txt
git commit -am "feat: second change by A"
git push
# expected rejection because B pushed first
git fetch origin
git log --oneline --graph --decorate --all
# integrate theo cách bạn chọn:
git rebase origin/main
# resolve nếu có conflict
git push

Kiểm tra kết quả

git log --oneline --graph --decorate --all
# local main và origin/main phải cùng tip sau push
Lab này mô phỏng collaboration gần thực tế nhất mà không phụ thuộc network.
Lab 06

Stash WIP

Cơ bản

Mục tiêu: Tạm cất thay đổi tracked + untracked và phục hồi.

cd ~/git-labs
rm -rf lab06 && mkdir lab06 && cd lab06
git init -b main
echo base > app.txt
git add . && git commit -m init
echo wip >> app.txt
echo new > temp.txt
git stash push -u -m "WIP demo"
git status
git stash list
git stash show -p stash@{0}
git stash pop

Kiểm tra kết quả

git status
# app.txt modified + temp.txt untracked phải quay lại
Lab 07

Reset soft/mixed/hard vs Revert

Trung bình

Mục tiêu: Quan sát chính xác mỗi mode tác động lên HEAD/Index/Working Tree.

cd ~/git-labs
rm -rf lab07 && mkdir lab07 && cd lab07
git init -b main
echo 1 > number.txt
git add . && git commit -m one
echo 2 > number.txt
git commit -am two

git reset --soft HEAD~1
git status
# commit lại
git commit -m two

git reset HEAD~1
git status
git add . && git commit -m two

# tạo commit 3 rồi revert
echo 3 > number.txt
git commit -am three
git revert HEAD --no-edit
git log --oneline

Kiểm tra kết quả

cat number.txt
git log --oneline
# commit "three" vẫn tồn tại, sau nó có revert commit
Lab 08

Recovery bằng reflog

Trung bình

Mục tiêu: Cố tình reset --hard rồi khôi phục commit.

cd ~/git-labs
rm -rf lab08 && mkdir lab08 && cd lab08
git init -b main
for n in 1 2 3; do echo $n > value.txt; git add .; git commit -m "value $n"; done
git log --oneline
git reset --hard HEAD~2
git log --oneline
git reflog
# lấy SHA của commit value 3 rồi:
git switch -c recovery <SHA_VALUE_3>

Kiểm tra kết quả

cat value.txt
# expected: 3
git log --oneline --all --graph
Thay <SHA_VALUE_3> bằng SHA thật từ reflog.
Lab 09

Interactive rebase: squash/fixup/reword

Nâng cao

Mục tiêu: Làm sạch history feature branch.

cd ~/git-labs
rm -rf lab09 && mkdir lab09 && cd lab09
git init -b main
echo base > app.txt; git add .; git commit -m init
echo feature >> app.txt; git commit -am "feat: add feature"
echo typo >> app.txt; git commit -am "fix typo"
echo debug >> app.txt; git commit -am "debug temporary"
git log --oneline
# chạy editor interactive:
git rebase -i HEAD~3
# thử: pick commit feat, fixup typo, reword debug (hoặc drop nếu muốn)
git log --oneline

Kiểm tra kết quả

git log --oneline
# history mới phải phản ánh action bạn đã chọn
Lab 10

Cherry-pick hotfix

Trung bình

Mục tiêu: Lấy một commit độc lập sang release branch.

cd ~/git-labs
rm -rf lab10 && mkdir lab10 && cd lab10
git init -b main
echo base > app.txt; git add .; git commit -m init
git branch release
git switch -c hotfix
echo fix >> app.txt
git commit -am "fix: urgent patch"
FIX_SHA=$(git rev-parse HEAD)
git switch release
git cherry-pick "$FIX_SHA"
git log --oneline --all --graph

Kiểm tra kết quả

cat app.txt
# release phải chứa fix
Lab 11

Bisect tìm commit gây bug

Nâng cao

Mục tiêu: Dùng binary search thay vì check từng commit.

cd ~/git-labs
rm -rf lab11 && mkdir lab11 && cd lab11
git init -b main
for n in 1 2 3 4 5 6 7 8; do echo $n > value.txt; git add .; git commit -m "value $n"; done
# giả sử value >= 6 là bad
git bisect start
git bisect bad HEAD
git bisect good HEAD~7
# tại mỗi commit Git chọn:
cat value.txt
# nếu value >= 6: git bisect bad; ngược lại git bisect good
# lặp tới khi tìm first bad
git bisect reset

Kiểm tra kết quả

git status
# quay lại branch ban đầu sau reset
Lab 12

Worktree: feature + hotfix song song

Nâng cao

Mục tiêu: Làm nhiều branch đồng thời không stash/switch liên tục.

cd ~/git-labs
rm -rf lab12-main lab12-hotfix
mkdir lab12-main && cd lab12-main
git init -b main
echo base > app.txt; git add .; git commit -m init
git worktree add ../lab12-hotfix -b hotfix main
git worktree list
cd ../lab12-hotfix
echo fix >> app.txt
git commit -am "fix: from worktree"
cd ../lab12-main
git log --oneline --all --graph
git worktree remove ../lab12-hotfix

Kiểm tra kết quả

git worktree list
# linked hotfix worktree đã được remove
Lab 13

Inspect Git objects

Nâng cao

Mục tiêu: Nhìn trực tiếp commit/tree/blob objects.

cd ~/git-labs/lab01
git cat-file -t HEAD
git cat-file -p HEAD
git cat-file -p HEAD^{tree}
git ls-tree -r HEAD
git rev-parse HEAD
git rev-parse --show-toplevel

Kiểm tra kết quả

# xác định object type của HEAD, tree và blob README.md