Trong bài viết này, tôi giới thiệu các cách để đưa local repo quay trở lại trạng thái của commit cũ

Trước tiên, tôi kiểm tra lịch sử commit bằng lệnh git log:

Lịch sử các commit ở local repo
Lịch sử các commit ở local repo

Tôi cũng kiểm tra danh sách các file và thư mục hiện có bằng lệnh ls:

2 file index.html và style.css
2 file index.html và style.css

Tôi thêm một file script.js:

$ touch script.js

và commit vào local repo:

$ git add .
$ git commit -m "thêm file script.js"

và lại kiểm tra lịch sử commit bằng lệnh git log

Commit số 3 mới được thêm vào local repo
Commit số 3 mới được thêm vào local repo

Giả sử tôi thấy không hài lòng với commit số 3 và muốn đưa project quay trở lại trạng thái của commit số 2. Tôi có 2 phương án như sau:

1. git reset

Tôi gõ lệnh sau:

$ git reset --hard b657dfc22dd4fd83d36333910fdb3bbdc649d266

trong đó b657dfc22dd4fd83d36333910fdb3bbdc649d266 chính là ID của commit số 2

Kiểm tra lại lịch sử trong local repo với git log:

commit số 3 đã bị xoá khỏi local repo
commit số 3 đã bị xoá khỏi local repo

Các bạn có thể thấy commit số 3 đã bị xoá khỏi local repo.

Kiểm tra tiếp bằng lệnh ls:

File script.js đã bị xoá
File script.js đã bị xoá

cho thấy file script.js cũng đã bị xoá khỏi thư mục. Project của tôi đã được đưa về trạng thái của commit số 2

Các bạn có thể xem hình minh hoạ sau để hình dung rõ hơn:

git reset --hard c2 sẽ xoá luôn 2 commit c3 và c4
git reset --hard c2 sẽ xoá luôn 2 commit c3 và c4

Như vậy: Muốn đưa project về trạng thái của commit nào, ta chạy lệnh:

$ git reset --hard ID-của-commit-cũ

Cách này có một nhược điểm là khi làm việc theo nhóm, nếu tôi đẩy local repo của mình lên remote repo (Github, Gitlab, ...) thì nó có thể conflict với local repo của các thành viên khác, đơn giản là bởi tôi đã xoá đi một số commit ở repo của mình, trong khi repo của các thành viên khác trong team vẫn có các commit mà tôi đã xoá

Do đó, cách này chỉ nên được dùng khi bạn làm việc trong một project mà chỉ có một mình bạn là người code :v. Còn nếu làm việc theo nhóm, bạn nên dùng cách số 2, đó là dùng git revert

2. git revert

Trước khi sử dụng git revert, tôi thêm lại file script.js vào project

Tạo lại file script.js
Tạo lại file script.js

Giờ tôi sẽ đưa project quay trở lại trạng thái của commit số 2 bằng lệnh sau:

$ git revert c70bcc54fc89b0b6d704dab01ea9cb614ca6ec9d

 

git revert
git revert

Các bạn chú ý: Để đưa project quay trở lại trạng thái của commit số 2, tôi sử dụng git revert với ID của commit số 3. Đây là một điểm khác biệt so với lệnh git reset (với git reset thì ta sẽ truyền vào ID của commit số 2)

Kiểm tra danh sách file trong thư mục: 

Đã xoá file script.js
Đã xoá file script.js

Kiểm tra lịch sử commit trong local repo:

git revert không xoá commit số 3 mà tạo commit mới
git revert không xoá commit số 3 mà tạo commit mới

Các bạn có thể thấy một điểm khác biệt nữa của git revert so với git reset: Trong khi git reset xoá các commit diễn ra sau commit số 2 thì git revert sẽ không xoá commit nào cả mà thay vào đó nó sẽ tạo ra một commit mới với nội dung giống hệt commit số 2

Như vậy, với git revert, không có commit nào bị xoá đi mà chỉ có commit mới được thêm vào, điều này giúp cho local repo của tôi không bị conflict với repo của các thành viên khác khi làm việc nhóm qua Github (hoặc Gitlab, ...)

Chốt lại, có 2 kĩ thuật để undo committed change:

- git reset: Đưa repo về commit cũ, đồng thời xoá luôn các commit diễn ra sau nó. Cách này phù hợp nếu bạn làm việc một mình

- git revert: Cũng đưa repo về commit cũ nhưng không xoá các commit diễn ra sau nó, thay vào đó Git sẽ tạo commit mới. Cách này an toàn hơn git reset, phù hợp khi làm việc theo nhóm

Trong bài viết sau, tôi sẽ hướng dẫn các bạn cách quay lui thay đổi (undo change) ở working directory và staging area.