Hướng dẫn toàn diện về các lệnh và quy trình làm việc với Git

Git là một hệ thống kiểm soát phiên bản phân tán mạnh mẽ, giúp theo dõi các thay đổi trong mã nguồn và phối hợp công việc giữa nhiều nhà phát triển. Để làm việc hiệu quả với Git, việc nắm vững các thuật ngữ và lệnh cơ bản là rất quan trọng. Dưới đây là danh sách các lệnh Git phổ biến và một số chiến lược quản lý nhánh.

Trước khi đi sâu vào các lệnh, hãy cùng tìm hiểu một số khái niệm cốt lõi trong Git:

  • Vùng làm việc (Working Directory): Nơi chứa các tệp dự án thực tế mà bạn đang chỉnh sửa.
  • Vùng đệm (Staging Area/Index): Nơi bạn "chuẩn bị" các thay đổi trước khi cam kết chúng vào kho lưu trữ. Đây là một lớp trung gian giữa vùng làm việc và kho lưu trữ cục bộ.
  • Kho lưu trữ cục bộ (Local Repository): Nơi Git lưu trữ toàn bộ lịch sử các cam kết (commit) của dự án trên máy tính của bạn.
  • Kho lưu trữ từ xa (Remote Repository): Một kho lưu trữ Git được đặt trên máy chủ từ xa (ví dụ: GitHub, GitLab, Bitbucket), được sử dụng để chia sẻ và đồng bộ mã nguồn với các thành viên khác trong nhóm.

Liên kết nhánh cục bộ với nhánh từ xa

Khi làm việc với các kho lưu trữ từ xa, việc liên kết một nhánh cục bộ với một nhánh từ xa tương ứng là cần thiết để dễ dàng sử dụng các lệnh pull và push. Bạn có thể thiết lập liên kết theo dõi (tracking relationship) bằng lệnh sau:

git branch --set-upstream-to=origin/ten_nhanh_tu_xa ten_nhanh_cuc_bo

Ví dụ, để liên kết nhánh my-feature cục bộ với nhánh origin/my-feature từ xa:

git branch --set-upstream-to=origin/my-feature my-feature

Giải quyết vấn đề khi đẩy mã sau khi thay đổi mật khẩu

Đôi khi, sau khi thay đổi mật khẩu tài khoản Git trên dịch vụ lưu trữ từ xa, bạn có thể gặp lỗi khi thực hiện lệnh git push. Điều này thường xảy ra do Git vẫn đang sử dụng thông tin xác thực cũ được lưu trong bộ nhớ đệm.

Để khắc phục, bạn cần xóa thông tin xác thực đã lưu và cấu hình lại trợ lý thông tin xác thực:

# Xóa thông tin xác thực đã lưu trong hệ thống (nếu có)
git config --system --unset credential.helper

# Cấu hình Git để lưu trữ thông tin xác thực cho lần sử dụng sau
# Lần đẩy tiếp theo bạn sẽ được yêu cầu nhập lại mật khẩu
git config --global credential.helper store

Sau khi thực hiện các lệnh trên, lần tiếp theo bạn git push, Git sẽ yêu cầu bạn nhập lại mật khẩu mới, và sau đó sẽ lưu trữ nó cho các thao tác sau này.

1. Khởi tạo kho lưu trữ Git

Để bắt đầu làm việc với Git, bạn cần tạo hoặc sao chép một kho lưu trữ (repository). Dưới đây là các lệnh cơ bản để thực hiện việc này:

  • Khởi tạo kho lưu trữ mới trong thư mục hiện tại:
# Biến thư mục hiện tại thành một kho lưu trữ Git
git init
  • Khởi tạo kho lưu trữ mới trong một thư mục chỉ định:
# Tạo một thư mục mới có tên 'my-project' và khởi tạo Git bên trong nó
git init my-project
  • Sao chép một kho lưu trữ hiện có từ xa:
# Tải về toàn bộ lịch sử dự án từ một URL kho lưu trữ từ xa
git clone https://github.com/user/repo.git

Lệnh git clone sẽ không chỉ tải xuống các tệp mà còn cả toàn bộ lịch sử cam kết của dự án, đồng thời tự động thiết lập một kho lưu trữ cục bộ và một nhánh origin/master theo dõi kho lưu trữ từ xa.

2. Cấu hình Git

Git có các tệp cấu hình (.gitconfig) có thể được đặt ở nhiều cấp độ khác nhau: cấp hệ thống (áp dụng cho tất cả người dùng trên máy), cấp người dùng (~/.gitconfig, áp dụng cho tất cả các kho lưu trữ của người dùng đó), và cấp dự án (.git/config, chỉ áp dụng cho kho lưu trữ hiện tại).

  • Hiển thị cấu hình Git hiện tại:
# Liệt kê tất cả các thiết lập Git hiện hành
git config --list
  • Chỉnh sửa tệp cấu hình Git:
# Mở trình chỉnh sửa văn bản để sửa đổi cấu hình cấp người dùng
git config -e --global
# Mở trình chỉnh sửa văn bản để sửa đổi cấu hình cấp dự án
git config -e
  • Thiết lập thông tin người dùng cho các cam kết:

Đây là một bước quan trọng để xác định ai là người thực hiện các cam kết mã. Thông tin này sẽ xuất hiện trong lịch sử cam kết.

# Thiết lập tên người dùng cho tất cả các kho lưu trữ
git config --global user.name "Tên Của Bạn"
# Thiết lập địa chỉ email cho tất cả các kho lưu trữ
git config --global user.email "email@example.com"

# Hoặc thiết lập chỉ cho kho lưu trữ hiện tại (bỏ '--global')
git config user.name "Tên Của Bạn"
git config user.email "email@example.com"

3. Thêm/Xóa tệp

Các lệnh này giúp bạn quản lý các tệp trong vùng làm việc và chuyển chúng vào vùng đệm để chuẩn bị cho cam kết.

  • Thêm các tệp cụ thể vào vùng đệm:
# Thêm file1.txt và file2.js vào vùng đệm
git add file1.txt file2.js
  • Thêm một thư mục vào vùng đệm (bao gồm cả thư mục con):
# Thêm thư mục 'src' cùng tất cả nội dung của nó
git add src/
  • Thêm tất cả các thay đổi trong thư mục hiện tại vào vùng đệm:
# Thêm tất cả các tệp mới và đã sửa đổi vào vùng đệm
git add .
  • Thêm các thay đổi tương tác (patch-mode):
# Duyệt qua từng thay đổi (chunk) và quyết định có thêm vào vùng đệm hay không
git add -p
  • Xóa tệp khỏi vùng làm việc và vùng đệm:
# Xóa file_can_xoa.txt khỏi cả vùng làm việc và vùng đệm, chuẩn bị cho commit
git rm file_can_xoa.txt
  • Ngừng theo dõi tệp nhưng vẫn giữ tệp trong vùng làm việc:
# Xóa tệp khỏi vùng đệm và kho lưu trữ, nhưng giữ nguyên trong vùng làm việc
git rm --cached file_khong_theo_doi.log
  • Đổi tên tệp và chuẩn bị cho cam kết:
# Đổi tên old_name.txt thành new_name.txt và đưa thay đổi này vào vùng đệm
git mv old_name.txt new_name.txt

4. Cam kết thay đổi (Commit)

Sau khi các thay đổi được thêm vào vùng đệm, bạn cần cam kết chúng vào kho lưu trữ cục bộ. Mỗi cam kết đại diện cho một "phiên bản" cụ thể của dự án và thường đi kèm với một thông điệp mô tả thay đổi.

  • Cam kết các thay đổi từ vùng đệm vào kho lưu trữ:
# Cam kết tất cả các tệp đã được 'git add' vào vùng đệm
git commit -m "Thêm tính năng đăng nhập người dùng"
  • Cam kết các tệp cụ thể từ vùng đệm:
# Cam kết chỉ các tệp 'api.js' và 'auth.js' đã được add vào vùng đệm
git commit api.js auth.js -m "Cập nhật logic xác thực API"
  • Tự động thêm và cam kết các tệp đã theo dõi (tracking files):
# Tự động thêm các tệp đã được sửa đổi (nhưng chưa 'add') vào vùng đệm và cam kết.
# Không bao gồm các tệp mới chưa được Git theo dõi.
git commit -a -m "Tối ưu hóa hiệu suất hiển thị"
  • Cam kết với hiển thị sự khác biệt đầy đủ:
# Khi thực hiện commit, hiển thị tất cả các thay đổi chi tiết (diff)
git commit -v -m "Sửa lỗi chính tả trong tài liệu"
  • Sửa đổi cam kết gần đây nhất:

Lệnh --amend cho phép bạn sửa đổi cam kết cuối cùng. Điều này hữu ích khi bạn muốn cập nhật thông điệp cam kết hoặc thêm các thay đổi nhỏ mà bạn quên đưa vào cam kết trước đó.

# Thay đổi thông điệp của cam kết gần nhất
git commit --amend -m "Cập nhật lại thông điệp commit cuối cùng"

# Thêm các thay đổi mới vào cam kết cuối cùng (sau khi đã 'git add' các thay đổi mới)
git add new_change.txt
git commit --amend --no-edit # Giữ nguyên thông điệp commit cũ, chỉ thêm file

5. Quản lý nhánh (Branches)

Nhánh là một tính năng cốt lõi của Git, cho phép bạn phát triển các tính năng, sửa lỗi hoặc thử nghiệm ý tưởng mới một cách độc lập mà không ảnh hưởng đến mã nguồn chính. Các lệnh dưới đây giúp bạn làm việc với các nhánh:

  • Liệt kê các nhánh:
# Liệt kê tất cả các nhánh cục bộ
git branch

# Liệt kê tất cả các nhánh từ xa
git branch -r

# Liệt kê cả nhánh cục bộ và nhánh từ xa
git branch -a
  • Tạo nhánh mới:
# Tạo một nhánh mới có tên 'feature/add-payment' nhưng vẫn ở nhánh hiện tại
git branch feature/add-payment
  • Tạo và chuyển sang nhánh mới:
# Tạo nhánh 'feature/user-profile' và ngay lập tức chuyển sang nhánh đó
git checkout -b feature/user-profile

# Tương đương với:
# git branch feature/user-profile
# git checkout feature/user-profile
  • Tạo nhánh mới từ một nhánh từ xa và chuyển sang đó:
# Tạo nhánh cục bộ 'my-local-feature' dựa trên 'origin/another-feature' và chuyển sang
git checkout -b my-local-feature origin/another-feature
  • Tạo nhánh mới trỏ đến một cam kết cụ thể:
# Tạo nhánh 'bugfix/old-version' từ một cam kết có ID 'abc1234'
git branch bugfix/old-version abc1234
  • Chuyển đổi giữa các nhánh:
# Chuyển sang nhánh 'develop'
git checkout develop

# Chuyển về nhánh bạn vừa ở trước đó
git checkout -
  • Thiết lập liên kết theo dõi cho một nhánh cục bộ:
# Thiết lập nhánh cục bộ 'feature-x' để theo dõi 'origin/feature-x'
git branch --set-upstream-to=origin/feature-x feature-x
  • Hợp nhất (Merge) các nhánh:

Lệnh merge tích hợp lịch sử cam kết từ một nhánh này sang nhánh khác.

# Đang ở nhánh 'develop', hợp nhất các thay đổi từ nhánh 'feature/new-ui' vào
git merge feature/new-ui
  • Chọn cam kết cụ thể để hợp nhất (Cherry-pick):

Thay vì hợp nhất toàn bộ một nhánh, bạn có thể chọn một hoặc nhiều cam kết cụ thể từ một nhánh khác để áp dụng vào nhánh hiện tại.

# Áp dụng cam kết 'def5678' vào nhánh hiện tại
git cherry-pick def5678
  • Xóa nhánh:

Sau khi một nhánh đã được hợp nhất và không còn cần thiết, bạn nên xóa nó để giữ cho kho lưu trữ gọn gàng.

# Xóa nhánh cục bộ 'feature/add-payment' (chỉ khi đã được merge)
git branch -d feature/add-payment

# Xóa nhánh cục bộ 'testing-branch' dù chưa merge (sử dụng -D để buộc xóa)
git branch -D testing-branch

# Xóa nhánh từ xa 'origin/old-feature'
git push origin --delete old-feature
# Hoặc:
git push origin :old-feature

6. Gắn thẻ (Tags)

Git tags được sử dụng để đánh dấu các điểm quan trọng trong lịch sử dự án, thường là các bản phát hành (releases) hoặc các mốc quan trọng khác. Các thẻ này không thay đổi, không giống như các nhánh.

  • Liệt kê tất cả các thẻ:
# Hiển thị tất cả các thẻ trong kho lưu trữ
git tag
  • Tạo thẻ nhẹ (lightweight tag) tại cam kết hiện tại:
# Tạo thẻ 'v1.0.0' tại cam kết HEAD hiện tại
git tag v1.0.0
  • Tạo thẻ chú thích (annotated tag) tại cam kết hiện tại:

Thẻ chú thích chứa thêm thông tin như tên người tạo, email, ngày tháng và một thông điệp. Chúng được lưu trữ dưới dạng đối tượng đầy đủ trong cơ sở dữ liệu của Git.

# Tạo thẻ chú thích 'v1.0.1' với thông điệp
git tag -a v1.0.1 -m "Bản vá lỗi quan trọng 1.0.1"
  • Tạo thẻ tại một cam kết cụ thể:
# Tạo thẻ 'alpha-release' cho cam kết có ID 'abcde123'
git tag alpha-release abcde123
  • Xóa thẻ cục bộ:
# Xóa thẻ 'old-tag' khỏi kho lưu trữ cục bộ
git tag -d old-tag
  • Xóa thẻ từ kho lưu trữ từ xa:
# Xóa thẻ 'release-candidate' từ kho lưu trữ từ xa 'origin'
git push origin --delete release-candidate
# Hoặc cú pháp cũ hơn:
git push origin :refs/tags/release-candidate
  • Xem thông tin chi tiết về thẻ:
# Hiển thị thông tin chi tiết của thẻ 'v1.0.0'
git show v1.0.0
  • Đẩy thẻ lên kho lưu trữ từ xa:

Thẻ không tự động được đẩy lên kho lưu trữ từ xa cùng với các cam kết. Bạn cần đẩy chúng một cách rõ ràng.

# Đẩy một thẻ cụ thể 'v1.0.0' lên kho lưu trữ 'origin'
git push origin v1.0.0

# Đẩy tất cả các thẻ cục bộ lên kho lưu trữ từ xa
git push origin --tags
  • Tạo một nhánh mới từ một thẻ:
# Tạo nhánh 'hotfix/v1.0.0' từ thẻ 'v1.0.0' và chuyển sang nhánh đó
git checkout -b hotfix/v1.0.0 v1.0.0

7. Xem thông tin và lịch sử dự án

Git cung cấp nhiều lệnh để kiểm tra trạng thái của kho lưu trữ, xem lịch sử cam kết và so sánh các phiên bản khác nhau của tệp.

  • Kiểm tra trạng thái vùng làm việc và vùng đệm:
# Hiển thị các tệp đã sửa đổi, đã thêm vào vùng đệm, và các tệp chưa được theo dõi
git status
  • Xem lịch sử cam kết:
# Hiển thị lịch sử cam kết theo thứ tự thời gian, từ mới nhất đến cũ nhất
git log

# Hiển thị lịch sử cam kết cùng với số liệu thống kê thay đổi của từng cam kết
git log --stat

# Hiển thị lịch sử cam kết gọn gàng trên một dòng cho mỗi cam kết
git log --pretty=oneline

# Hiển thị lịch sử cam kết với đồ thị nhánh
git log --graph --pretty=oneline --abbrev-commit
  • Tìm kiếm trong lịch sử cam kết:
# Tìm kiếm các cam kết có chứa từ khóa "feature" trong thông điệp
git log --grep "feature"

# Tìm kiếm các cam kết mà nội dung tệp có chứa chuỗi "MyKeyword"
git log -S "MyKeyword"
  • Xem lịch sử thay đổi của một tệp:
# Hiển thị lịch sử cam kết của 'src/main.js', bao gồm cả việc đổi tên tệp
git log --follow src/main.js
  • Xem sự khác biệt (diff) của các thay đổi:
# Hiển thị sự khác biệt giữa vùng làm việc và vùng đệm
git diff

# Hiển thị sự khác biệt giữa vùng đệm và cam kết cuối cùng
git diff --cached (hoặc git diff --staged)

# Hiển thị sự khác biệt giữa vùng làm việc và cam kết cuối cùng trên nhánh hiện tại (HEAD)
git diff HEAD

# Hiển thị sự khác biệt giữa hai cam kết hoặc hai nhánh
git diff main...feature/new-feature
git diff 1a2b3c4 5d6e7f8
  • Kiểm tra chi tiết một cam kết cụ thể:
# Hiển thị thông tin (metadata) và nội dung thay đổi của cam kết 'abc1234'
git show abc1234

# Chỉ hiển thị tên các tệp đã thay đổi trong cam kết 'abc1234'
git show --name-only abc1234

# Xem nội dung của một tệp tại một cam kết cụ thể
git show abc1234:path/to/my_file.txt
  • Xem nhật ký tham chiếu (Reflog):

Reflog ghi lại mọi thao tác mà HEAD hoặc các nhánh khác đã thực hiện, giúp bạn khôi phục lại các cam kết "bị mất" hoặc các trạng thái trước đó.

# Hiển thị nhật ký các tham chiếu của HEAD
git reflog

8. Đồng bộ hóa với kho lưu trữ từ xa

Để làm việc hợp tác, bạn cần tương tác với kho lưu trữ từ xa. Các lệnh sau đây cho phép bạn tải về, tải lên và quản lý các kết nối từ xa.

  • Lấy về (Fetch) các thay đổi từ kho lưu trữ từ xa:

Lệnh fetch tải về tất cả các nhánh và thẻ từ kho lưu trữ từ xa, nhưng không tự động hợp nhất chúng vào các nhánh cục bộ của bạn.

# Tải về các thay đổi từ kho lưu trữ từ xa 'origin'
git fetch origin
  • Liệt kê các kho lưu trữ từ xa:
# Hiển thị tên và URL của tất cả các kho lưu trữ từ xa đã cấu hình
git remote -v
  • Xem thông tin chi tiết về một kho lưu trữ từ xa:
# Hiển thị thông tin chi tiết về kho lưu trữ 'origin', bao gồm các nhánh và trạng thái tracking
git remote show origin
  • Thêm một kho lưu trữ từ xa mới:
# Thêm một kho lưu trữ từ xa mới với tên ngắn 'upstream' và URL
git remote add upstream https://github.com/another-user/another-repo.git
  • Kéo về và hợp nhất (Pull) các thay đổi từ xa:

Lệnh pull là sự kết hợp của git fetch và git merge. Nó tải về các thay đổi từ một nhánh từ xa và ngay lập tức hợp nhất chúng vào nhánh cục bộ hiện tại của bạn.

# Kéo các thay đổi từ nhánh 'main' của kho lưu trữ 'origin' và hợp nhất vào nhánh hiện tại
git pull origin main
  • Đẩy (Push) các thay đổi cục bộ lên kho lưu trữ từ xa:

Lệnh push tải các cam kết cục bộ của bạn lên một nhánh trên kho lưu trữ từ xa.

# Đẩy nhánh 'feature/my-new-feature' cục bộ lên nhánh cùng tên trên 'origin'
git push origin feature/my-new-feature
  • Buộc đẩy (Force Push) các thay đổi:

--force được sử dụng để ghi đè lịch sử trên kho lưu trữ từ xa. Hãy cẩn thận khi sử dụng lệnh này vì nó có thể ghi đè công việc của người khác.

# Buộc đẩy nhánh 'develop' lên 'origin'. Chỉ sử dụng khi bạn chắc chắn và hiểu rõ rủi ro.
git push origin develop --force
  • Đẩy tất cả các nhánh lên kho lưu trữ từ xa:
# Đẩy tất cả các nhánh cục bộ có liên kết theo dõi lên kho lưu trữ từ xa
git push origin --all

9. Hoàn tác và khôi phục thay đổi

Git cung cấp nhiều cách để hoàn tác các thay đổi, tùy thuộc vào việc chúng đang ở vùng làm việc, vùng đệm hay đã được cam kết vào kho lưu trữ.

  • Khôi phục tệp trong vùng làm việc:
# Hủy bỏ các thay đổi chưa được 'git add' của 'my_file.txt' trong vùng làm việc.
# Tệp sẽ trở về trạng thái của cam kết gần nhất hoặc trạng thái khi được thêm vào vùng đệm.
git checkout -- my_file.txt
  • Khôi phục một tệp cụ thể từ một cam kết:
# Khôi phục 'my_file.txt' về trạng thái tại cam kết 'abcde123'
git checkout abcde123 my_file.txt
  • Đưa các tệp từ vùng đệm trở lại vùng làm việc (Unstage):

Lệnh git reset với tùy chọn mặc định (--mixed) hoặc không có tùy chọn sẽ di chuyển các thay đổi từ vùng đệm về lại vùng làm việc mà không làm thay đổi các tệp trong vùng làm việc.

# Đưa 'staged_file.txt' ra khỏi vùng đệm, nhưng giữ các thay đổi trong vùng làm việc
git reset HEAD staged_file.txt
# Hoặc đơn giản hơn:
git reset staged_file.txt
  • Hoàn tác các cam kết (Reset):

Lệnh git reset di chuyển con trỏ HEAD và các nhánh của bạn đến một cam kết khác. Nó có ba chế độ chính:

# <strong>--soft:</strong> Di chuyển HEAD đến cam kết 'abcde123'. Các thay đổi từ các cam kết bị loại bỏ
#          sẽ được giữ nguyên trong vùng đệm, sẵn sàng để cam kết lại.
git reset --soft abcde123

# <strong>--mixed (mặc định):</strong> Di chuyển HEAD đến 'abcde123'. Các thay đổi sẽ được đưa về vùng làm việc,
#          cần 'git add' lại trước khi cam kết.
git reset --mixed abcde123
# Hoặc (nếu bạn muốn reset về commit trước đó):
git reset HEAD^

# <strong>--hard:</strong> Di chuyển HEAD đến 'abcde123'. Các thay đổi từ các cam kết bị loại bỏ
#         sẽ bị hủy bỏ hoàn toàn khỏi vùng đệm VÀ vùng làm việc.
#         Hãy CẨN THẬN khi sử dụng lệnh này vì nó có thể làm mất dữ liệu!
git reset --hard abcde123
  • Hoàn tác một cam kết cụ thể bằng một cam kết mới (Revert):

git revert tạo ra một cam kết mới để hoàn tác các thay đổi của một cam kết trước đó, thay vì xóa bỏ lịch sử. Điều này an toàn hơn khi bạn đã đẩy mã lên kho lưu trữ từ xa.

# Tạo một cam kết mới để hoàn tác các thay đổi của cam kết 'fedcb987'
git revert fedcb987
  • Tạm thời cất giữ các thay đổi chưa cam kết (Stash):

git stash lưu trữ tạm thời các thay đổi chưa được cam kết (trong vùng làm việc và vùng đệm) để bạn có thể chuyển sang một nhánh khác hoặc làm việc trên một tác vụ khác, sau đó có thể áp dụng lại các thay đổi đó sau.

# Cất giữ các thay đổi hiện tại
git stash

# Áp dụng lại các thay đổi đã cất giữ và xóa chúng khỏi danh sách stash
git stash pop

# Áp dụng lại các thay đổi đã cất giữ nhưng vẫn giữ chúng trong danh sách stash
git stash apply

10. Các lệnh khác

  • Tạo một tệp lưu trữ (archive) của dự án:

Lệnh git archive tạo ra một tệp nén (ví dụ: .zip hoặc .tar) của cây dự án tại một cam kết, nhánh hoặc thẻ cụ thể. Điều này hữu ích khi bạn muốn tạo một bản phân phối không phải là kho lưu trữ Git.

# Tạo tệp zip của nhánh 'main'
git archive --format=zip --output=project-main.zip main

# Tạo tệp tar.gz của thẻ 'v1.0.0'
git archive --format=tar.gz --output=project-v1.0.0.tar.gz v1.0.0

Chiến lược quản lý nhánh trong Git

Một chiến lược quản lý nhánh hiệu quả là chìa khóa để duy trì sự ổn định của mã nguồn và hợp lý hóa quy trình phát triển. Dưới đây là một mô hình phân nhánh phổ biến, thường được gọi là Git Flow đơn giản hóa.

1. Nhánh chính (Master/Main Branch)

Kho lưu trữ nên có một và chỉ một nhánh chính. Tất cả các phiên bản chính thức được cung cấp cho người dùng đều được phát hành từ nhánh này. Theo quy ước, nhánh này thường được gọi là master hoặc main. Sau khi khởi tạo kho lưu trữ, đây là nhánh mặc định để phát triển.

2. Nhánh phát triển (Develop Branch)

Nhánh chính chỉ được dùng cho các bản phát hành quan trọng. Việc phát triển hàng ngày nên được thực hiện trên một nhánh khác, gọi là develop. Nhánh này có thể được dùng để tạo ra các bản dựng thử nghiệm (nightly builds) mới nhất. Khi sẵn sàng phát hành chính thức, các thay đổi từ develop sẽ được hợp nhất vào master.

Tạo nhánh develop từ master:

git checkout -b develop master

Phát hành các thay đổi từ develop sang master:

# Chuyển sang nhánh master
git checkout master
# Hợp nhất nhánh develop vào master với tùy chọn --no-ff
git merge --no-ff develop

Tham số --no-ff (no fast-forward) có ý nghĩa quan trọng khi hợp nhất các nhánh. Mặc định, Git thường thực hiện "hợp nhất fast-forward" nếu có thể, nghĩa là chỉ di chuyển con trỏ của nhánh đích đến cam kết mới nhất của nhánh nguồn mà không tạo ra một cam kết hợp nhất mới. Điều này làm mất đi thông tin về việc một nhánh đã từng tồn tại và được hợp nhất.

Khi sử dụng --no-ff, Git sẽ buộc tạo một cam kết hợp nhất (merge commit) mới, ngay cả khi hợp nhất fast-forward là có thể. Điều này giúp duy trì lịch sử nhánh rõ ràng, cho thấy rõ ràng khi nào một nhánh tính năng được phát triển và khi nào nó được hợp nhất vào nhánh chính. Cách này đặc biệt hữu ích cho việc theo dõi lịch sử phát triển và gỡ lỗi.

3. Các nhánh tạm thời

Ngoài các nhánh cố định như master và develop, có ba loại nhánh tạm thời được sử dụng cho các mục đích phát triển cụ thể:

  • Nhánh tính năng (Feature Branches)
  • Nhánh phát hành trước (Release Branches)
  • Nhánh sửa lỗi nóng (Hotfix Branches)

Các nhánh này chỉ tồn tại trong một thời gian ngắn, sau khi hoàn thành nhiệm vụ và được hợp nhất, chúng sẽ được xóa để giữ cho kho lưu trữ gọn gàng.

4. Nhánh tính năng (Feature Branches)

Nhánh tính năng được tạo ra để phát triển một chức năng mới cụ thể hoặc một phần của dự án. Chúng được tách ra từ nhánh develop và sẽ được hợp nhất trở lại develop sau khi hoàn thành. Tên nhánh thường có dạng feature/*.

Tạo một nhánh tính năng mới:

# Tạo nhánh 'feature/user-dashboard' từ 'develop' và chuyển sang nhánh đó
git checkout -b feature/user-dashboard develop

Hoàn thành và hợp nhất nhánh tính năng:

# Chuyển về nhánh develop
git checkout develop
# Hợp nhất nhánh tính năng vào develop (sử dụng --no-ff để giữ lịch sử rõ ràng)
git merge --no-ff feature/user-dashboard

Xóa nhánh tính năng:

# Xóa nhánh cục bộ sau khi đã hợp nhất
git branch -d feature/user-dashboard

5. Nhánh phát hành trước (Release Branches)

Nhánh phát hành trước được tạo ra khi mã nguồn đã sẵn sàng cho một bản phát hành mới. Đây là giai đoạn cuối cùng để kiểm tra, sửa lỗi nhỏ và chuẩn bị cho việc đóng gói bản phát hành. Nhánh này được tách ra từ develop và sau khi ổn định, sẽ được hợp nhất vào cả master (để đánh dấu bản phát hành) và develop (để cập nhật các sửa lỗi). Tên nhánh thường có dạng release/*.

Tạo một nhánh phát hành trước:

# Tạo nhánh 'release/1.2.0' từ 'develop' và chuyển sang đó
git checkout -b release/1.2.0 develop

Kết thúc nhánh phát hành trước:

# Chuyển về nhánh master
git checkout master
# Hợp nhất release branch vào master
git merge --no-ff release/1.2.0
# Đánh dấu bản phát hành bằng tag
git tag -a v1.2.0 -m "Release version 1.2.0"

# Chuyển về nhánh develop
git checkout develop
# Hợp nhất release branch vào develop (để đảm bảo các sửa lỗi nhỏ được cập nhật)
git merge --no-ff release/1.2.0

Xóa nhánh phát hành trước:

# Xóa nhánh cục bộ sau khi đã hoàn tất
git branch -d release/1.2.0

6. Nhánh sửa lỗi nóng (Hotfix Branches)

Nhánh sửa lỗi nóng được sử dụng để nhanh chóng vá các lỗi nghiêm trọng trên phiên bản đã phát hành (trên nhánh master). Chúng được tách ra trực tiếp từ master. Sau khi sửa lỗi, nhánh này sẽ được hợp nhất vào cả master (để phát hành bản vá) và develop (để đảm bảo lỗi không tái diễn trong các phiên bản tương lai). Tên nhánh thường có dạng hotfix/*.

Tạo một nhánh sửa lỗi nóng:

# Tạo nhánh 'hotfix/bug-critical' từ 'master' và chuyển sang đó
git checkout -b hotfix/bug-critical master

Kết thúc nhánh sửa lỗi nóng:

# Chuyển về nhánh master
git checkout master
# Hợp nhất hotfix branch vào master
git merge --no-ff hotfix/bug-critical
# Đánh dấu bản vá lỗi bằng tag
git tag -a v1.0.1 -m "Hotfix for critical bug"

# Chuyển về nhánh develop
git checkout develop
# Hợp nhất hotfix branch vào develop
git merge --no-ff hotfix/bug-critical

Xóa nhánh sửa lỗi nóng:

# Xóa nhánh cục bộ sau khi đã hoàn tất
git branch -d hotfix/bug-critical

Khôi phục phiên bản và hoàn tác thay đổi

Git cung cấp các công cụ mạnh mẽ để hoàn tác các thay đổi hoặc quay lại các phiên bản trước đó. Việc hiểu rõ cách các lệnh này tương tác với vùng làm việc, vùng đệm và kho lưu trữ cục bộ là rất quan trọng.

Khôi phục tệp trong vùng làm việc (trước git add)

Nếu bạn đã sửa đổi một tệp trong vùng làm việc nhưng chưa thêm nó vào vùng đệm (chưa chạy git add), bạn có thể dễ dàng hoàn tác các thay đổi đó. Kiểm tra trạng thái bằng git status, bạn sẽ thấy tệp trong mục "Changes not staged for commit".

Để hủy bỏ các thay đổi và đưa tệp về trạng thái cuối cùng trong kho lưu trữ (hoặc trạng thái khi được thêm vào vùng đệm), bạn dùng lệnh:

git checkout -- my_document.txt

Lưu ý: Dấu -- là rất quan trọng. Nếu không có nó, git checkout sẽ được hiểu là lệnh chuyển đổi nhánh. Lệnh này sẽ làm mất tất cả các thay đổi chưa được thêm vào vùng đệm của tệp my_document.txt.

Khôi phục tệp đã thêm vào vùng đệm (trước git commit)

Nếu bạn đã sửa đổi một tệp và thêm nó vào vùng đệm (bằng git add), nhưng chưa cam kết (chưa chạy git commit), bạn có thể đưa tệp đó ra khỏi vùng đệm.

Khi kiểm tra git status, bạn sẽ thấy tệp trong mục "Changes to be committed". Git cũng thường gợi ý lệnh cần dùng:

git reset HEAD my_document.txt

Lệnh này sẽ đưa tệp my_document.txt ra khỏi vùng đệm, nhưng các thay đổi vẫn sẽ còn trong vùng làm việc của bạn. Sau đó, bạn có thể quyết định chỉnh sửa thêm hoặc hoàn tác các thay đổi trong vùng làm việc như mục trên.

# Bước 1: Đưa tệp ra khỏi vùng đệm
git reset HEAD my_document.txt

# Bước 2: Hủy bỏ các thay đổi trong vùng làm việc (nếu muốn)
git checkout -- my_document.txt

Lệnh git reset HEAD <file> tương đương với git reset --mixed HEAD <file>, nó di chuyển tệp từ vùng đệm trở lại vùng làm việc mà không thay đổi nội dung tệp.

Hoàn tác các cam kết đã thực hiện (Version Rollback)

Khi bạn đã cam kết các thay đổi vào kho lưu trữ cục bộ, việc hoàn tác liên quan đến việc di chuyển con trỏ lịch sử Git.

Xem lịch sử cam kết

Trước tiên, bạn cần biết lịch sử các cam kết của mình. Sử dụng git log:

git log --pretty=oneline

Kết quả có thể trông như sau (ID cam kết của bạn sẽ khác):

abcdef1234 Cập nhật phiên bản GPL
1234567890 Thêm module phân tán
890abcdef1 Khởi tạo tệp README

Mỗi chuỗi ký tự dài là một "ID cam kết" (commit ID) duy nhất. HEAD trỏ đến cam kết gần đây nhất. HEAD^ là cam kết trước đó, HEAD^^ là cam kết trước đó nữa, và HEAD~N là N cam kết trước đó.

Quay về cam kết trước đó

Để quay về một cam kết cũ hơn, bạn sử dụng lệnh git reset --hard. Ví dụ, để quay về cam kết trước cam kết hiện tại (HEAD^):

git reset --hard HEAD^

Lệnh này sẽ di chuyển con trỏ HEAD đến cam kết trước đó, đồng thời cập nhật cả vùng đệm và vùng làm việc để khớp với trạng thái của cam kết đó. Cam kết "Cập nhật phiên bản GPL" sẽ không còn xuất hiện trong git log nữa.

Cảnh báo: git reset --hard sẽ loại bỏ tất cả các thay đổi chưa được cam kết trong vùng làm việc và vùng đệm, cũng như các cam kết sau cam kết đích. Hãy cẩn thận khi sử dụng!

Khôi phục cam kết sau khi đã reset

Nếu bạn đã thực hiện git reset --hard và sau đó nhận ra mình muốn quay lại cam kết "mới hơn" đã bị loại bỏ, bạn có thể sử dụng git reflog.

git reflog ghi lại tất cả các hoạt động mà con trỏ HEAD đã thực hiện. Điều này bao gồm cả các lần chuyển nhánh, cam kết, reset, v.v.

git reflog

Kết quả có thể như sau:

1234567 HEAD@{0}: reset: moving to HEAD^
abcdef1 HEAD@{1}: commit: Cập nhật phiên bản GPL
890abcdef1 HEAD@{2}: commit: Thêm module phân tán
xyzabcde HEAD@{3}: commit (initial): Khởi tạo tệp README

Từ nhật ký này, bạn có thể tìm thấy ID của cam kết "Cập nhật phiên bản GPL" (ví dụ: abcdef1). Sau đó, bạn có thể quay lại cam kết đó:

git reset --hard abcdef1

Git sẽ di chuyển HEAD và cập nhật vùng làm việc/vùng đệm về trạng thái của cam kết abcdef1. Điều này cho phép bạn "quay ngược thời gian" và khôi phục các cam kết đã bị loại bỏ cục bộ.

Thẻ: git GitCommands GitBranchingStrategy GitWorkflow GitReset

Đăng vào ngày 13 tháng 10 lúc 19:17