Đối với những nhà phát triển lần đầu tiếp xúc với Git, chuỗi lệnh git add
, git commit
, git push
có thể trông như một "nghi thức ma thuật". Bạn gõ lệnh và bằng một cách nào đó, mã nguồn của bạn được lưu lại và chia sẻ. Nhưng bạn đã bao giờ tự hỏi: Điều gì thực sự xảy ra với một tập tin khi bạn thực hiện những lệnh đó? Tại sao lại cần git add
trước khi commit
?
Hiểu rõ vòng đời của một tập tin chính là chìa khóa để giải mã những bí ẩn này và biến Git từ một công cụ đáng sợ thành một "đồng minh" mạnh mẽ và đáng tin cậy. Hãy cùng nhau khám phá hành trình của một tập tin, từ khi nó được sinh ra trong thư mục dự án cho đến khi được lưu trữ vĩnh viễn trong lịch sử phiên bản.
Nền tảng cốt lõi: 3 trạng thái & 4 khu vực
Trước khi theo dõi hành trình của một tập tin, chúng ta cần làm quen với "bản đồ". Trong thế giới của Git, mọi tập tin bạn làm việc đều tồn tại ở một trong ba trạng thái cốt lõi, và chúng di chuyển giữa bốn khu vực hoạt động riêng biệt.
Ba trạng thái cốt lõi
- Modified (Đã sửa đổi): Tập tin đã có sự thay đổi (bạn đã thêm code, sửa lỗi, xóa một dòng...) nhưng chưa được chính thức đánh dấu để lưu vào lịch sử.
- Staged (Đã dàn dựng): Bạn đã cẩn thận chọn lựa và đánh dấu phiên bản hiện tại của tập tin, sẵn sàng để được ghi vào "cuốn sổ lịch sử" trong lần commit tiếp theo. Đây là trạng thái trung gian vô cùng quan trọng.
- Committed (Đã cam kết): Dữ liệu của tập tin đã được lưu trữ an toàn và vĩnh viễn trong kho chứa (repository) cục bộ của bạn. Nó đã trở thành một phần của lịch sử dự án.
Bốn khu vực hoạt động
- Working Directory (Thư mục làm việc): Đây chính là thư mục dự án trên máy tính của bạn. Là nơi bạn thực sự tạo, chỉnh sửa, và xóa các tập tin. Đây là "sàn diễn" nơi mọi thay đổi diễn ra.
- Staging Area (Khu vực dàn dựng): Hãy tưởng tượng đây là một "khu vực chờ" hay một "cái giỏ hàng". Trước khi "thanh toán" (commit), bạn phải bỏ những món hàng (thay đổi) mà bạn muốn mua vào giỏ. Staging Area cho phép bạn lựa chọn cẩn thận những thay đổi nào sẽ được gộp vào trong lần commit kế tiếp. Về mặt kỹ thuật, đây là một tập tin đặc biệt trong thư mục
.git
của bạn, thường được gọi là "index". - Local Repository (Kho chứa cục bộ): Đây là "cuốn sổ lịch sử" hay "kho lưu trữ" của dự án, được đặt trong thư mục con
.git
. Nó chứa tất cả các commit, tức là tất cả các phiên bản đã lưu của dự án. Mọi thứ ở đây đều an toàn trên máy của bạn. - Remote Repository (Kho chứa từ xa): Một bản sao của kho chứa của bạn, thường được đặt trên một máy chủ từ xa (như GitHub, GitLab). Đây là nơi bạn chia sẻ và đồng bộ hóa công việc của mình với đồng đội.
Hành trình của một tập tin
Bây giờ, hãy cùng theo chân một tập tin có tên là feature.js
trong suốt vòng đời của nó.
Giai đoạn 1: Sự ra đời - Untracked (Chưa được theo dõi)
Bạn vừa tạo một tập tin mới feature.js
trong Working Directory. Vì nó còn quá mới, Git chưa hề biết đến sự tồn tại của nó.
Nếu bạn chạy lệnh git status
, Git sẽ thông báo:
Untracked files:
(use "git add <file>..." to include in what will be committed)
feature.js
Lúc này, feature.js
đang ở trạng thái Untracked. Nó tồn tại trong dự án của bạn, nhưng Git sẽ hoàn toàn phớt lờ nó cho đến khi bạn ra lệnh.
Giai đoạn 2: Bước ra "ánh sáng" - Lệnh git add
Bạn đã viết xong những dòng code đầu tiên cho feature.js
và muốn Git bắt đầu quản lý nó. Đây là lúc bạn sử dụng lệnh git add
.
git add feature.js
Lệnh này thực hiện hai việc quan trọng:
- Nó nói với Git: "Hãy bắt đầu theo dõi tập tin này."
- Nó lấy phiên bản hiện tại của
feature.js
trong Working Directory và sao chép nó vào Staging Area.
Bây giờ, feature.js
đã chuyển sang trạng thái Staged. Chạy git status
lần nữa, bạn sẽ thấy:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: feature.js
Giai đoạn 3: Hóa thành "bất tử" - Lệnh git commit
Staging Area giờ đây giống như một bản nháp hoàn hảo cho lần lưu trữ tiếp theo. Bạn đã sẵn sàng để ghi lại dấu mốc này vào lịch sử. Lệnh git commit
sẽ làm điều đó.
git commit -m "Add initial structure for new feature"
Lệnh này sẽ lấy "ảnh chụp nhanh" (snapshot) của tất cả các tập tin trong Staging Area, gói chúng lại thành một commit, và lưu trữ vĩnh viễn vào Local Repository.
Sau khi commit, feature.js
đã ở trạng thái Committed. Working Directory của bạn được coi là "sạch" vì nó hoàn toàn khớp với phiên bản vừa được lưu trong kho. git status
sẽ báo:
nothing to commit, working tree clean
Giai đoạn 4: Vòng lặp của sự thay đổi
Hành trình chưa kết thúc. Ngày hôm sau, bạn mở feature.js
và thêm một hàm mới. Ngay khi bạn lưu tập tin, Git phát hiện ra rằng phiên bản trong Working Directory đã khác với phiên bản cuối cùng được lưu trong kho.
Tập tin lập tức chuyển sang trạng thái Modified. git status
sẽ hiển thị:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: feature.js
Để lưu lại thay đổi này, bạn phải lặp lại chu trình:
git add feature.js
: Đưa phiên bản đã sửa đổi vào lại Staging Area.git commit -m "Implement new function"
: Lưu lại ảnh chụp nhanh mới từ Staging Area vào kho.
Và cứ thế, vòng đời của tập tin tiếp diễn: modify -> add -> commit.
Phép so sánh dễ nhớ: Xưởng chụp ảnh
Hãy hình dung bạn là một nhiếp ảnh gia và dự án của bạn là một buổi chụp hình:
- Working Directory là toàn bộ bối cảnh lộn xộn ngoài đời thực.
- Staging Area (
git add
) là hành động bạn cẩn thận sắp xếp mọi thứ vào trong khung hình. Bạn chọn người mẫu, chỉnh ánh sáng, quyết định góc máy. Chỉ những gì nằm trong khung hình mới được chụp. - Local Repository (
git commit
) là hành động bấm nút chụp. Bức ảnh (snapshot) được ghi lại và lưu vào album (kho chứa). Bức ảnh đó là bất biến. Bạn không thể thay đổi nó, nhưng bạn luôn có thể chụp một bức ảnh mới.
Phép so sánh này lý giải tại sao git add
lại quan trọng đến vậy. Nó cho phép bạn toàn quyền quyết định thay đổi nào là đủ tốt, đủ hoàn chỉnh để được đưa vào "bức ảnh" lịch sử tiếp theo, thay vì phải chụp lại toàn bộ bối cảnh lộn xộn.
Các công cụ hỗ trợ khác
git diff
: Xem sự khác biệt giữa phiên bản trong Working Directory và Staging Area. (Bạn đã thay đổi những gì nhưng chưaadd
?).git diff --staged
: Xem sự khác biệt giữa phiên bản trong Staging Area và commit cuối cùng. (Bạn đãadd
những gì và sẵn sàng đểcommit
?).git rm <file>
: Xóa một tập tin khỏi Working Directory và đồng thời cũng đưa việc xóa đó vào Staging Area..gitignore
: Một tập tin đặc biệt nơi bạn liệt kê những tập tin hoặc thư mục mà bạn muốn Git phớt lờ hoàn toàn (ví dụ: file log, thư mục chứa các gói cài đặt...).
Hiểu rõ vòng đời này không chỉ giúp bạn sử dụng Git một cách tự tin mà còn giúp bạn gỡ rối các vấn đề một cách hiệu quả. Lần tới khi bạn gõ git status
, bạn sẽ không chỉ đọc thông báo của nó, mà bạn sẽ hiểu được câu chuyện mà Git đang kể về các tập tin của mình.