Câu hỏi về Git khi phỏng vấn: 25 câu hỏi và đáp án
Khi phỏng vấn về Git, người ta thường kiểm tra hiểu biết về mô hình dữ liệu (commit, index, nhánh, HEAD), sự khác nhau giữa merge và rebase, fetch và pull, reset và revert, khả năng giải quyết xung đột và khôi phục commit đã mất, cũng như hiểu biết về các quy trình nhóm như GitHub Flow và Git Flow.
Git được hỏi gần như trong mọi buổi phỏng vấn lập trình viên, tester hay kỹ sư DevOps: đôi khi là một phần riêng, đôi khi lồng vào câu hỏi khác («bạn sẽ hoàn tác bản phát hành lỗi thế nào?»). Người phỏng vấn quan tâm không nhiều đến việc thuộc cờ lệnh, mà đến hiểu biết về mô hình: commit là gì, nhánh trỏ tới đâu, lịch sử bị viết lại ra sao. Dưới đây là 25 câu hỏi phổ biến nhất, với đáp án ở mức tạo ấn tượng tốt.
Các câu hỏi được sắp từ cơ bản đến nâng cao. Khi trả lời, nên đưa thêm một ví dụ ngắn từ thực tế — điều này được đánh giá cao hơn việc kể lại tài liệu.
Câu hỏi cơ bản
1. Git là gì, và hệ thống quản lý phiên bản phân tán khác tập trung ở điểm nào?
Git là hệ thống quản lý phiên bản phân tán: nó lưu lịch sử thay đổi của dự án và cho phép nhiều người làm việc song song. Trong hệ thống tập trung (ví dụ SVN), toàn bộ lịch sử nằm trên một máy chủ, còn lập trình viên chỉ có bản làm việc. Trong Git, mỗi bản clone chứa toàn bộ lịch sử, nên commit, nhánh, xem lịch sử và gộp đều chạy cục bộ và không cần mạng.
Từ đó có các lợi ích thực tế: tốc độ cao, làm việc được khi offline, không có điểm lỗi duy nhất. Máy chủ như GitHub hay GitLab trong Git chỉ là thỏa thuận của nhóm về bản «chính», chứ không phải yêu cầu kỹ thuật.
2. Công việc với Git gồm những khu vực nào?
Thư mục làm việc (các tệp trên đĩa), index hoặc staging area (ảnh chụp đã chuẩn bị cho commit tiếp theo) và kho cục bộ (thư mục .git chứa lịch sử). git add chuyển thay đổi từ thư mục làm việc sang index, còn git commit chuyển từ index vào kho.
Điểm cộng khi trả lời là nhắc thêm khu vực thứ tư — kho từ xa — cùng các lệnh git push và git fetch làm việc với nó.
3. Tại sao cần index, nếu có thể commit thẳng?
Index cho phép bạn commit có chủ đích: trong mười tệp đã sửa, commit ba tệp thuộc cùng một công việc, còn phần còn lại để sau. Với git add -p có thể chọn cả từng đoạn trong một tệp.
Đây là nền tảng của commit nguyên tử: một commit là một thay đổi logic. Lịch sử như vậy dễ đọc, dễ review, dễ hoàn tác bằng revert và dễ chuyển bằng cherry-pick.
4. Commit bên trong Git được cấu tạo thế nào?
Commit là một đối tượng lưu tham chiếu tới cây (tree) — ảnh chụp toàn bộ tệp của dự án, tham chiếu tới các commit cha, tác giả, người commit, thời gian và thông điệp. Nó được định danh bằng hash SHA-1 (các phiên bản mới có hỗ trợ thử nghiệm SHA-256) tính trên toàn bộ nội dung.
Ý quan trọng: Git lưu ảnh chụp, không lưu phần khác biệt. Tệp không đổi không được nhân bản — cây chỉ trỏ tới cùng một blob. Vì hash phụ thuộc vào cha, không thể sửa một commit cũ mà không làm thay đổi hash của mọi commit sau nó.
5. Nhánh và HEAD là gì?
Nhánh là con trỏ di chuyển được tới một commit — một tệp trong .git/refs/heads/ chứa hash bên trong. Vì vậy tạo nhánh trong Git diễn ra tức thì và không sao chép gì. Khi có commit mới, con trỏ của nhánh hiện tại dịch chuyển tới nó.
HEAD là con trỏ cho biết bạn đang đứng đâu; thường nó trỏ tới một nhánh (ref: refs/heads/main). Nếu chuyển sang một commit hoặc thẻ cụ thể, HEAD trỏ trực tiếp vào commit — đó là trạng thái detached HEAD.
6. Detached HEAD là gì và nguy hiểm ở đâu?
Đó là trạng thái HEAD trỏ tới commit thay vì nhánh, ví dụ sau git switch --detach v1.0 hoặc git checkout a1b2c3d. Có thể xem code và thậm chí commit, nhưng các commit mới không thuộc nhánh nào.
Nếu chuyển sang nhánh khác lúc này, các commit đó trở nên không với tới được và sau này sẽ bị bộ thu gom rác xóa. Để giữ công việc, tạo nhánh: git switch -c fix-from-detached. Nếu đã rời đi, hash có thể tìm trong git reflog.
7. git fetch khác git pull ở điểm nào?
git fetch tải commit mới về và cập nhật các nhánh theo dõi từ xa như origin/main, nhưng không đụng tới nhánh cục bộ hay tệp của bạn. git pull là fetch cộng với tích hợp: mặc định là merge, còn với --rebase hoặc cấu hình pull.rebase=true thì là rebase.
Lập trình viên có kinh nghiệm thường chạy fetch riêng, xem git log HEAD..origin/main, rồi mới quyết định tích hợp thay đổi thế nào.
8. .gitignore hoạt động ra sao, và vì sao tệp vẫn được theo dõi dù đã thêm vào đó?
.gitignore định nghĩa các mẫu tệp mà Git không nên đề xuất thêm: phụ thuộc, sản phẩm build, nhật ký, cấu hình cục bộ chứa bí mật. Quy tắc chỉ áp dụng cho tệp chưa được theo dõi.
Nếu tệp đã từng được commit, việc bỏ qua không có tác dụng. Cần gỡ nó khỏi index nhưng giữ trên đĩa: git rm --cached config.local.php, rồi commit việc xóa đó. Để biết quy tắc nào đang khớp, dùng git check-ignore -v đường-dẫn.
Nhánh, gộp và xung đột
9. Fast-forward merge là gì?
Nếu nhánh đích không tiến thêm kể từ khi tách ra, khi gộp Git chỉ dịch chuyển con trỏ của nó tới commit cuối của nhánh được gộp — không tạo commit mới. Lịch sử vẫn thẳng hàng.
Cờ --no-ff buộc Git tạo commit gộp ngay cả trong trường hợp này: lịch sử cho thấy một nhóm commit là một tính năng riêng biệt. Cờ --ff-only thì ngược lại: chỉ cho phép fast-forward và từ chối khi cần merge thực sự.
10. Xung đột gộp xảy ra thế nào và giải quyết ra sao?
Xung đột xuất hiện khi cả hai nhánh đều sửa cùng các dòng trong một tệp (hoặc một bên xóa tệp mà bên kia sửa), và Git không tự quyết định được. Git dừng việc gộp và đánh dấu vị trí bằng các ký hiệu <<<<<<<, =======, >>>>>>>.
git status # danh sách tệp có xung đột
# sửa tệp, giữ phiên bản đúng
git add app.js
git commit # với merge; với rebase — git rebase --continue
Câu trả lời tốt còn nêu cách phòng tránh: nhánh nhỏ, kéo nhánh chính về thường xuyên, thống nhất định dạng code. Và nhắc tới git merge --abort khi cần rút lui.
11. Merge và rebase khác nhau thế nào?
merge gộp hai nhánh bằng cách tạo commit gộp với hai cha; các commit hiện có không đổi, lịch sử phản ánh đúng việc làm song song. rebase đặt các commit của nhánh bạn lên trên nhánh khác, tạo bản sao với hash mới; lịch sử thành một đường thẳng.
Quy tắc thông thường: rebase để làm gọn nhánh cục bộ trước khi công bố, merge để tích hợp vào nhánh chung. Rebase các commit đã công bố mà người khác đang dựa vào sẽ tạo bản trùng và nhầm lẫn.
12. Rebase tương tác là gì và dùng để làm gì?
git rebase -i HEAD~5 mở danh sách năm commit gần nhất, và với mỗi commit có thể chọn hành động: pick — giữ, reword — sửa thông điệp, edit — dừng lại để chỉnh sửa, squash và fixup — gộp với commit trước, drop — xóa. Các dòng có thể đổi thứ tự.
Tình huống điển hình: trước pull request, biến «wip», «fix typo», «thêm fix» thành hai hoặc ba commit có ý nghĩa. Cách kết hợp tiện: git commit --fixup=<hash>, rồi git rebase -i --autosquash.
13. Squash merge làm gì và khi nào được chọn?
Với squash merge, mọi commit của nhánh được nén thành một commit trong nhánh đích (git merge --squash hoặc nút trên GitHub/GitLab). Nhánh chính nhận mỗi tính năng đúng một commit.
Lợi ích là lịch sử main sạch. Nhược điểm là mất lịch sử chi tiết bên trong tính năng, và Git không coi nhánh gốc là đã gộp, nên git branch -d sẽ từ chối xóa nó nếu không có -D.
14. Cherry-pick là gì và khi nào hợp lý?
git cherry-pick <hash> áp dụng thay đổi của một commit vào nhánh hiện tại, tạo commit mới có cùng nội dung nhưng hash khác. Trường hợp kinh điển là chuyển bản sửa lỗi từ develop sang nhánh phát hành hoặc hotfix.
Không nên lạm dụng: cùng một bản sửa tồn tại trong hai commit, và khi gộp nhánh sau này có thể xảy ra xung đột. Cờ -x thêm vào thông điệp liên kết tới commit gốc.
Hoàn tác và khôi phục
15. Khác nhau giữa reset --soft, --mixed và --hard?
| Chế độ | Con trỏ nhánh | Index | Thư mục làm việc |
|---|---|---|---|
--soft | dịch chuyển | không đổi | không đổi |
--mixed (mặc định) | dịch chuyển | được đặt lại | không đổi |
--hard | dịch chuyển | được đặt lại | được đặt lại, chỉnh sửa bị mất |
git reset --soft HEAD~3 tiện để làm lại ba commit cuối thành một. --hard nguy hiểm với chỉnh sửa chưa commit: ngay cả reflog cũng không cứu được chúng.
16. git revert khác git reset ở điểm nào?
reset di chuyển con trỏ nhánh về phía sau, thực chất là viết lại lịch sử. revert tạo một commit mới hoàn tác thay đổi của commit được chỉ định, và không viết lại gì.
Vì vậy với commit đã công bố trên nhánh chung, câu trả lời đúng là revert: lịch sử của đồng nghiệp không bị phá, còn việc hoàn tác hiển thị rõ trong log. Với commit gộp, cần chỉ định cha chính: git revert -m 1 <hash>.
17. Làm sao khôi phục commit sau một lệnh git reset --hard nhầm?
Bằng git reflog: nó lưu lịch sử di chuyển của HEAD và các nhánh trên máy bạn (mặc định khoảng 90 ngày). Tìm dòng trước lệnh sai và quay lại:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~2
# 9f8e7d6 HEAD@{1}: commit: Thêm thanh toán
git reset --hard 9f8e7d6
Lưu ý quan trọng: reflog chỉ cứu được những gì đã commit. Thay đổi chưa từng vào commit (hoặc ít nhất là vào stash) thì không thể khôi phục bằng Git.
18. Làm sao hoàn tác thay đổi trong tệp và gỡ tệp khỏi index?
Lệnh hiện đại là git restore app.js (đưa tệp về trạng thái của index) và git restore --staged app.js (gỡ khỏi index nhưng giữ chỉnh sửa). Trước đây người ta dùng git checkout -- app.js và git reset HEAD app.js; hai cách này vẫn hoạt động.
19. git stash là gì và có những điểm cần lưu ý nào?
git stash cất tạm các thay đổi chưa commit và làm sạch thư mục làm việc — ví dụ để chuyển gấp sang hotfix. Lấy lại bằng git stash pop hoặc apply.
Điều cần lưu ý: mặc định không cất các tệp chưa theo dõi (cần -u); khi pop có thể xảy ra xung đột, và khi đó bản ghi không bị xóa khỏi danh sách; stash rất dễ bị quên. Với công việc dài hạn, nên commit vào một nhánh riêng.
Câu hỏi nâng cao và làm việc nhóm
20. Làm sao tìm commit đã làm hỏng một chức năng?
Bằng git bisect — tìm kiếm nhị phân trong lịch sử. Bạn chỉ ra một commit chắc chắn lỗi và một commit chắc chắn đúng, Git chuyển bạn tới điểm giữa, và cứ thế tìm ra thủ phạm trong khoảng log2(N) bước.
git bisect start
git bisect bad # phiên bản hiện tại bị lỗi
git bisect good v2.3.0 # ở đây mọi thứ vẫn chạy
# kiểm tra và trả lời good/bad, cho đến khi Git nêu tên commit
git bisect reset
Nếu có script kiểm tra, quá trình được tự động hóa: git bisect run npm test.
21. Vì sao git push --force nguy hiểm và nên thay bằng gì?
--force ghi đè nhánh từ xa bằng phiên bản của bạn, và các commit mà đồng nghiệp đã kịp push sẽ biến mất khỏi máy chủ. An toàn hơn là git push --force-with-lease: lệnh chỉ ghi đè khi nhánh trên máy chủ đúng như bạn đã thấy ở lần fetch gần nhất.
Force push là chấp nhận được với nhánh tính năng riêng sau rebase; còn với main và các nhánh chung thì thường bị cấm bằng cơ chế bảo vệ nhánh trên máy chủ.
22. Bạn biết những quy trình làm việc (workflow) Git nào?
GitHub Flow: một nhánh chính luôn sẵn sàng triển khai, và các nhánh tính năng ngắn được gộp qua pull request sau khi review và CI. Git Flow: các nhánh main và develop, cùng feature/*, release/*, hotfix/*; phù hợp với sản phẩm có bản phát hành theo phiên bản. Trunk-based development: mọi người tích hợp vào trunk rất thường xuyên, còn phần chưa xong được giấu sau feature flag.
Câu trả lời mạnh giải thích được lựa chọn: với dịch vụ web triển khai liên tục, Git Flow thường thừa; với thư viện có nhiều phiên bản đang được hỗ trợ thì lại hợp lý.
23. Pull request là gì và người ta kiểm tra những gì trong đó?
Pull request (trên GitLab gọi là merge request) là yêu cầu gộp một nhánh, đi qua code review và các kiểm tra CI tự động trước khi được gộp. Đây là tính năng của nền tảng (GitHub, GitLab, Bitbucket), không phải của bản thân Git.
Một PR tốt thì nhỏ, giải quyết một việc, có mô tả rõ ràng và liên kết tới công việc trong hệ thống theo dõi. Người review kiểm tra tính đúng đắn, khả năng đọc hiểu, test, và xem có tệp thừa hay bí mật nào lọt vào hay không.
24. Bạn tuân theo những quy tắc nào khi viết thông điệp commit?
Tiêu đề ngắn (tối đa 50–72 ký tự) ở thể mệnh lệnh — «Thêm kiểm tra email», sau đó một dòng trống và phần thân giải thích «vì sao» thay vì «cái gì» (cái gì đã đổi thì xem trong diff). Nhiều nhóm dùng Conventional Commits: feat:, fix:, docs:, refactor:.
Thông điệp như vậy cho phép sinh changelog tự động, tìm nhanh bằng git log --grep, và hiểu lý do thay đổi sau nhiều năm.
25. Nếu lỡ push mật khẩu lên kho, bạn sẽ làm gì?
Việc đầu tiên là thu hồi và cấp lại bí mật: nó đã bị lộ, dù có xóa sau một phút (bản clone, fork, cache vẫn còn). Sau đó gỡ tệp khỏi theo dõi, thêm vào .gitignore, và nếu cần thì làm sạch lịch sử bằng công cụ như git filter-repo, kèm force push và thông báo cho cả nhóm.
Ở đây người phỏng vấn kiểm tra thứ tự ưu tiên: ứng viên bắt đầu bằng việc viết lại lịch sử và quên xoay vòng khóa là trả lời sai.
Chuẩn bị cho câu hỏi về Git thế nào
Cách đáng tin cậy nhất là đừng học thuộc đáp án, mà tự chạy từng tình huống trong kho thử nghiệm: tạo xung đột và giải quyết, reset --hard rồi khôi phục bằng reflog, gom commit bằng rebase tương tác. Trong buổi phỏng vấn, thường có bài thực hành hoặc yêu cầu vẽ đồ thị commit trước và sau một lệnh — nếu bạn đã làm việc đó bằng tay, câu trả lời sẽ tự nhiên.
Cũng nên thử một bài kiểm tra ngắn về Git để tự đánh giá: không nhìn tài liệu, hãy trả lời điều gì xảy ra với lịch sử sau git rebase main hoặc git revert HEAD. Nếu bạn trả lời chắc chắn câu hỏi «ba khu vực thay đổi thế nào», nền tảng của bạn đã vững.
Tóm lại
Phỏng vấn Git hầu như luôn xoay quanh ba chủ đề: mô hình dữ liệu (commit, nhánh, HEAD, index), tích hợp thay đổi (merge, rebase, xung đột, fetch và pull), và hoàn tác an toàn (reset, revert, reflog). Thêm hiểu biết về quy trình nhóm và pull request là bạn đã bao quát phần lớn các câu hỏi. Tất cả các tình huống này, kể cả làm việc nhóm và công cụ nâng cao, được thực hành trong khóa học Git.
Câu hỏi thường gặp
Người mới được hỏi những câu nào về Git, còn người có kinh nghiệm được hỏi gì?
Người mới thường được hỏi về add, commit, nhánh, xung đột, fetch và pull. Với người có kinh nghiệm, kỳ vọng là hiểu rebase, reflog, quy trình làm việc, chiến lược phát hành và khả năng gỡ một lịch sử bị rối trong nhóm.
Có hay giao bài thực hành về Git khi phỏng vấn không?
Thường là có: yêu cầu giải quyết một xung đột, vẽ đồ thị sau rebase, hoặc chọn lệnh hoàn tác một commit đã công bố. Đôi khi đây là một phần của bài test, và lịch sử commit cũng được đánh giá.
Có cần biết cấu trúc bên trong của Git không?
Ở mức cơ bản thì có: commit lưu ảnh chụp và tham chiếu tới cha, còn nhánh là một con trỏ. Chi tiết về định dạng đối tượng và packfile ít khi được hỏi.
Nhà tuyển dụng có xem lịch sử commit của ứng viên không?
Nhiều khi có: họ xem hồ sơ GitHub hoặc lịch sử của bài tập thử việc. Thông điệp rõ ràng và các commit nguyên tử gọn gàng tạo ấn tượng tốt.
Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Git с нуля до уверенного разработчика”.
- Зачем вообще нужен Git — и почему без него не берут на работу
- Git-процессы в реальных командах: какой workflow выбрать
- Продвинутые инструменты: rebase, stash, cherry-pick и теги