→ From Coder to Shipper
From Coder to Shipper · Nền tảng

Git — Kiểm soát phiên bản

Máy thời gian cho code của bạn: mọi thay đổi đều được lưu, nên bạn có thể quay lại, làm việc song song và cùng ship với mọi người.

← / → để chuyển slide · chuyển EN/VI bên dưới

Vì sao nó tồn tại

Vấn đề 'final_final_v3'

Không có kiểm soát phiên bản, code của bạn nằm trên một ổ đĩa, file nọ file kia. Sửa gì đó rồi cầu nguyện.

File sinh sôi

index.html, index_v2.html, index_final.html, index_final_REAL.html — lúc 2 giờ sáng bạn chẳng biết file nào là thật.

Sai một lần lưu, hết tất cả

Ghi đè, máy sập, một lần AI sửa nhầm — và không có 'undo' cho cả một dự án.

Không thấy được quá khứ

Code hồi thứ Ba tuần trước trông thế nào? Vì sao nó hỏng sau lần sửa đó? Không cách nào biết được.

Một mình thì ổn, đông lên thì loạn

Hai người sửa cùng một file trên một laptop? Chúc may mắn khi phải quyết ai thắng.

Toàn cảnh

Git là máy thời gian có nút chia sẻ

Một ý tưởng: git giữ toàn bộ lịch sử dự án trên máy bạn — và có thể đồng bộ lịch sử đó với một bản sao trên internet (GitHub).

Your laptop
Working tree — các file bạn đang sửa
.git folder — mọi tấm ảnh chụp, theo thứ tự
git push →← git pull
The internet
mạng — chỉ chở dữ liệu
⇄
GitHub — "origin"
Repo từ xa — bản sao lịch sử chung
Đồng đội & server lấy code từ đây
01
Phần 1 · Mô hình tư duy

Bốn căn phòng

Mỗi lệnh git đều di chuyển thứ gì đó giữa bốn căn phòng: working tree → staging area → commits → con trỏ branch.

Phần 1 · các căn phòng

Working tree, staging, commits, branch

Đó là toàn bộ bảng từ vựng. Phần còn lại đều là chi tiết.

Working tree — bàn làm việc

Các file thật trên ổ đĩa, do bạn và AI sửa. 'Hiện tại', nhưng chưa được lưu vào lịch sử.

Staging area — khay chờ

Danh sách chính xác thay đổi nào sẽ vào commit kế tiếp. Bạn chọn; git không đoán.

Commits — album ảnh

Mỗi commit = một tấm ảnh chụp cả dự án + một dòng ghi chú. Các tấm ảnh xếp chồng thành lịch sử.

Branch — cái tên di động

Không phải bản sao code — chỉ là con trỏ nói 'bản chụp mới nhất tính tới đây = cái này'.

Phần 1 · dòng chảy

sửa → add → commit

Một sơ đồ cần nhớ: bạn sửa ở working tree, chọn thay đổi vào staging, và commit biến khay thành tấm ảnh mới.

1 · Working tree
app.pyđã sửa
styles.cssđã sửa
git add
2 · Staging area
app.pyđã chọn
git commit
3 · Commits (lịch sử)
C3fix loginmain →
C2add styles
C1first commit
Phần 1 · một commit

Một commit thực sự là gì

Một mã ngắn, một dòng ghi chú, và một tấm ảnh chụp được đóng băng của dự án. git log cho bạn xem album.

terminal
git log --oneline

a1b2c3d  fix: handle empty search results
d4e5f6a  feat: add user profile page
0f9e8d7  first commit

Mới nhất ở trên cùng. Mỗi dòng = một tấm ảnh bạn luôn có thể quay lại.

Phần 1 · vì sao

Sao cần khay? Sao cần tấm ảnh?

Cả hai câu trả lời cùng một từ: kiểm soát. Bạn quyết định chính xác cái gì được lưu, và khi nào.

Staging = kiểm soát CÁI GÌ

Bạn có thể chọn 1 trong 5 file đã sửa. Commit chứa đúng những gì bạn bỏ vào khay — không thừa, không thiếu.

Cách dùng kinh điển: chọn file sửa code, nhưng không chọn file .env chứa bí mật của bạn.

Commits = kiểm soát KHI NÀO

Commit là điểm lưu mà bạn tạo ra có chủ đích. Không auto-save, không sự cố — lịch sử là chuỗi những quyết định.

Commit nhỏ và thường xuyên = lịch sử hoàn tác chi tiết.

02
Phần 2 · Vòng lặp hằng ngày

status → add → commit

90% một ngày dùng git là vòng lặp ba lệnh này. Học nó đến thành phản xạ.

Phần 2 · vòng lặp

Ba lệnh

Kiểm tra, chọn, lưu. Lặp lại.

  1. 1

    git status — tôi đang ở đâu?

    Liệt kê file đã sửa và file mới: 'bạn đã sửa X, và Y là file mới'. Lệnh đầu tiên gõ mỗi khi bạn không chắc.

  2. 2

    git add — bỏ vào khay

    git add app.py bỏ trạng thái hiện tại của file đó vào staging. git add . = mọi thứ đã đổi.

  3. 3

    git commit — chụp ảnh

    git commit -m "lời nhắn" biến khay thành tấm ảnh mới trong lịch sử. Lời nhắn là viết cho bạn ở tương lai.

Phần 2 · status

git status: la bàn

Nó cho bạn biết chính xác bạn đang ở đâu: gì đã sửa, gì đã chọn, gì hoàn toàn mới.

ops@vps — zsh
$ git status
On branch main
Changes not staged for commit:
modified: app.py
Untracked files:
styles.css
← 'modified' = edited, 'untracked' = git has never seen it
Phần 2 · add + commit

Chọn, rồi lưu

Hai lệnh và một tấm ảnh đã tồn tại. Dòng ghi chú là phần duy nhất bạn tự viết.

ops@vps — zsh
$ git add app.py
$ git commit -m "fix: login fails on empty form"
[main a1b2c3d] fix: login fails on empty form
1 file changed, 2 insertions(+), 1 deletion(-)
$ git status
On branch main
nothing to commit, working tree clean
← 'working tree clean' = everything is saved in history
Commit nhỏ, commit thường xuyên. Commit là điểm lưu, không phải tượng đài.
quy tắc duy nhất quan trọng
Phần 2 · dòng ghi chú

Điều gì làm nên một commit hay

Bạn sẽ đọc những dòng này sau vài tháng — hoặc một đồng đội. Hãy viết cho người đọc đó.

Một việc mỗi commit

Sửa lỗi đăng nhập = một commit. Icon mới = commit khác. Trộn vào nhau là không thể hoàn tác được.

Thì hiện tại, ngắn gọn

"fix: xử lý form rỗng" — không phải "mình đã sửa cái gì đó với form hay là". Như tiêu đề, không phải nhật ký.

Lý do, ngắn gọn

Diff đã cho thấy CÁI GÌ đổi. Dòng ghi chú là để giải thích VÌ SAO — 'vì API giờ trả về null'.

AI giúp, bạn quyết

Nhờ AI soạn dòng ghi chú từ thay đổi của bạn — nhưng chỉ giữ đúng một dòng bạn sẵn sàng bảo vệ.

03
Phần 3 · Lịch sử & quay lại

Nhìn lại & quay lại

Lịch sử mới là mấu chốt. git có thể cho bạn xem bất kỳ trạng thái quá khứ nào — và đưa bạn quay về đó.

Phần 3 · ba công cụ đọc

Ba cách nhìn vào quá khứ

log = danh sách, diff = so sánh, show = xem kỹ một tấm ảnh.

LệnhNó trả lờiKhi nào dùng
git logChuyện gì đã xảy ra, theo thứ tự nào?Luôn luôn — bản đồ lịch sử của bạn
git diffCái gì đổi, từng dòng một?Trước khi commit, hay 'mình có hỏng gì không?'
git show a1b2c3dCommit ĐÓ cụ thể đã đổi gì?Khi một commit gây ra vấn đề
Phần 3 · log

git log: bản đồ quá khứ

--oneline = mỗi commit một dòng. Thói quen: liếc bản đồ trước khi sửa bất cứ thứ gì.

ops@vps — zsh
$ git log --oneline
a1b2c3d fix: handle empty search results
d4e5f6a feat: add user profile page
9c8b7a6 fix: login fails on empty form
0f9e8d7 first commit
← newest first. Each line = one snapshot you can go back to
Phần 3 · diff

git diff: thấy đúng cái gì đã đổi

Dòng bắt đầu bằng + là thêm, dòng có - là bỏ. Cách nhanh nhất để trả lời 'mình có hỏng gì không?'.

terminal
git diff
--- a/app.py
+++ b/app.py
-price = 100
+price = 99   # black friday!

Diff là sự thật: đúng những gì sẽ vào commit kế tiếp.

Phần 3 · hoàn tác

Ba cấp độ hoàn tác

Tự hỏi: mình muốn quay lại xa tới đâu? Working tree → staging → lịch sử. Mỗi cấp một lệnh hoàn tác.

Working tree — git restore

'Mình phá hỏng file này, trả lại bản đã commit gần nhất.' git restore app.py. Các commit không hề hấn gì.

Staging — git restore --staged

'Mình chọn nhầm file vào khay.' Lấy nó ra khỏi khay. File trên ổ đĩa không đổi.

Lịch sử — git reset

'Commit đó sai rồi.' Đưa con trỏ branch lùi một bước. Công việc vẫn cứu được — đừng hoảng.

Phần 3 · restore

Hoàn tác một file, giữ nguyên phần còn lại

Cứu nguy phổ biến nhất: một file bị sửa hỏng (thường do AI), phần còn lại ổn.

ops@vps — zsh
# oops — app.py got clobbered
$ git restore app.py
$ git status
On branch main
nothing to commit, working tree clean
← app.py is back to its last committed version. Other files untouched.
04
Phần 4 · Nhánh

Branch: các vũ trụ song song

Branch là con trỏ, không phải bản sao. Đó là lý do tạo branch tức thì, còn chuyển branch thì miễn phí.

Phần 4 · mô hình tư duy

Branch chỉ là một cái tên trên commit

Branch 'main' trỏ tới tấm ảnh mới nhất. Mỗi commit mới, con trỏ lại trượt lên trước. Chỉ vậy thôi.

Con trỏ, không phải bản sao

Tạo branch không sao chép gì cả — chỉ ghim một cái tên vào một commit. Mili-giây, chi phí bằng không.

Commit đẩy nó đi

Commit trên 'main' thì 'main' trượt tới tấm ảnh mới. Lịch sử là một chuỗi; branch là nhãn gắn ở cuối chuỗi.

Nhiều tên, một chuỗi

Mười branch có thể trỏ cùng một commit — hoặc khác nhau. Chúng chia sẻ lịch sử như cây gia phả.

Bạn luôn đang ở một branch

Dù bạn không bao giờ tạo branch, 'main' (hay 'master') vẫn tồn tại. Commit của bạn đi tới nơi con trỏ đang đứng.

Phần 4 · hình ảnh

Hai branch, một gia đình

Bạn tách ra từ C2, thêm C3 trên branch feature, rồi merge về — main hấp thụ công việc của bạn.

main C1first commit── C2add styles── C4merge feature
feature C3fix login── được gộp vào main phía trên →
Phần 4 · quy trình

Vũ điệu branch

Bốn lệnh: cắt branch, làm việc, về lại main, merge. Đó là toàn bộ vũ điệu.

ops@vps — zsh
$ git switch -c feature/login
← creates feature/login AND switches to it (-c = create)
$ git commit -m "fix: login fails on empty form"
[feature/login c3d4e5f] fix: login fails on empty form
$ git switch main
$ git merge feature/login
Merge made by the 'ort' strategy.
← main now contains your fix. The branch did its job.
Phần 4 · vì sao

Vì sao ai cũng dùng branch

Branch là cách làm việc song song không còn là cuộc chiến.

Làm mà không giẫm chân

Đang refactor dở dang? Sang một branch. 'main' vẫn ổn định cho mọi người khác.

Thử nghiệm miễn phí

Thử ý tưởng rủi ro trên branch. Thất bại? Xóa branch — lịch sử nguyên vẹn.

Một tính năng = một branch

Quy ước của team: đặt tên theo tính năng (feature/login, fix/broken-nav). Xong, merge, hết.

Scale được với cả team

Mười người, mười branch, không còn 'ai ghi đè file của mình?'. GitHub biến mỗi branch thành Pull Request để review.

05
Phần 5 · Remote & bàn giao

Laptop của bạn không phải là nguồn sự thật

Dự án thật sống trên một repo từ xa — thường là GitHub. Laptop của bạn chỉ là một trong nhiều bản sao.

Phần 5 · hai bản sao

Local vs remote (origin)

Mỗi lần clone, git đặt tên remote mặc định là 'origin' — repo mà bạn lấy về.

Local = sân chơi của bạn

Nhanh, riêng tư, offline. Bạn commit ở đây thoải mái — không ai để ý cả.

Remote = sự thật chung

Bản trên GitHub mà đồng đội, server và lần triển khai cùng thống nhất.

origin = một cái tên, không phải nơi chốn

git push origin main = 'gửi branch main của tôi tới repo tôi đặt tên là origin'. Bạn có thể có nhiều remote.

Chúng lệch nhau

Bạn commit ở local, đồng đội push lên remote — hai bản lệch nhau. Đồng bộ là thói quen hằng ngày, không phải sự kiện lớn.

Phần 5 · vòng lặp remote

clone một lần, rồi pull & push

clone = 'lấy một bản sao, nối với origin'. Sau đó, vòng lặp chỉ là pull vào, push ra.

ops@vps — zsh
$ git clone https://github.com/you/shop.git
cd shop ← you now have a full copy + history
$ git pull
← work, commit … then:
$ git push origin main
To https://github.com/you/shop.git
main -> main
← your commits now live on GitHub, visible to everyone
Phần 5 · bốn động từ

clone / fetch / pull / push

Hai chiều: phía pull (nhận) và phía push (gửi). fetch là cái lặng lẽ; pull = fetch + áp dụng.

LệnhNó làm gìNói dễ hiểu
git clone <url>Tải toàn bộ repo (code + lịch sử) và ghi nhớ nguồn của nóĐầu mọi dự án: 'đưa tôi một bản sao'
git fetchTải commit mới từ origin — không đổi gì trên máy bạn'Cho tôi xem bên kia có gì mới'
git pullfetch + merge vào branch hiện tại'Mang đồ mới vào code của tôi'
git pushTải commit của bạn lên origin'Công bố việc của tôi — ai cũng thấy'
Phần 5 · .gitignore

Những gì git không bao giờ được thấy

.gitignore liệt kê các mẫu bỏ qua. git status thậm chí không nhắc tới các file này — chúng ở lại local.

.gitignore
# secrets — never, ever commit these
.env
*.db

# generated stuff — easy to rebuild
__pycache__/
node_modules/
*.log
dist/

Quy tắc: nếu nó tạo lại được, hoặc là bí mật — hãy ignore.

Phần 5 · quy tắc

Danh sách 'không bao giờ commit'

Một khi bí mật vào lịch sử, nó thành công khai — lịch sử không quên, và kẻ tấn công cũng vậy.

Bí mật — .env, keys, tokens

API key, mật khẩu, token. File .env là nguồn rò rỉ số 1. Ai cũng có thể đọc lịch sử repo của bạn.

Database — *.db, dumps

Database có dữ liệu người dùng thật, về bản chất là riêng tư. Commit bản mẫu hoặc schema, không phải dữ liệu.

Cache — __pycache__/, .pyc

Cache bytecode của Python. Nó tự tạo lại; trong git nó chỉ là rác.

Thư viện — node_modules/

Vài trăm MB thư viện đã cài. npm install tự dựng lại từ package.json.

Phần 5 · bàn giao

Push là cách bạn bàn giao

Mọi dự án thật đều sống trong git. Repo là nguồn sự thật duy nhất, mọi thứ khác đều dựng từ đó.

Bạn (laptop)
commit của bạn
git push →
GitHub (origin)
toàn bộ lịch sử — một sự thật
clone / deploy →
Mọi người khác
laptop của đồng đội
server & ứng dụng đã chạy
Tổng kết · bộ công cụ

Khoảng 10 lệnh chiếm 95% git hằng ngày

Nhớ những lệnh này là bạn làm việc được với mọi dự án. Phần còn lại, AI và tài liệu lo.

LệnhViệc
git statusTôi ở đâu? Gì đã đổi?
git add / git commitChọn và lưu một tấm ảnh
git log / git diff / git showĐọc lịch sử
git restoreHoàn tác một file (hoặc một lần chọn)
git switch (-c) / git branchChuyển giữa các dòng công việc song song
git mergeGộp branch về main
git clone / git pull / git pushLấy bản sao, giữ mới, công bố việc
Git là máy thời gian có nút chia sẻ.
mô hình tư duy trong một dòng

git init. Bạn đã vào cuộc.

Mọi dự án bạn chạm tới trong khóa học này đều sống trong git. status → add → commit → push. Đó là toàn bộ vòng lặp của một shipper.