Nhiều lập trình viên dùng Git hàng ngày nhưng chưa chắc đã hiểu rõ bên trong nó hoạt động ra sao. Bài viết này sẽ đi qua các khái niệm nền tảng của Git: Repository, Commit, Staging Area, Branch và Merge.


Repository

Nói đơn giản, repository là một thư mục chứa toàn bộ source code của dự án cùng với lịch sử thay đổi của nó. Ngoài các file code bình thường, Git tạo thêm một thư mục ẩn .git bên trong để lưu trữ toàn bộ cơ chế theo dõi thay đổi.

Khi bạn khởi tạo một dự án Git mới hoặc clone một dự án có sẵn, chính thư mục .git này biến một folder bình thường thành một Git repository.

Repository tồn tại ở hai nơi:

  • Local repository: Repository nằm trên máy tính cá nhân của bạn. Đây là nơi bạn làm việc hàng ngày.
  • Remote repository: Bản sao của repository được lưu trữ trên server (như GitHub hay GitLab). Nó đóng vai trò trung tâm để cả team cùng chia sẻ code với nhau.

Bạn dùng các thao tác clone, push và pull để đồng bộ lịch sử giữa Local repository và Remote server.

Commands: git-init, git-clone, git-remote, git-push, git-pull, git-fetch

Đồng bộ giữa Local và Remote repository qua git clone, push, pull

Staging Area

Staging Area là nơi bạn chọn lọc những thay đổi nào đã sẵn sàng để đưa vào commit.

Khi bạn sửa file trong working directory, Git nhận biết chúng như là những thay đổi chưa được staged. Trước khi commit, bạn phải chủ động chọn chính xác những thay đổi nào muốn đưa vào. Các thay đổi này có thể thuộc nhiều loại:

  • Thêm (Add): Tạo file hoàn toàn mới.
  • Sửa (Edit): Chỉnh sửa nội dung file có sẵn.
  • Xoá (Delete): Xoá file khỏi repository.
  • Di chuyển / Đổi tên (Move / Rename): Thay đổi vị trí hoặc tên file.

Bằng cách tách biệt working directory và commit history, staging area cho phép bạn tạo ra những commit gọn gàng, có chủ đích, thay vì ném tất cả mọi thứ đã sửa vào một commit duy nhất.

Commands: git-add, git-rm, git-mv, git-reset, git-status, git-diff

Staging Area cho phép chọn lọc các thay đổi (Thêm, Sửa, Xoá, Di chuyển) để đưa vào commit tiếp theo

Commit

Commit là một bản chụp (snapshot) của repository, nhưng nói cho dễ hiểu, nó giống như một dòng ghi trong sổ cái kế toán.

Thay vì chỉ lưu trạng thái cuối cùng của file, mỗi commit ghi lại chính xác những gì đã xảy ra:

  • File nào bị thay đổi.
  • Chính xác dòng nào được thêm, sửa, hoặc xoá.
  • Ai là người thay đổi (tác giả).
  • Khi nào thay đổi được thực hiện (mốc thời gian).
  • Tham chiếu đến commit trước đó, tạo thành một chuỗi lịch sử liên tục không đứt đoạn.

Vì mỗi commit đều trỏ ngược về commit trước nó, bạn có thể truy vết toàn bộ quá trình phát triển của dự án từng dòng một, hoặc dễ dàng hoàn tác lỗi. Bạn xem các dòng ghi này qua lệnh git log:

$ git log --stat

commit 7b1c4a9d8f3e2a1b5c6d7e8f9a0b1c2d3e4f5a6b
Author: trviph <[email protected]>
Date:   Wed Feb 28 10:45:12 2026 +0700

    feat: write first post

 content/en/posts/git-1.md | 95 ++++++++++++++++++++++++++++++
 static/img/git/staging.svg |  1 +
 2 files changed, 96 insertions(+)

Commands: git-commit, git-log, git-show, git-revert

Branch và Merge

Branch đại diện cho một nhánh phát triển độc lập. Về bản chất, branch là một con trỏ đến commit cụ thể, nơi lịch sử của bạn rẽ nhánh ra khỏi dòng chính.

Khi làm feature mới hoặc sửa bug, bạn tạo branch để cách ly công việc. Điều này cho phép nhiều người cùng làm việc trên cùng một codebase mà không giẫm chân nhau.

Khi công việc trên branch hoàn tất, nó cần được gộp lại vào dự án chính. Merge là quá trình lấy lịch sử đã phân nhánh và kết hợp nó trở lại thành một dòng thời gian thống nhất.

Xét kịch bản sau khi hai người cùng tạo branch từ dự án chính:

  1. Dự án có lịch sử ban đầu là A -> B -> C.
  2. User 1 tạo branch mới tại commit C và tạo ba commit: C1, C2, C3.
  3. Trong lúc đó, nhánh chính nhận thêm commit D.
  4. User 2 tạo branch mới từ D và tạo commit D1.

Commands: git-branch, git-checkout, git-switch, git-merge, git-rebase

Cây lịch sử Git với các branch phân nhánh tại commit C và D

Khi các branch sẵn sàng để merge:

  1. User 2 hoàn thành trước và merge D1 vào nhánh chính.
  2. User 1 hoàn thành sau và merge C1, C2, C3 vào sau merge của User 2.

Kết quả là nhánh chính trở thành: A -> B -> C -> D -> D1 Merge -> C Merge. Mỗi merge commit gắn kết lịch sử của branch trở lại vào nhánh chính.

Lịch sử merge: User 2 merge trước, User 1 merge sau

Khi san phẳng cây ra, toàn bộ lịch sử commit trên main trở thành một dòng thời gian tuyến tính:

Dòng thời gian tuyến tính sau khi merge

Mọi commit từ mọi branch đều hiện rõ trong một đường thẳng duy nhất. Đây là sức mạnh của merge: không có công sức nào bị mất, và mọi thay đổi đều truy vết được ai làm, lúc nào.

Merge Conflicts

Merge không phải lúc nào cũng suôn sẻ. Khi hai branch cùng sửa chính xác cùng một dòng trong cùng một file, Git không thể tự quyết định giữ phiên bản nào. Đây gọi là merge conflict.

Khi conflict xảy ra, Git sẽ tạm dừng merge và đánh dấu các đoạn xung đột trong file. Bạn phải tự tay chọn giữ đoạn nào, sau đó stage và commit kết quả. Chỉ khi đó merge commit mới được tạo.

Conflict là chuyện bình thường. Nó không có nghĩa là có gì đó sai, chỉ đơn giản là hai người cùng sửa một chỗ vào cùng một lúc.