Unstage một tập tin bị xóa trong git


504

Thông thường, để loại bỏ các thay đổi đối với một tệp bạn sẽ làm:

git checkout -- <file>

Điều gì xảy ra nếu thay đổi tôi muốn loại bỏ đang xóa tệp? Dòng trên sẽ báo lỗi:

error: pathspec '<file>' did not match any file(s) known to git.

Lệnh nào sẽ khôi phục tập tin duy nhất đó mà không hoàn tác các thay đổi khác?

điểm thưởng: Ngoài ra, nếu thay đổi tôi muốn loại bỏ là thêm một tệp thì sao? Tôi cũng muốn biết làm thế nào để thay đổi sự thay đổi đó.


1
Loại bỏ các thay đổi và không theo dõi là hai điều khác nhau, bạn đang cố gắng làm gì?
Andrew Marshall

1
Đây là hai câu hỏi và vấn đề khác nhau trong một bài. Điều này làm cho các câu trả lời quá nhiều và khó hiểu không cần thiết.
David Sopko

Câu trả lời:


779

Giả sử bạn muốn hoàn tác các hiệu ứng git rm <file>hoặc rm <file>theo sau git add -Ahoặc một cái gì đó tương tự:

# this restores the file status in the index
git reset -- <file>
# then check out a copy from the index
git checkout -- <file>

Để hoàn tác git add <file>, dòng đầu tiên ở trên đủ, giả sử bạn chưa cam kết.


70
Đây --là chìa khóa. git reset <file>không làm việc, đó là những gì mang tôi đến đây.

2
Tại sao chỉ được end-of-options-markeryêu cầu trong trường hợp tệp bị xóa?
haridsv

5
@handsv Không yêu cầu nghiêm ngặt (bạn có thể luân phiên làm git reset HEAD <file>, tương đương), nhưng git resetxử lý đối số đầu tiên của nó trước đây end-of-options-markerdưới dạng tên ref, không phải tên tệp. Nó có thể được viết linh hoạt hơn một chút? Có lẽ. Tại sao không phải là nó? Có lẽ chỉ có các nhà phát triển biết chắc chắn.
twalberg

2
@twalberg git reset filenamehoạt động tốt đối với các tệp không bị xóa.
Brian Gordon

1
@AaronMahan - bạn có thể vui lòng giải thích sự khác biệt giữa git reset <file>git reset -- <file>. Tôi đang gặp khó khăn khi tìm câu trả lời cho điều đó trên google.
Neeraj B.

56

Cả hai câu hỏi được trả lời trong git status.

Để unstage thêm một tập tin mới sử dụng git rm --cached filename.ext

# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   test

Để unstage xóa một tập tin sử dụng git reset HEAD filename.ext

# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   deleted:    test

Mặt khác, git checkout --không bao giờ bỏ qua, nó chỉ loại bỏ những thay đổi không theo giai đoạn.


5
Tôi không thấy gợi ý cho một tệp đã bị xóa trong git 1.7.2.5 trên Debian.
tripleee

Rất vui được xem git statustrích dẫn; chỉ cho người dùng cách tự trợ giúp ngay bây giờ và lần sau và trong trường hợp thông tin được thêm hoặc cập nhật trong các phiên bản git trong tương lai.
Will Cain

Cái này sai. "Những thay đổi được cam kết" là những gì bạn nhìn thấy trước sự git reset. Sau đó git reset, bạn thấy "Thay đổi nhưng không cập nhật" có nghĩa là "Thay đổi không được dàn dựng" bằng ngôn ngữ bản địa của các tác giả git, rõ ràng. Quan trọng hơn, toàn bộ giáo điều về "tình trạng git cho bạn biết mọi thứ bạn biết" là một lời nói dối. (Những người quản lý nói rằng đang lãng phí thời gian của mọi người và nên bị sa thải.)
Personal_cloud

11

Các câu trả lời cho hai câu hỏi của bạn có liên quan. Tôi sẽ bắt đầu với cái thứ hai:

Khi bạn đã dàn dựng một tệp (thường là với git add, mặc dù một số lệnh khác cũng hoàn toàn thay đổi các thay đổi, như git rm), bạn có thể sao lưu thay đổi đó bằng git reset -- <file>.

Trong trường hợp của bạn, bạn phải sử dụng git rmđể xóa tệp, tương đương với việc xóa nó đi rmvà sau đó dàn dựng sự thay đổi đó. Nếu bạn lần đầu tiên mở khóa nó với git reset -- <file>bạn thì bạn có thể khôi phục nó bằng git checkout -- <file>.


7

Nếu nó đã được dàn dựng và cam kết, thì sau đây sẽ đặt lại tệp:

git reset COMMIT_HASH file_path
git checkout COMMIT_HASH file_path
git add file_path

Điều này sẽ làm việc cho một xóa đã xảy ra một số cam kết trước đó.


1
Nó hiệu quả hơngit revert COMMIT_HASH
Flair

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.