Skip to content

3.14 - Ôn tập và đánh giá Module 3 ​

Tóm tắt: Bài tổng kết Module 3 gồm ba phần. Quiz 10 câu tình huống, mỗi câu kèm đáp án và giải thích. Lab 4 bài thực hành trên một kho thật của bạn: đưa kho lên GitHub, làm một vòng nhánh → pull request → squash merge, giải một xung đột, và cứu commit bằng reflog. Rubric mô tả từng mức điểm để bạn tự chấm hoặc nhờ mentor chấm. Làm quiz trước khi mở đáp án; làm lab trên máy, không chép output.

Mục tiêu bài học ​

Sau bài này bạn có thể:

  • Tự đánh giá mức nắm vững Module 3 qua 10 câu hỏi tình huống.
  • Đi trọn một vòng làm việc nhóm với Git và GitHub mà không cần xem lại bài.
  • Giải một xung đột merge và giữ được ý định của cả hai bên.
  • Khôi phục commit đã mất bằng reflog và cất việc dở bằng stash -u.

Cần biết trước: toàn bộ Module 3, từ bài 3.1 tới bài 3.13. Lab 2 cần tài khoản GitHub và đăng nhập được như bài 3.2.

Phần A — Quiz (30 điểm, mỗi câu 3 điểm) ​

Ghi đáp án và một dòng lý do cho từng câu trước khi mở phần giải thích.

Câu 1. Bạn vừa git commit --amend -m "fix: correct typo" cho commit cuối (chưa push). Phát biểu nào đúng?

A. Git sửa message của commit cũ, mã băm giữ nguyên. B. Git tạo commit mới với mã băm mới; commit cũ vẫn còn trong kho và tìm lại được qua git reflog. C. Commit cũ bị xoá vĩnh viễn ngay lập tức. D. --amend chỉ sửa message, không bao giờ đưa thêm file vào commit.

Đáp án câu 1

B. Commit là bất biến; mã băm tính từ nội dung, kể cả message (bài 3.1). D sai vì --amend gộp luôn mọi thứ đang nằm trong staging vào commit mới.

Câu 2. Sau git fetch, git status báo Your branch is behind 'origin/main' by 2 commits. File trong thư mục làm việc của bạn đã đổi chưa?

A. Rồi, fetch đã cập nhật file. B. Chưa. fetch chỉ cập nhật origin/main; phải git pull (hoặc merge/rebase origin/main) thì nhánh và file mới đổi. C. Chưa, vì fetch không tải gì về, chỉ so sánh. D. Rồi, nhưng chỉ với file chưa sửa.

Đáp án câu 2

B. origin/main là bản ghi nhớ trên máy về vị trí nhánh trên remote (bài 3.4). C sai vì fetch có tải commit về, chỉ không gộp vào nhánh của bạn.

Câu 3. Bạn thêm appsettings.Production.json vào .gitignore, nhưng git status vẫn báo file đó đã sửa. Vì sao, và làm gì?

A. .gitignore sai cú pháp; thêm dấu / ở đầu. B. File đã được theo dõi từ trước; .gitignore không hồi tố. Chạy git rm --cached appsettings.Production.json rồi commit — và nếu file có bí mật đã push thì thu hồi bí mật trước. C. Phải chạy git clean -fd. D. Phải xoá thư mục .git và git init lại.

Đáp án câu 3

B (bài 3.2). C xoá file chưa theo dõi, không liên quan và có thể làm mất file. D xoá toàn bộ lịch sử.

Câu 4. Bạn sửa dở ba file và tạo thêm một file mới, chưa commit. Có lỗi gấp phải sang nhánh khác sửa ngay. Lệnh nào cất hết việc dở?

A. git stash B. git stash -u C. git reset --hard D. git clean -fd

Đáp án câu 4

B. stash mặc định không cất file chưa theo dõi; -u cất cả chúng (bài 3.3). C và D xoá mất việc dở, không cứu lại được.

Câu 5. Bạn lỡ git reset --hard HEAD~3 trên nhánh chưa push. Ba commit đó còn cứu được không, và bằng cách nào?

A. Không, --hard xoá vĩnh viễn. B. Có: git reflog tìm mã commit trước khi reset, rồi git reset --hard <mã> (hoặc git branch rescue <mã>), trong khoảng 30 ngày theo mặc định. C. Có, nhưng chỉ khi đã push. D. Có: git revert HEAD~3.

Đáp án câu 5

B (bài 3.3). Thứ --hard xoá vĩnh viễn là thay đổi chưa commit, không phải commit.

Câu 6. Đang ở nhánh feature/report, bạn chạy git rebase main và gặp xung đột. Bạn gõ git restore --ours Report.cs với ý "giữ code của tôi". Chuyện gì xảy ra?

A. Giữ code của bạn, đúng ý. B. Giữ phiên bản của main: trong rebase, "ours" là nhánh đích, còn commit của bạn là "theirs". C. Git báo lỗi vì không dùng được --ours khi rebase. D. Giữ cả hai bên.

Đáp án câu 6

B (bài 3.7). Khi rebase, Git đứng trên nhánh đích và phát lại từng commit của bạn lên trên, nên "ours" là main. Cách an toàn: mở file ra đọc dấu xung đột.

Câu 7. Bạn rebase nhánh cá nhân đã push lên GitHub và cần đẩy lại. Lệnh nào phù hợp nhất?

A. git push --force B. git push --force-with-lease --force-if-includes C. git pull rồi git push D. git push --no-verify

Đáp án câu 7

B (bài 3.3). --force-with-lease từ chối nếu remote có commit bạn chưa thấy; --force-if-includes vá trường hợp bạn vừa fetch ngay trước đó. C trộn lại lịch sử cũ với lịch sử đã rebase, tạo commit trùng lặp.

Câu 8. PR của bạn được squash merge trên GitHub. Về máy, git branch -d feature/report báo not fully merged. Vì sao?

A. PR chưa thật sự được merge. B. Squash merge tạo một commit mới trên main; các commit gốc của nhánh không nằm trong main, nên Git không biết nhánh đã được gộp. Xác nhận PR đã merged rồi xoá bằng -D. C. Phải git fetch trước thì -d mới chạy. D. Nhánh đang bị khoá bởi branch protection.

Đáp án câu 8

B (bài 3.5, bài 3.8).

Câu 9. Nhánh A đổi tên CalculateRevenue thành CalculateAnnualRevenue; nhánh B (tách cùng lúc) thêm một file mới gọi CalculateRevenue. Merge cả hai vào main. Điều gì xảy ra?

A. Git báo xung đột ở file mới. B. Git merge sạch, nhưng dotnet build báo lỗi CS1061. Chỉ CI chạy build/test trên kết quả merge mới bắt được. C. Git tự sửa chỗ gọi theo tên mới. D. Cả hai merge đều bị từ chối.

Đáp án câu 9

B — xung đột ngữ nghĩa (bài 3.7). Git làm việc trên dòng văn bản, không hiểu C#.

Câu 10. Một bạn lỡ push mật khẩu database production lên kho công khai 5 phút trước. Việc đầu tiên phải làm là gì?

A. git rm --cached file đó và push. B. Chạy git filter-repo xoá file khỏi lịch sử. C. Đổi mật khẩu database và ngắt các phiên đang mở; dọn lịch sử làm sau. D. Chuyển kho sang riêng tư.

Đáp án câu 10

C (bài 3.12). A và B không thu hồi được các bản sao đã bị clone hay bị bot đọc; D cũng vậy. Đổi mật khẩu không tự ngắt phiên cũ, nên phải ngắt chúng.

Phần B — Lab (70 điểm) ​

Làm trên máy của bạn, trong một kho tên crm-git-review. Mỗi lab có tiêu chí kiểm tra được; nộp đường dẫn kho GitHub và file LAB.md ở gốc kho ghi output các lệnh được yêu cầu.

Lab 1 — Kho đầu tiên lên GitHub (15 điểm) ​

  1. Tạo kho trên máy với nhánh đầu tiên là main (dùng git init -b main, vì trên nhiều máy Windows giá trị mặc định vẫn là master).
  2. Tạo project bằng dotnet new console -n Crm -o ., thêm .gitignore bằng dotnet new gitignore, thêm .gitattributes có dòng * text=auto.
  3. Commit theo Conventional Commits.
  4. Trên GitHub, tạo kho trống crm-git-review (không tick Add a README), rồi git remote add origin ... và git push -u origin main.

Tiêu chí kiểm tra: trang GitHub của kho hiện Program.cs, Crm.csproj, .gitignore, .gitattributes, không có thư mục bin/ hay obj/; git branch -vv (ghi vào LAB.md) cho thấy main theo dõi origin/main.

Lời giải — Lab 1
bash
mkdir crm-git-review && cd crm-git-review
git init -b main
dotnet new console -n Crm -o .
dotnet new gitignore
echo "* text=auto" > .gitattributes
git add .
git status                 # kiểm tra: không có bin/ hay obj/
git commit -m "chore: initialize CRM console project"
git remote add origin https://github.com/<ten-ban>/crm-git-review.git
git push -u origin main
git branch -vv

Nếu gặp error: src refspec main does not match any: hoặc chưa commit, hoặc nhánh đang tên master — đổi bằng git branch -M main.

Lab 2 — Nhánh, pull request, squash merge (20 điểm) ​

  1. Tạo nhánh feature/customer-notes từ main.
  2. Tạo file docs/customer-notes.md mô tả tính năng "ghi chú cho khách hàng" (vài dòng là đủ, không cần viết code), commit. Sửa thêm một ý, commit lần hai. Cả hai message theo Conventional Commits.
  3. Push nhánh, mở pull request với mô tả theo cấu trúc ở bài 3.6: Vì sao, Làm gì, Cách kiểm tra, Lưu ý cho người review.
  4. Squash merge PR (tiêu đề PR theo Conventional Commits), rồi dọn nhánh ở cả GitHub và máy.

Tiêu chí kiểm tra: trên main có một commit mới cho PR, message bắt đầu bằng feat: hoặc docs:; PR có đủ bốn mục mô tả; git branch trên máy không còn feature/customer-notes; LAB.md ghi lại lệnh đã dùng để xoá nhánh và giải thích vì sao dùng -D.

Lời giải — Lab 2
bash
git switch -c feature/customer-notes
mkdir docs
printf '# Ghi chú khách hàng\n\nNhân viên thêm ghi chú cho mỗi khách hàng.\n' > docs/customer-notes.md
git add docs && git commit -m "docs: describe customer notes feature"
printf 'Mỗi ghi chú lưu người viết và thời điểm.\n' >> docs/customer-notes.md
git commit -am "docs: add author and timestamp to customer notes"
git push -u origin feature/customer-notes
# Mở PR trên GitHub (đường dẫn in ra sau lệnh push), viết mô tả, chọn "Squash and merge"
git switch main
git pull
git branch -D feature/customer-notes    # -d sẽ báo "not fully merged" sau squash merge
git fetch --prune
git log --oneline -3

PR có hai commit nên GitHub mặc định đề xuất tiêu đề PR làm dòng đầu của commit squash (bài 3.10) — vì vậy tiêu đề PR phải theo quy ước.

Lab 3 — Giải xung đột (20 điểm) ​

Trong cùng kho, chạy đoạn sau (Git Bash, macOS hoặc Linux). Đây là một kho, hai nhánh tách từ cùng một commit; không cần hai terminal.

bash
git switch main
printf '# Quy tắc cập nhật khách hàng\n1. Tên không được rỗng.\n2. (chưa có quy tắc liên hệ)\n' > customer-rules.md
git add customer-rules.md && git commit -m "docs: add customer update rules"

git switch -c feature/email-validation
printf '# Quy tắc cập nhật khách hàng\n1. Tên không được rỗng.\n2. Email phải có dạng ten@mien.\n' > customer-rules.md
git commit -am "docs: require a valid email when updating a customer"

git switch main
git switch -c feature/phone-validation
printf '# Quy tắc cập nhật khách hàng\n1. Tên không được rỗng.\n2. Số điện thoại phải có 10 chữ số.\n' > customer-rules.md
git commit -am "docs: require a 10-digit phone number when updating a customer"

git switch main
git merge feature/email-validation
git merge feature/phone-validation      # xung đột

Giải xung đột sao cho giữ cả hai quy tắc (email là quy tắc 2, số điện thoại là quy tắc 3), hoàn tất merge và push main.

Tiêu chí kiểm tra: customer-rules.md trên main có đúng ba quy tắc, không còn dòng nào chứa <<<<<<<, ======= hay >>>>>>>; git log --oneline --graph (dán vào LAB.md) có một merge commit với hai cha.

Lời giải — Lab 3

Output thật của lệnh merge thứ hai:

text
Auto-merging customer-rules.md
CONFLICT (content): Merge conflict in customer-rules.md
Automatic merge failed; fix conflicts and then commit the result.
text
# Quy tắc cập nhật khách hàng
1. Tên không được rỗng.
<<<<<<< HEAD
2. Email phải có dạng ten@mien.
=======
2. Số điện thoại phải có 10 chữ số.
>>>>>>> feature/phone-validation

Sửa file thành (bằng tay hoặc Accept Both Changes trong VS Code rồi đánh lại số):

text
# Quy tắc cập nhật khách hàng
1. Tên không được rỗng.
2. Email phải có dạng ten@mien.
3. Số điện thoại phải có 10 chữ số.
bash
git add customer-rules.md
git commit --no-edit
git log --oneline --graph -5
git push
text
*   413c0ed Merge branch 'feature/phone-validation'
|\
| * 2c2962f docs: require a 10-digit phone number when updating a customer
* | 77a7987 docs: require a valid email when updating a customer
|/
* a0aba22 docs: add customer update rules

Merge đầu tiên là fast-forward (main chưa có commit mới), nên chỉ merge thứ hai mới tạo merge commit. Mã băm trên máy bạn sẽ khác.

Lab 4 — Cứu dữ liệu (15 điểm) ​

  1. Tạo nhánh practice/rescue, tạo 3 commit nhỏ trên đó. Ghi git log --oneline -4 vào LAB.md.
  2. Chạy git reset --hard HEAD~2. Dùng git reflog khôi phục nhánh về đúng commit cuối.
  3. Sửa customer-rules.md (file đã có từ Lab 3) và tạo một file mới todo.md, không commit. Cất cả hai bằng một lệnh, chuyển sang main, quay lại practice/rescue và lấy lại.

Tiêu chí kiểm tra: sau bước 2, git log --oneline -4 giống hệt bước 1 (cùng mã băm); sau bước 3, git status --short hiện lại M customer-rules.md và ?? todo.md. LAB.md có output của git reflog dùng ở bước 2.

Lời giải — Lab 4
bash
git switch -c practice/rescue
for i in 1 2 3; do echo "bước $i" >> rescue.txt; git add rescue.txt; git commit -m "chore: rescue practice step $i"; done
git log --oneline -4

git reset --hard HEAD~2
git reflog -4
# dòng "commit: chore: rescue practice step 3" cho biết mã cần lấy lại
git reset --hard <mã đó>
git log --oneline -4          # giống hệt lần đầu

echo "sửa dở" >> customer-rules.md
echo "- việc cần làm" > todo.md
git stash push -u -m "wip: rescue practice"
git switch main
git switch practice/rescue
git stash pop
git status --short

Quên -u thì todo.md không được cất và vẫn nằm trong thư mục khi bạn chuyển sang main — đó là cái bẫy mà lab này muốn bạn nhìn thấy.

Phần C — Rubric ​

Tổng điểm: Quiz 30 + Lab 70 = 100. Đạt từ 70 điểm, Khá từ 85, Giỏi từ 95.

Hạng mụcĐầy đủMột phầnChưa đạt
Quiz (30)3 điểm mỗi câu đúng và lý do đúng1 điểm nếu đáp án đúng nhưng lý do sai0
Lab 1 (15)Kho trên GitHub đúng file, không có bin//obj/, main theo dõi origin/main (15)Thiếu .gitattributes hoặc nhánh tên master (8)Chưa push được (0)
Lab 2 (20)Một commit squash trên main, PR đủ bốn mục, nhánh đã dọn, giải thích được -D (20)PR thiếu mục hoặc message sai quy ước (10)Không có PR, commit thẳng vào main (0)
Lab 3 (20)Ba quy tắc, không còn dấu xung đột, merge commit hai cha (20)Giữ được một bên hoặc đánh số sai (10)Còn dấu xung đột trong file (0)
Lab 4 (15)Khôi phục đúng mã băm, stash giữ được cả file mới, có output reflog (15)Khôi phục được nhưng mất todo.md (8)Không khôi phục được (0)

Quy tắc chung cho mọi lab: commit message theo Conventional Commits bằng tiếng Anh. Mỗi commit sai quy ước trừ 1 điểm, tối đa trừ 5.

Kết luận ​

Module 3 đã đi từ mô hình dữ liệu của Git (commit bất biến, nhánh là con trỏ) tới làm việc nhóm (remote, pull request, CI, xung đột) và xử lý sự cố (reflog, bisect, lộ bí mật). Nếu lab nào bạn phải xem lại bài nhiều lần, quay lại đúng bài đó: Lab 1 là bài 3.4, Lab 2 là bài 3.6, Lab 3 là bài 3.7, Lab 4 là bài 3.3. Từ Module 4 trở đi, mọi bài tập đều nên nằm trong một kho Git và đi qua đúng vòng nhánh → PR → merge này.

Tham khảo ​

Điều hướng ​

Phát hành theo giấy phép MIT.