cách tiếp cận của bạn là hoàn toàn sai. Bạn đang sửa đổi một cái gì đó mà bạn không muốn sửa đổi: Chi nhánh hiện tại của bạn (có lẽ là master
).
A, kho git tuyến tính đơn giản là một chuỗi các cam kết như thế này
*---A---*---*---B---*---*---C
^ ^
| |
master origin/master
^
|
HEAD
Đó là tình trạng của kho lưu trữ của bạn sau khi bạn đã gọi git fetch
. Lưu ý rằng toàn bộ lịch sử với tất cả các bước trung gian của nó nằm ngay trên ổ đĩa cứng cục bộ của bạn. Chỉ là bạn chỉ có trạng thái tại cam kết A
được kiểm tra (HEAD
điểm đến master
trỏ đến A
), vì vậy các tệp mà bạn thấy thuộc về trạng thái đó.
Bây giờ, nếu bạn chỉ muốn xem trạng thái đã cam kết là B
, bạn có thể chỉ cần kiểm tra cam kết đó với git checkout B
. Này cập nhật các tập tin mà bạn nhìn thấy trạng thái của B
, và chỉ HEAD
tại đó cam kết:
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master HEAD origin/master
HEAD
luôn tham chiếu cam/chi nhánh git
nghĩ bạn đang ở trên, và mà nó sẽ so sánh thư mục làm việc của bạn khi bạn gọi git status
.
Đơn giản git checkout B
là đủ, nếu bạn chỉ muốn xem xét cam kết đó. Nếu bạn thực sự muốn thực hiện các thay đổi mà bạn cam kết và muốn giữ lại, bạn nên giới thiệu một nhánh mới để ghi lại những thay đổi đó. Điều này đạt được bằng một đơn giản git checkout -b newBranch
sau git checkout B
. Điều này sẽ cung cấp cho bạn trạng thái
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master newBranch origin/master
^
|
HEAD
Điều này chỉ cung cấp tên để cam kết B
ngoài giá trị băm của nó. Sau khi một số cam kết hơn, trạng thái của bạn sẽ trông như thế này:
*---A---*---*---B---*---*---C
^ | ^
| | |
master \ origin/master
\
*---*---D
^
|
newBranch
^
|
HEAD
Vấn đề là, rằng, sau khi kiểm tra ra một số chi nhánh khác/cam kết với git checkout ...
, bạn luôn có thể dễ dàng trở lại cam kết D
bằng cách gọi git checkout newBranch
, và tham chiếu cố định dừng lại git
từ cam kết thu gom rác D
.
Bây giờ, tại sao sử dụng git reset --hard
không hợp lệ? Trước hết, nó thay đổi tất cả các thay đổi cục bộ mà bạn chưa cam kết mà không cần thông báo thêm. Thứ hai, nó có thể làm bạn mất lịch sử nếu bạn không cẩn thận với nó. Ví dụ:
Hãy xem xét trường hợp bạn đã thực hiện một số thay đổi sau lần cuối cùng bạn đẩy tới kho lưu trữ ngược dòng của mình và muốn xem xét một số cam kết lịch sử B
. (. Hơi ngược lại của vụ án trong câu hỏi của bạn) Lịch sử trông như thế này:
*---A---*---*---B---*---*---C
^ ^
| |
origin/master master
^
|
HEAD
Với git reset --hard B
, bạn sẽ có được trạng thái này:
*---A---*---*---B-(-*---*---C)
^ ^
| |
origin/master master
^
|
HEAD
Các cam kết trong ngoặc đơn không được tham chiếu trực tiếp hoặc gián tiếp bởi bất kỳ chi nhánh nào nữa, và có thể là rác thu thập bất cứ lúc nào. git
có thể không quá tích cực với việc thu thập rác, nhưng nếu thu gom rác trong khi bạn ở trạng thái này, không có cách nào để bạn nhận được cam kết C
trở lại, nó sẽ bị mất mãi mãi. Bạn không muốn điều này xảy ra, do đó, không nên để thói quen sử dụng git reset --hard
một cách nhẹ nhàng.
Nếu bạn đã sử dụng git checkout
thay vào đó, chi nhánh master
sẽ vẫn trỏ vào C
và bạn vẫn có thể quay lại với đơn giản git checkout master
.
Bạn không thực sự cần phải thiết lập lại chi nhánh, vì bạn có thể chỉ cần tạo nó với điểm bắt đầu là nơi bạn muốn nó, tức là.'git branch newbranch SHA1-of-B', hoặc' git checkout -b newbranch SHA1-of-B' – Hasturkun
@ Sébastien Cảm ơn bạn đã giới thiệu cho tôi một số khái niệm cơ bản. –
@Hasturkun câu trả lời của bạn hoạt động hoàn hảo cho tôi, cảm ơn. –