Git là một hệ thống kiểm soát phiên bản phân tán mã nguồn mở, được tạo ra bởi Linus Torvalds vào năm 2005 để phát triển nhân Linux. Không giống như các hệ thống tập trung như SVN, Git lưu trữ một bản sao đầy đủ của kho chứa trên mỗi thiết bị của nhà phát triển, cho phép làm việc mà không cần kết nối liên tục với máy chủ. Theo Git SCM, 2024, Git được sử dụng trong hơn 90% tất cả các dự án phát triển phần mềm thương mại.
Những điểm chính
Git là một hệ thống kiểm soát phiên bản phân tán (VCS) theo dõi các thay đổi trong tệp và cho phép nhiều nhà phát triển làm việc trên cùng một dự án đồng thời. Không giống như các hệ thống tập trung, trong Git mỗi nhà phát triển có một bản sao đầy đủ của kho chứa, bao gồm toàn bộ lịch sử thay đổi, làm cho hệ thống có khả năng chống mất dữ liệu và không yêu cầu kết nối liên tục đến máy chủ trung tâm.
Lịch sử của Git bắt đầu vào năm 2005, khi Linus Torvalds tạo ra một VCS mới sau khi BitKeeper thu hồi giấy phép miễn phí cho các nhà phát triển nhân Linux. Các mục tiêu là: tốc độ, đơn giản của kiến trúc, hỗ trợ phát triển phi tuyến tính thông qua rẽ nhánh và phân tán hoàn toàn. Trong 3 tháng, Torvalds đã viết nhân của Git, và trong vòng một năm, dự án đã trở thành tự quản dưới sự lãnh đạo của Junio Hamano.
Theo khảo sát Stack Overflow (2024), Git được 93,9% nhà phát triển chuyên nghiệp sử dụng, trở thành hệ thống kiểm soát phiên bản thống trị trong ngành. Đối thủ cạnh tranh gần nhất — Subversion (SVN) — chỉ được sử dụng trong 5,2% dự án, chủ yếu trong các môi trường doanh nghiệp lớn với quy trình tập trung.
Kho chứa Git là một thư mục nơi Git theo dõi các thay đổi của tất cả tệp. Bên trong thư mục có một thư mục ẩn .git lưu trữ tất cả các đối tượng hệ thống: commit, cây, blob và tham chiếu. Khi một nhà phát triển tạo commit, Git không sao chép toàn bộ tệp — nó tạo một ảnh chụp nhanh và lưu một tham chiếu đến nó.
Mỗi commit chứa: một hàm băm SHA-1 duy nhất (40 ký tự), tham chiếu đến commit trước đó (parent), tác giả, ngày tháng, thông điệp commit và tham chiếu đến một cây mô tả trạng thái của các tệp tại thời điểm commit. Chuỗi các commit tạo thành một đồ thị có hướng không chu trình, nơi mỗi commit trỏ đến một hoặc nhiều cha.
# Khởi tạo kho chứa
git init my-project
cd my-project
# Tạo commit
echo "Xin chào, Git" > README.md
git add README.md
git commit -m "Initial commit"
# Xem lịch sử
git log --oneline --graph --all
Git sử dụng ba khu vực chính: working directory (tệp trên đĩa), staging area (chỉ mục nơi các tệp đã chuẩn bị được đặt) và repository (lịch sử commit). Lệnh git add di chuyển các thay đổi từ thư mục làm việc vào staging, và git commit ghi lại nội dung của staging vào kho chứa. Sự phân tách này cho phép nhà phát triển tập hợp một commit có ý nghĩa từ một tập hợp các thay đổi mà không cần commit từng chỉnh sửa riêng lẻ.
Các lệnh Git cơ bản bao phủ 90% các thao tác hàng ngày của nhà phát triển. Lệnh git clone tạo một bản sao cục bộ của kho chứa từ xa, git pull lấy thay đổi từ máy chủ và hợp nhất chúng với nhánh hiện tại, và git push gửi các commit cục bộ lên máy chủ. Ba lệnh này tạo thành chu kỳ chính của quy trình làm việc với Git.
Để xem trạng thái, sử dụng git status — nó hiển thị tệp nào đã được sửa đổi, tệp nào đã được thêm vào staging và tệp nào không được theo dõi. git diff hiển thị các thay đổi cụ thể trong tệp trước khi thêm vào staging. Dưới đây là bảng các lệnh thường được sử dụng nhất:
| Lệnh | Hành động | Ví dụ |
|---|---|---|
| git clone | Sao chép kho chứa từ xa | git clone https://example.com/repo |
| git add | Thêm tệp vào staging | git add src/main.kt |
| git commit | Ghi lại thay đổi trong lịch sử | git commit -m “Sửa lỗi đăng nhập” |
| git push | Gửi commit lên máy chủ | git push origin main |
| git pull | Lấy thay đổi từ máy chủ | git pull origin feature |
Để hoàn tác thay đổi, Git cung cấp một số tùy chọn. git reset di chuyển con trỏ nhánh đến một commit được chỉ định và có thể đặt lại staging hoặc thư mục làm việc. git revert tạo một commit mới để hoàn tác các thay đổi của commit được chỉ định — đây là cách hoàn tác an toàn cho các nhánh chia sẻ vì lịch sử không bị ghi đè.
Các nhánh trong Git là các con trỏ di động nhẹ trỏ đến một commit cụ thể. Tạo một nhánh mới không sao chép tệp mà chỉ đơn giản tạo một con trỏ mới, làm cho việc rẽ nhánh gần như tức thì. Nhánh main (trước đây là master) là nhánh chính của dự án chứa mã ổn định, sẵn sàng phát hành.
Thực hành tiêu chuẩn là sử dụng Git Flow hoặc GitHub Flow. Git Flow sử dụng các nhánh: main (mã phát hành), develop (nhánh tích hợp), feature/* (tính năng mới), release/* (chuẩn bị phát hành) và hotfix/* (sửa lỗi khẩn cấp). GitHub Flow đơn giản hơn: chỉ có main và các nhánh tính năng, và tất cả thay đổi được phân phối qua Pull Request.
# Tạo và chuyển nhánh
git branch feature-auth
git checkout feature-auth
# hoặc bằng một lệnh:
git checkout -b feature-auth
# Danh sách nhánh
git branch --list
git branch -a # tất cả các nhánh, kể cả đã xóa
# Xóa nhánh
git branch -d feature-auth
Một tính năng quan trọng của rẽ nhánh trong Git là cherry-pick: di chuyển một commit riêng lẻ từ nhánh này sang nhánh khác bằng lệnh git cherry-pick <hash>. Điều này hữu ích khi bạn cần chuyển một bản sửa lỗi từ nhánh tính năng sang bản phát hành mà không cần hợp nhất toàn bộ nhánh. Git cũng hỗ trợ rebase và rebase tương tác (git rebase -i) để gộp, sắp xếp lại và chỉnh sửa commit.
Merge (hợp nhất) tạo một commit hợp nhất đặc biệt có hai cha. Commit này ghi lại sự kiện hợp nhất hai nhánh và giữ nguyên toàn bộ lịch sử — có thể thấy nơi nào và khi nào việc hợp nhất xảy ra. Merge bảo toàn lịch sử như nó được tạo ra, giúp đơn giản hóa việc kiểm tra nhưng làm cho đồ thị commit phức tạp hơn.
Rebase thay vì tạo một commit hợp nhất, di chuyển các commit của nhánh hiện tại lên đỉnh của nhánh mục tiêu. Lịch sử trở nên tuyến tính — tạo ấn tượng rằng việc phát triển diễn ra tuần tự. Tuy nhiên, rebase ghi đè lịch sử, thay đổi hàm băm SHA-1 của các commit, khiến nó trở nên nguy hiểm cho các nhánh chia sẻ mà các nhà phát triển khác có quyền truy cập.
Khuyến nghị: sử dụng merge cho các nhánh công khai nơi lịch sử hiển thị với các nhà phát triển khác (feature → develop), và rebase cho công việc cục bộ khi bạn cần áp dụng các thay đổi mới từ main vào nhánh tính năng của mình trước khi tạo Pull Request. Quy tắc rất đơn giản: nếu một commit đã được đẩy lên máy chủ — đừng rebase nó.
Xung đột hợp nhất xảy ra khi Git không thể tự động hợp nhất các thay đổi trong một tệp duy nhất. Git đánh dấu các phần xung đột trong tệp bằng các điểm đánh dấu đặc biệt: <<<<<<< (thay đổi của chúng ta), ======= (dấu phân cách), >>>>>>> (thay đổi của họ). Nhà phát triển chỉnh sửa tệp thủ công, chọn tùy chọn mong muốn hoặc kết hợp cả hai, và hoàn tất việc hợp nhất bằng một commit.
Kho chứa từ xa (remote) là một bản sao của kho Git nằm trên máy chủ. GitHub, GitLab và Bitbucket là các nền tảng phổ biến nhất để lưu trữ kho chứa từ xa. Chúng cung cấp giao diện web để xem mã, quản lý truy cập, đánh giá mã và tích hợp với các hệ thống CI/CD.
Trong Git, bạn có thể cấu hình nhiều kho chứa từ xa cho một dự án. Theo mặc định, remote chính được gọi là origin. Lệnh git remote add thêm một remote mới, git fetch lấy thay đổi mà không hợp nhất, và git pull là viết tắt của git fetch + git merge. Để làm việc với mã qua Pull Request, nhà phát triển tạo một fork của kho chứa, sao chép nó, làm việc trong nhánh tính năng và gửi yêu cầu hợp nhất đến kho chứa gốc.
# Thêm kho chứa từ xa
git remote add origin https://github.com/user/repo.git
# Xem các kho chứa từ xa
git remote -v
# Đẩy nhánh lên máy chủ
git push -u origin feature-auth
# Lấy thay đổi từ nhánh từ xa
git pull origin main
Các kho chứa từ xa hỗ trợ gắn thẻ để đánh dấu các phiên bản phát hành. Thẻ có thể là nhẹ (chỉ là con trỏ đến một commit) hoặc có chú thích (chứa siêu dữ liệu: tác giả, ngày tháng, thông điệp). Thẻ có chú thích được khuyến nghị cho các phiên bản phát hành vì chúng mang thông tin phiên bản đầy đủ và có thể được ký bằng khóa GPG để xác minh tác giả.
Git Worktree cho phép bạn làm việc đồng thời với nhiều nhánh trong các thư mục khác nhau mà không cần chuyển đổi giữa chúng. Lệnh git worktree add ../feature-auth feature-auth tạo một thư mục làm việc mới feature-auth nơi bạn có thể viết mã mà không cần chuyển nhánh trong thư mục chính. Worktree hữu ích cho các sửa chữa nhanh trong nhánh phát hành khi thư mục chính đang bận với phát triển dài hạn.
Git Submodules là một cơ chế để bao gồm một kho Git bên trong một kho khác. Submodule lưu trữ một tham chiếu đến một commit cố định của kho bên ngoài, đảm bảo khả năng tái tạo bản dựng. Lệnh git submodule add https://github.com/example/lib.git thêm một thư viện bên ngoài như một submodule. Khi sao chép một dự án có submodules, cần thực hiện git submodule update --init --recursive để tải xuống tất cả các phụ thuộc.
Các câu hỏi thường gặp
Git là một VCS phân tán với lịch sử cục bộ và khả năng làm việc ngoại tuyến. SVN là một hệ thống tập trung yêu cầu kết nối liên tục với máy chủ cho mọi thao tác ngoại trừ xem tệp.
Sử dụng git revert HEAD để hoàn tác an toàn (tạo một commit mới). Nếu commit chưa được đẩy lên máy chủ, bạn có thể sử dụng git reset --soft HEAD~1.
.gitignore là một tệp liệt kê các mẫu tệp và thư mục mà Git nên bỏ qua. Nó được sử dụng để loại trừ các tệp tạm thời, bản dựng và cấu hình IDE khỏi kho chứa.
git fetch tải xuống các thay đổi từ máy chủ nhưng không hợp nhất chúng với nhánh hiện tại. git pull thực hiện fetch và ngay lập tức thực hiện merge. Để kiểm soát, hãy sử dụng fetch + xem xét diff, sau đó tự động hợp nhất thủ công.
Sử dụng git commit --amend — lệnh này mở một trình soạn thảo để thay đổi thông điệp commit. Nếu commit đã có trên máy chủ, bạn sẽ cần git push --force, điều này nguy hiểm cho các nhánh chia sẻ.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm