Git: Đặt lại, kiểm tra, và hoàn nguyên
Các lệnh git reset
, git checkout
và git revert
là một số trong những công cụ hữu ích nhất trong hộp công cụ Git của bạn. Tất cả đều cho phép bạn hoàn tác một số loại thay đổi trong kho lưu trữ của bạn và hai lệnh đầu tiên có thể được sử dụng để thao tác với các commit hoặc các tệp riêng lẻ.
Vì chúng rất giống nhau, nên rất dễ trộn lẫn lệnh nào sẽ được sử dụng trong bất kỳ kịch bản phát triển cụ thể nào. Trong bài viết này, chúng tôi sẽ so sánh các cấu hình phổ biến nhất của git reset
, git checkout
và git revert
. Hy vọng rằng, bạn sẽ tự tin bỏ đi để điều hướng kho lưu trữ của mình bằng bất kỳ lệnh nào trong số này.
Nó giúp suy nghĩ về từng lệnh về tác dụng của chúng đối với ba cơ chế quản lý trạng thái của kho lưu trữ Git: thư mục làm việc, ảnh chụp theo giai đoạn và lịch sử cam kết. Những thành phần này đôi khi được gọi là "Ba cây" của Git. Chúng tôi khám phá ba cây sâu trong git reset
trang. Hãy ghi nhớ các cơ chế này khi bạn đọc qua bài viết này.
Thanh toán là một hoạt động di chuyển HEAD
con trỏ ref đến một xác nhận đã chỉ định. Để chứng minh điều này hãy xem xét ví dụ sau đây.
Ví dụ này cho thấy một chuỗi các cam kết trên master
nhánh. Các HEAD
ref và master
chi nhánh hiện đang trỏ đến cam kết d. Bây giờ hãy để chúng tôi thực hiện git checkout b
Đây là bản cập nhật cho cây "Lịch sử cam kết". Các git checkout
lệnh có thể được sử dụng trong một cam kết, hoặc cấp tập tin phạm vi. Kiểm tra cấp độ tệp sẽ thay đổi nội dung của tệp thành các cam kết cụ thể.
Hoàn nguyên là một hoạt động có một cam kết được chỉ định và tạo ra một cam kết mới đảo ngược cam kết đã chỉ định. git revert
chỉ có thể được chạy ở phạm vi mức cam kết và không có chức năng cấp tệp.
Thiết lập lại là một hoạt động có một cam kết được chỉ định và đặt lại "ba cây" để khớp với trạng thái của kho lưu trữ tại cam kết đã chỉ định đó. Một thiết lập lại có thể được gọi trong ba chế độ khác nhau tương ứng với ba cây.
Thanh toán và đặt lại thường được sử dụng để thực hiện 'hoàn tác' cục bộ hoặc riêng tư. Họ sửa đổi lịch sử của một kho lưu trữ có thể gây ra xung đột khi đẩy vào kho lưu trữ được chia sẻ từ xa. Revert được coi là một hoạt động an toàn cho 'công khai hoàn tác' vì nó tạo ra lịch sử mới có thể được chia sẻ từ xa và không ghi đè lên lịch sử mà các thành viên nhóm từ xa có thể phụ thuộc vào.
Tham chiếu Git vs Revert vs Checkout
Bảng dưới đây tổng hợp các trường hợp sử dụng phổ biến nhất cho tất cả các lệnh này. Hãy chắc chắn để giữ tài liệu tham khảo này tiện dụng, vì chắc chắn bạn sẽ cần sử dụng ít nhất một số trong số chúng trong sự nghiệp Git của bạn.
Chỉ huy | Phạm vi | Các trường hợp sử dụng phổ biến |
---|---|---|
git reset |
Cam kết cấp | Hủy bỏ cam kết trong một chi nhánh tư nhân hoặc vứt bỏ những thay đổi không được cam kết |
git reset |
Cấp độ tệp | Bỏ tập tin |
git checkout |
Cam kết cấp | Chuyển đổi giữa các chi nhánh hoặc kiểm tra ảnh chụp nhanh cũ |
git checkout |
Cấp độ tệp | Hủy thay đổi trong thư mục làm việc |
git revert |
Cam kết cấp | Hoàn tác cam kết trong một chi nhánh công cộng |
git revert |
Cấp độ tệp | (Không có) |
Cam kết hoạt động cấp
Các tham số mà bạn truyền đến git reset
và git checkout
xác định phạm vi của chúng. Khi bạn không bao gồm đường dẫn tệp làm tham số, chúng sẽ hoạt động trên toàn bộ cam kết. Đó là những gì chúng ta sẽ khám phá trong phần này. Lưu ý rằng git revert
không có đối tác cấp tệp.
Đặt lại một cam kết cụ thể
Ở cấp độ cam kết, đặt lại là một cách để di chuyển đầu nhánh sang một cam kết khác. Điều này có thể được sử dụng để loại bỏ các cam kết từ chi nhánh hiện tại. Ví dụ, lệnh sau di chuyển hotfix
nhánh ngược lại bằng hai lần xác nhận.
git checkout hotfix
git reset HEAD~2
Hai cam kết cuối cùng hotfix
hiện đang lơ lửng, hoặc mồ côi. Điều này có nghĩa là chúng sẽ bị xóa vào lần tới khi Git thực hiện bộ sưu tập rác. Nói cách khác, bạn đang nói rằng bạn muốn vứt bỏ những cam kết này. Điều này có thể được hình dung như sau:
Cách sử dụng git reset
này là một cách đơn giản để hoàn tác các thay đổi chưa được chia sẻ với bất kỳ ai khác. Đó là mệnh lệnh của bạn khi bạn bắt đầu làm việc với một tính năng và thấy mình suy nghĩ, cùi Oh, tôi đang làm gì vậy? Tôi chỉ nên bắt đầu lại.
Ngoài việc di chuyển nhánh hiện tại, bạn cũng có git reset
thể thay đổi ảnh chụp nhanh theo giai đoạn và / hoặc thư mục làm việc bằng cách chuyển qua một trong các cờ sau:
--soft
- Ảnh chụp nhanh và thư mục làm việc không bị thay đổi theo bất kỳ cách nào.--mixed
- Ảnh chụp theo giai đoạn được cập nhật để phù hợp với cam kết đã chỉ định, nhưng thư mục làm việc không bị ảnh hưởng. Đây là tùy chọn mặc định.--hard
- Ảnh chụp nhanh theo giai đoạn và thư mục làm việc đều được cập nhật để phù hợp với cam kết đã chỉ định.
Dễ dàng hơn khi nghĩ về các chế độ này khi xác định phạm vi git reset
hoạt động. Để biết thêm thông tin chi tiết truy cập git reset
trang.
Thanh toán các cam kết cũ
Các git checkout
lệnh được sử dụng để cập nhật trạng thái của kho lưu trữ đến một điểm cụ thể trong lịch sử dự án. Khi được thông qua với một tên chi nhánh, nó cho phép bạn chuyển đổi giữa các chi nhánh.
git checkout hotfix
Trong nội bộ, tất cả các lệnh trên làm là di chuyển HEAD
đến một nhánh khác và cập nhật thư mục làm việc cho phù hợp. Vì đây có khả năng ghi đè lên thay đổi địa phương, Git buộc bạn phải cam kết hoặc giấu bất kỳ thay đổi trong thư mục làm việc đó sẽ bị mất trong các hoạt động thanh toán. Không giống như git reset
, git checkout
không di chuyển bất kỳ chi nhánh xung quanh.
Bạn cũng có thể kiểm tra các cam kết tùy ý bằng cách chuyển tham chiếu cam kết thay vì một nhánh. Điều này thực hiện chính xác tương tự như kiểm tra một nhánh: nó di chuyển HEAD
tham chiếu đến cam kết đã chỉ định. Ví dụ: lệnh sau sẽ kiểm tra ông bà của cam kết hiện tại:
git checkout HEAD~2
Điều này rất hữu ích để nhanh chóng kiểm tra một phiên bản cũ của dự án của bạn. Tuy nhiên, vì không có tham chiếu chi nhánh nào cho hiện tại HEAD
, điều này đặt bạn vào HEAD
trạng thái tách rời . Điều này có thể nguy hiểm nếu bạn bắt đầu thêm các cam kết mới vì sẽ không có cách nào để quay lại với chúng sau khi bạn chuyển sang chi nhánh khác. Vì lý do này, bạn phải luôn tạo một nhánh mới trước khi thêm các xác nhận vào một tách ra HEAD
.
Hoàn tác các cam kết công khai với Revert
Hoàn nguyên cam kết bằng cách tạo một cam kết mới. Đây là một cách an toàn để hoàn tác các thay đổi, vì nó không có cơ hội viết lại lịch sử cam kết. Ví dụ, lệnh sau sẽ chỉ ra các thay đổi có trong lần xác nhận thứ 2 đến lần cuối, tạo một cam kết mới hoàn tác các thay đổi đó và giải quyết cam kết mới đối với dự án hiện có.
git checkout hotfix
git revert HEAD~2
Điều này có thể được hình dung như sau:
Tương phản điều này với git reset
, điều này làm thay đổi lịch sử cam kết hiện có. Vì lý do này, git revert
nên được sử dụng để hoàn tác các thay đổi trên một nhánh công cộng và git reset
nên được dành riêng cho các thay đổi hoàn tác trên một nhánh riêng.
Bạn cũng có thể nghĩ về git revert
như một công cụ để hoàn tác các thay đổi đã cam kết , trong khi đó git reset HEAD
là hoàn tác các thay đổi không được cam kết .
Giống như git checkout
, git revert
có khả năng ghi đè lên các tệp trong thư mục làm việc, vì vậy nó sẽ yêu cầu bạn thực hiện hoặc xóa các thay đổi sẽ bị mất trong quá trình hoàn nguyên.
Hoạt động cấp tệp
Các lệnh git reset
và git checkout
cũng chấp nhận một đường dẫn tệp tùy chọn làm tham số. Điều này làm thay đổi đáng kể hành vi của họ. Thay vì hoạt động trên toàn bộ ảnh chụp nhanh, điều này buộc họ phải giới hạn hoạt động của mình trong một tệp duy nhất.
Git Đặt lại một tệp cụ thể
Khi được gọi với đường dẫn tệp, git reset
cập nhật ảnh chụp theo giai đoạn để khớp với phiên bản từ cam kết đã chỉ định. Ví dụ: lệnh này sẽ tìm nạp phiên bản của foo.py
cam kết thứ 2 đến lần cuối và thực hiện nó cho lần xác nhận tiếp theo:
git reset HEAD~2 foo.py
Như với phiên bản cấp độ cam kết git reset
, điều này thường được sử dụng HEAD
hơn là một cam kết tùy ý. Chạy git reset HEAD foo.py
sẽ ra sân khấu foo.py
. Những thay đổi mà nó chứa vẫn sẽ hiện diện trong thư mục làm việc.
Các --soft
, --mixed
và các --hard
cờ không có bất kỳ ảnh hưởng nào đến phiên bản cấp tệp git reset
, vì ảnh chụp nhanh theo giai đoạn luôn được cập nhật và thư mục làm việc không bao giờđược cập nhật.
Tệp thanh toán Git
Kiểm tra một tệp tương tự như sử dụng git reset
với đường dẫn tệp, ngoại trừ nó cập nhật thư mục làm việc thay vì giai đoạn. Không giống như phiên bản mức cam kết của lệnh này, điều này không di chuyển HEAD
tham chiếu, điều đó có nghĩa là bạn sẽ không chuyển nhánh.
Ví dụ, lệnh sau làm cho foo.py
trong thư mục làm việc khớp với lệnh từ lần xác nhận thứ 2 đến lần cuối:
git checkout HEAD~2 foo.py
Giống như lời gọi mức cam kết git checkout
, điều này có thể được sử dụng để kiểm tra các phiên bản cũ của một dự án, nhưng phạm vi được giới hạn trong tệp được chỉ định.
Nếu bạn thực hiện và cam kết tệp đã thanh toán, điều này có tác dụng của việc hoàn nguyên lại thành phiên bản cũ của tệp đó. Lưu ý rằng điều này loại bỏ tất cả các thay đổi tiếp theo đối với tệp, trong khi git revert
lệnh chỉ hoàn tác các thay đổi được đưa ra bởi cam kết đã chỉ định.
Giống như git reset
, điều này thường được sử dụng với HEAD
tham chiếu cam kết. Chẳng hạn, git checkout HEAD foo.py
có tác dụng loại bỏ những thay đổi không có căn cứ thành foo.py
. Đây là hành vi tương tự git reset HEAD --hard
, nhưng nó chỉ hoạt động trên tệp được chỉ định.
Tóm lược
Bây giờ bạn sẽ có tất cả các công cụ bạn cần để hoàn tác các thay đổi trong kho Git. Các git reset
, git checkout
và git revert
các lệnh có thể gây nhầm lẫn, nhưng khi bạn nghĩ về ảnh hưởng của chúng trên thư mục làm việc, tổ chức ảnh chụp, và cam kết lịch sử, nó phải là dễ dàng hơn để phân biệt mà chỉ huy phù hợp với nhiệm vụ phát triển trong tầm tay.