Tuần 1 - Ngày 1: Tại Sao Git? Object Model và Khởi Động
Mục tiêu học tập
- Hiểu vì sao Git trở thành tiêu chuẩn của ngành và Git giải quyết vấn đề gì
- Phân biệt distributed VCS (Git) với centralized VCS (SVN, CVS)
- Nắm vững object model của Git: blob, tree, commit, tag
- Thực hành
git init,git clone,git status - Hiểu ba vùng không gian làm việc: Working Directory, Staging Area, Repository
1. Vấn đề trước khi có Git
Trước Git: Copy-paste version control
project_v1/
project_v2/
project_v2_final/
project_v2_final_FINAL/
project_v2_final_FINAL_v3_use_this_one/
Vấn đề thực tế:
- Không biết file nào là mới nhất
- Không biết ai thay đổi gì, khi nào, tại sao
- Merge thay đổi của 2 người cùng sửa file giống nhau là nightmare
- Muốn thử ý tưởng mới phải copy cả folder
Centralized VCS (SVN, CVS, Perforce)
Vấn đề của centralized VCS:
- Server chết = không làm việc được, mất lịch sử
- Commit và share là một việc — không thể commit thử locally
- Branch/merge rất đau, thường tránh dùng
- Slow vì mọi thao tác cần network request tới server
2. Distributed VCS — Git
Ưu điểm distributed:
- Mọi clone là full backup: lịch sử đầy đủ, không cần server
- Offline work: commit, branch, merge đều không cần mạng
- Nhanh: hầu hết operations đọc từ local disk
- Branch/merge nhẹ nhàng: Git được thiết kế để branch là cheap
3. Object Model của Git
Git lưu dữ liệu không phải dạng "diff giữa các phiên bản" mà là snapshot của toàn bộ project tại từng thời điểm. Mỗi object được định danh bằng SHA-1 hash 40 ký tự.
Bốn loại object
Blob — Nội dung file
Blob không lưu filename — chỉ lưu nội dung thuần túy. Hai file khác tên nhưng cùng nội dung → cùng blob hash → Git chỉ lưu một lần (deduplication).
Tree — Cấu trúc thư mục
Tree = directory listing: mode + type + hash + name. Tree trỏ đến blob (file) hoặc tree khác (subdirectory).
Commit — Snapshot + metadata
Commit đầu tiên không có parent. Commit merge có 2+ parents.
Tag — Annotated tag
Cách objects liên kết nhau
Khi bạn thay đổi src/index.js:
- Blob mới được tạo cho
src/index.js - Tree mới cho
src/(trỏ đến blob mới) - Tree mới cho root (trỏ đến tree
src/mới) - Commit mới trỏ đến root tree mới
- Các file không thay đổi (README.md, utils.js) vẫn trỏ đến blob cũ — không duplicate
4. Ba vùng không gian làm việc
| Vùng | Nơi lưu | Tác dụng |
|---|---|---|
| Working Directory | Filesystem thường | Nơi bạn edit file |
| Staging Area (Index) | .git/index | "Danh sách" những thay đổi sẽ vào commit tiếp |
| Repository | .git/objects/ | Lịch sử commit bất biến |
Tại sao có Staging Area? — Cho phép bạn commit có chọn lọc. Ví dụ bạn sửa 5 file nhưng chỉ muốn commit 2 file liên quan đến một feature, 3 file còn lại chờ commit sau.
5. Lệnh khởi động
git init — Khởi tạo repository mới
git clone — Sao chép repository
# Clone từ GitHub
git clone https://github.com/user/repo.git
# Clone vào thư mục tên cụ thể
git clone https://github.com/user/repo.git my-folder
# Clone qua SSH (cần setup SSH key)
git clone git@github.com:user/repo.git
# Clone chỉ một branch cụ thể (nhanh hơn cho repo lớn)
git clone --single-branch --branch main https://github.com/user/repo.git
# Clone shallow — chỉ lấy N commit gần nhất (rất nhanh, dùng trong CI)
git clone --depth 1 https://github.com/user/repo.git
git status — Trạng thái hiện tại
git status
# Output example:
# On branch main
# Your branch is up to date with 'origin/main'.
#
# Changes to be committed: ← đã staged
# (use "git restore --staged <file>..." to unstage)
# modified: src/app.js
#
# Changes not staged for commit: ← modified nhưng chưa staged
# (use "git add <file>..." to update what will be committed)
# modified: README.md
#
# Untracked files: ← Git chưa biết file này
# (use "git add <file>..." to include in what will be committed)
# new-feature.js
# Ngắn gọn hơn
git status -s
# M src/app.js ← staged modified (cột 1 = staged, cột 2 = unstaged)
# M README.md ← unstaged modified
# ?? new-feature.js ← untracked
6. Cấu hình ban đầu
# Thiết lập bắt buộc trước khi commit lần đầu
git config --global user.name "Tên Của Bạn"
git config --global user.email "email@example.com"
# Editor mặc định (dùng khi viết commit message dài)
git config --global core.editor "code --wait" # VS Code
git config --global core.editor "vim" # Vim
# Xem tất cả config
git config --list --global
# Config chỉ cho repo hiện tại (không có --global)
git config user.email "work@company.com"
# Config level: system < global < local (local override global)
Câu hỏi ôn tập
-
Git khác SVN ở điểm cốt lõi nào liên quan đến nơi lưu trữ repository?
<details> <summary>Xem đáp án</summary>Git là distributed VCS — mỗi clone là một full repository với toàn bộ lịch sử. SVN là centralized VCS — chỉ có server lưu repository đầy đủ, client chỉ có working copy. Hệ quả: Git hoạt động offline hoàn toàn (commit, branch, merge), server chết không mất lịch sử, và hầu hết operations đọc từ local disk nên nhanh hơn.
</details> -
Tại sao hai file khác tên nhưng nội dung giống nhau chỉ tạo ra một blob trong Git?
<details> <summary>Xem đáp án</summary>Blob object trong Git lưu nội dung thuần túy (không lưu filename). Hash của blob được tính từ nội dung: cùng nội dung → cùng SHA-1 hash → cùng blob object. Filename được lưu trong tree object ở tầng trên. Đây là content-addressable storage — Git tự động deduplication mà không cần logic phức tạp.
</details> -
Khi bạn commit một file mới, Git tạo ra bao nhiêu objects tối thiểu? Đó là những loại nào?
<details> <summary>Xem đáp án</summary>Tối thiểu 3 objects: (1) blob — nội dung file, (2) tree — directory listing trỏ đến blob với filename, (3) commit — trỏ đến root tree, chứa metadata (author, date, message, parent). Nếu có subdirectory, cần thêm tree object cho mỗi directory level.
</details> -
Staging area (Index) có vai trò gì mà Working Directory không thể thay thế?
<details> <summary>Xem đáp án</summary>Staging area cho phép commit có chọn lọc. Bạn có thể sửa 10 file trong working directory nhưng chỉ stage và commit 3 file liên quan đến một feature cụ thể — 7 file còn lại vẫn chờ trong working directory. Thậm chí
</details>git add -pcho phép stage từng hunk trong cùng một file. Working directory chỉ là filesystem thông thường, không có khái niệm "sẽ commit cái gì". -
Lệnh nào hiển thị trạng thái ngắn gọn, và ký tự đầu tiên trong output đó có nghĩa gì?
<details> <summary>Xem đáp án</summary>
</details>git status -s(hoặc--short). Output dạng 2 cột: cột đầu (index/staged status), cột hai (working tree status). Ký tự cột đầu:M= modified staged,A= added staged,D= deleted staged,?= untracked (dùng??). Ví dụ:M file.js(staged modified),M file.js(unstaged modified),?? new.js(untracked).
Bài tập thực hành
# 1. Khởi tạo repo mới và khám phá cấu trúc .git
mkdir git-lab && cd git-lab
git init
ls -la .git/
# 2. Cấu hình user info
git config user.name "Your Name"
git config user.email "you@example.com"
# 3. Tạo file đầu tiên và quan sát status
echo "# My Project" > README.md
git status
# → Untracked files: README.md
# 4. Stage file và quan sát thay đổi
git add README.md
git status
# → Changes to be committed: new file: README.md
# 5. Commit lần đầu
git commit -m "feat: initial commit"
# 6. Khám phá objects được tạo ra
find .git/objects -type f
# Thử đọc một object (thay hash bằng hash thật)
git cat-file -t <hash> # xem type (blob/tree/commit)
git cat-file -p <hash> # xem nội dung
# 7. Clone một repo public để thực hành
cd /tmp
git clone https://github.com/github/gitignore.git
ls gitignore/
Tài liệu tham khảo chính thức
Tiếp theo: Ngày 2 — Staging Area và Commit