Interview Prep
PracticePortfolio

Categories

  • HTML & CSS41
  • JavaScript40
  • TypeScript42
  • ReactJS40
  • Next.js44
  • Node.js41
  • NestJS44
  • SQL & Database43
  • MongoDB40
  • Git40
  • Docker44
  • GraphQL47
Interview PrepGit

Git

40 questions

20 / 40 questions

1

Git là một hệ quản lý phiên bản phân tán (distributed VCS): mỗi developer clone về sẽ có toàn bộ lịch sử repo trên máy mình, không phụ thuộc một server trung tâm như SVN. Nhờ vậy bạn có thể commit, xem log, tạo branch offline, và mỗi bản clone là một bản backup đầy đủ. Git theo dõi thay đổi bằng snapshot của toàn bộ cây file (không phải delta từng dòng), mỗi snapshot được định danh bằng một hash SHA-1/SHA-256.

2

Git có 3 khu vực: Working Directory (thư mục làm việc, nơi bạn sửa file), Staging Area (còn gọi là index, nơi chuẩn bị nội dung cho commit tiếp theo), và Repository (thư mục .git, nơi lưu các commit đã ghi vĩnh viễn). File di chuyển qua các khu vực: sửa ở working dir → git add đưa vào staging → git commit ghi vào repository.

3

Staging area là vùng đệm cho phép bạn chọn chính xác những thay đổi nào sẽ vào commit tiếp theo, thay vì commit tất cả. git add <file> chụp lại trạng thái hiện tại của file vào index. Điều này cho phép tách một mớ thay đổi thành nhiều commit gọn gàng — ví dụ dùng git add -p để stage từng phần (hunk) của cùng một file.

4

Một commit là một snapshot bất biến của toàn bộ nội dung được track, kèm metadata: tác giả, thời gian, message, và con trỏ tới commit cha (parent). Mỗi commit có một hash SHA (40 ký tự hex với SHA-1) được tính từ nội dung + metadata + parent, nên chỉ cần đổi một chi tiết là hash đổi hoàn toàn. Chuỗi các parent tạo thành đồ thị lịch sử (DAG), đảm bảo tính toàn vẹn của lịch sử.

5

Một branch chỉ đơn giản là một con trỏ (pointer) di động trỏ tới một commit — về bản chất là một file text chứa hash trong .git/refs/heads/. Vì thế tạo branch trong Git cực kỳ nhẹ và nhanh, khác hẳn các VCS phải copy cả thư mục. Khi bạn commit trên một branch, con trỏ branch đó tự động dời lên commit mới.

6

HEAD là con trỏ tới commit/branch hiện tại bạn đang làm việc — thường HEAD trỏ tới một branch (ví dụ main). Detached HEAD xảy ra khi bạn git checkout <commit-hash> hoặc một tag: HEAD trỏ thẳng vào một commit thay vì một branch. Commit tạo ra ở trạng thái này sẽ không thuộc branch nào và dễ bị mất; muốn giữ lại phải tạo branch mới: git switch -c <new-branch>.

7

merge tạo một merge commit gộp hai nhánh, giữ nguyên lịch sử thật (có nhánh rẽ). rebase dời các commit của nhánh lên đầu nhánh đích, cho lịch sử thẳng, sạch nhưng viết lại commit (đổi hash). Quy tắc vàng: không rebase nhánh đã push/chia sẻ với người khác.

8

Fast-forward xảy ra khi nhánh đích không có commit mới nào so với nhánh cần merge — Git chỉ dời con trỏ về phía trước, không tạo merge commit, lịch sử phẳng. git merge --no-ff buộc tạo một merge commit dù có thể fast-forward, giúp giữ lại dấu vết rằng "một feature branch đã được gộp vào đây".

git merge --no-ff feature/login
9

Conflict xảy ra khi hai nhánh sửa cùng vùng của cùng một file theo cách khác nhau, Git không tự quyết được giữ bên nào. Git đánh dấu vùng xung đột bằng <<<<<<<, =======, >>>>>>>. Bạn mở file sửa tay chọn nội dung đúng, xóa các marker, rồi git add <file> và git commit (hoặc git merge --continue). Có thể dùng git mergetool hoặc git merge --abort để hủy.

10

Cả ba đều dời con trỏ branch về commit chỉ định, khác nhau ở việc động tới staging & working dir:

  • --soft: giữ nguyên staging + working dir (các thay đổi nằm ở staged).
  • --mixed (mặc định): reset staging nhưng giữ working dir (thay đổi thành unstaged).
  • --hard: reset cả staging lẫn working dir — mất thay đổi chưa commit, cần cẩn thận.
11

git reset dời lịch sử về sau (bỏ commit), viết lại lịch sử — chỉ nên dùng cho commit cục bộ chưa push. git revert tạo một commit mới đảo ngược thay đổi của commit cũ, không xóa lịch sử — an toàn cho nhánh đã chia sẻ. Quy tắc: nhánh public dùng revert, nhánh private có thể dùng reset.

12

checkout là lệnh cũ đa năng (chuyển branch, khôi phục file, detach HEAD...) nên dễ gây nhầm. Git tách nó thành hai lệnh rõ nghĩa: git switch chỉ để chuyển/tạo branch (switch -c), còn git restore chỉ để khôi phục file (bỏ thay đổi working dir hoặc unstage với --staged). Khuyến khích dùng switch/restore cho code mới.

13

git stash cất tạm các thay đổi chưa commit (working dir + staging) vào một stack và trả working dir về sạch, hữu ích khi cần chuyển branch gấp mà chưa muốn commit dở. Lấy lại bằng git stash pop (áp dụng + xóa khỏi stack) hoặc git stash apply (giữ lại).

git stash push -m "WIP: dang lam form"
git stash list
git stash pop
14

git cherry-pick <commit> sao chép một (hoặc vài) commit cụ thể từ nhánh khác vào nhánh hiện tại, tạo ra commit mới với cùng thay đổi nhưng hash khác. Hữu ích khi muốn lấy đúng một fix mà không merge cả nhánh. Cẩn thận vì có thể tạo commit trùng lặp nội dung và gây conflict nếu lạm dụng.

15

git log xem lịch sử commit. Các option hay dùng: --oneline (gọn một dòng), --graph (vẽ đồ thị nhánh), --all (mọi branch), -p (kèm diff), --stat (thống kê file), --author=, --since=, -n 5 (giới hạn số commit).

git log --oneline --graph --all --decorate
16

git diff so sánh sự khác biệt giữa các trạng thái. Mặc định git diff so working dir với staging (thay đổi chưa stage); git diff --staged (hay --cached) so staging với commit cuối (sẽ vào commit tiếp theo); git diff <commitA> <commitB> so hai commit; git diff main..feature so hai nhánh.

17

Remote là một bản repo đặt ở nơi khác (thường trên server như GitHub) mà bạn đồng bộ tới. origin chỉ là tên mặc định Git đặt cho remote khi bạn git clone — không có gì đặc biệt, chỉ là quy ước. Xem/quản lý bằng git remote -v, git remote add <name> <url>.

18

git fetch tải commit mới từ remote về nhưng không thay đổi nhánh làm việc của bạn — chỉ cập nhật các remote-tracking branch (như origin/main), an toàn để xem trước. git pull = git fetch + git merge (hoặc git pull --rebase = fetch + rebase), tức tải và gộp luôn vào nhánh hiện tại. Nếu muốn kiểm soát, hãy fetch rồi tự merge/rebase.

19

Một tracking branch là nhánh local được liên kết với một nhánh trên remote (gọi là upstream), giúp git push/git pull biết đẩy/kéo về đâu mà không cần chỉ rõ mỗi lần. Thiết lập bằng git push -u origin <branch> (lần đầu) hoặc git branch --set-upstream-to=origin/main. Khi đó git status báo bạn "ahead/behind" bao nhiêu commit so với upstream.

20

git push đẩy commit local lên remote. Nếu bạn đã rewrite history (rebase/amend), push thường bị từ chối vì không fast-forward. git push --force ghi đè lịch sử remote — có thể xóa commit của người khác. An toàn hơn là git push --force-with-lease: chỉ ghi đè nếu remote chưa thay đổi so với bản bạn thấy, tránh đè mất công của đồng đội.