a

Câu hỏi Làm cách nào để hoàn tác 'git add' trước khi commit?


Tôi đã thêm nhầm các tệp vào git bằng lệnh:

git add myfile.txt

Tôi chưa chạy git commit. Có cách nào để hoàn tác việc này, vì vậy các tệp này sẽ không được đưa vào cam kết không?


Hiện có 48 câu trả lời cho đến nay (một số bị xóa). Vui lòng không thêm địa chỉ mới trừ khi bạn có một số thông tin mới.


7464
2017-12-07 21:57


gốc


Bắt đầu với Git v1.8.4, tất cả các câu trả lời dưới đây sử dụng HEAD hoặc là head bây giờ có thể sử dụng @ thay cho HEAD thay thế. Xem câu trả lời này (phần cuối) để tìm hiểu lý do tại sao bạn có thể làm điều đó.
Tôi đã thực hiện một chút tóm tắt cho thấy tất cả các cách để unstage một tập tin: stackoverflow.com/questions/6919121/… - Daniel Alder
Tại sao không git checkout? - Erik Reppen
@ErikReppen git checkout không loại bỏ các thay đổi theo giai đoạn từ chỉ mục cam kết. Nó chỉ reverts un-staged thay đổi để sửa đổi cam kết cuối cùng - mà bằng cách này không phải là những gì tôi muốn, hoặc, tôi muốn những thay đổi, tôi chỉ muốn họ trong một cam kết sau này. - paxos1977
Nếu bạn sử dụng Eclipse, nó đơn giản như việc bỏ chọn các tệp trong hộp thoại cam kết - Hamzahfrq


Các câu trả lời:


Bạn có thể hoàn tác git add trước khi cam kết

git reset <file>

sẽ xóa nó khỏi chỉ mục hiện tại (danh sách "sắp được cam kết") mà không thay đổi bất kỳ thứ gì khác.

Bạn có thể dùng

git reset

mà không có bất kỳ tên tập tin nào để unstage tất cả các thay đổi do. Điều này có thể hữu ích khi có quá nhiều tệp được liệt kê từng cái một trong một khoảng thời gian hợp lý.

Trong các phiên bản cũ của Git, các lệnh trên tương đương với git reset HEAD <file> và git reset HEAD tương ứng, và sẽ thất bại nếu HEAD là không xác định (vì bạn chưa thực hiện bất kỳ cam kết nào trong repo của bạn) hoặc không rõ ràng (vì bạn đã tạo một chi nhánh được gọi là HEAD, đó là một điều ngu ngốc mà bạn không nên làm). Điều này đã được thay đổi trong Git 1.8.2Mặc dù vậy, trong các phiên bản Git hiện đại, bạn có thể sử dụng các lệnh trên ngay cả trước khi thực hiện cam kết đầu tiên của mình:

"git reset" (không có tùy chọn hoặc tham số) được sử dụng để báo lỗi khi      bạn không có bất kỳ cam kết nào trong lịch sử của bạn, nhưng bây giờ nó mang lại cho bạn      chỉ mục trống (để khớp với cam kết không tồn tại mà bạn thậm chí không bật).


8379
2017-12-07 22:30



Tất nhiên, đây không phải là hoàn tác thực sự, bởi vì nếu sai git add ghi đè phiên bản chưa được phân tích trước đó, chúng tôi không thể khôi phục phiên bản đó. Tôi đã cố gắng làm rõ điều này trong câu trả lời của tôi dưới đây. - leonbloy
git reset HEAD *.ext Ở đâu ext là các tệp của tiện ích mở rộng đã cho mà bạn muốn bỏ. Đối với tôi, đó là *.bmp & *.zip - boulder_ruby
@ Jonny, chỉ mục (còn gọi là khu vực dàn dựng) chứa tất cả các các tệp, không chỉ các tệp đã thay đổi. Nó "bắt đầu cuộc sống" (khi bạn kiểm tra một cam kết hoặc sao chép một repo) như là một bản sao của tất cả các tập tin trong cam kết được chỉ bởi HEAD. Vì vậy, nếu bạn tẩy một tệp từ chỉ mục (git rm --cached) có nghĩa là bạn đang chuẩn bị cam kết xóa tập tin đó. git reset HEAD <filename> mặt khác sẽ sao chép tệp từ HEAD sang chỉ mục, để cam kết tiếp theo sẽ không hiển thị bất kỳ thay đổi nào được thực hiện cho tệp đó. - Wildcard
Tôi vừa phát hiện ra rằng có một git reset -p giống như git add -p. Điều này thật tuyệt! - donquixote
Bạn thực sự có thể khôi phục ghi đè các thay đổi đã được dàn dựng trước đó nhưng không được sửa đổi trước đó nhưng không theo cách thân thiện và không an toàn 100% (ít nhất là không có gì tôi tìm thấy): goto .git / objects, tìm kiếm các tệp được tạo tại thời điểm git add bạn muốn khôi phục (61/3AF3... -> id đối tượng 613AF3...), sau đó git cat-file -p <object-id> (có thể đáng để phục hồi vài giờ làm việc nhưng cũng là một bài học để cam kết thường xuyên hơn ...) - Peter Schneider


Bạn muốn:

git rm --cached <added_file_to_undo>

Lý do:

Khi tôi mới này, lần đầu tiên tôi đã thử

git reset .

(để hoàn tác toàn bộ bổ sung ban đầu của tôi), chỉ để nhận được thông báo hữu ích (không phải như vậy):

fatal: Failed to resolve 'HEAD' as a valid ref.

Nó chỉ ra rằng điều này là do HEAD ref (branch?) Không tồn tại cho đến sau commit đầu tiên. Tức là, bạn sẽ gặp phải vấn đề của người mới bắt đầu giống như tôi nếu luồng công việc của bạn, giống như tôi, giống như:

  1. cd vào thư mục dự án mới tuyệt vời của tôi để thử Git, sự nóng bỏng mới
  2. git init
  3. git add .
  4. git status

    ... rất nhiều cuộn giấy ...

    => Chết tiệt, tôi không muốn thêm tất cả điều đó.

  5. google "hoàn tác git thêm"

    => tìm Stack Overflow - yay

  6. git reset .

    => gây tử vong: Không thể giải quyết 'HEAD' dưới dạng ref hợp lệ.

Nó tiếp tục chỉ ra rằng có một lỗi đăng nhập chống lại sự vô ích của điều này trong danh sách gửi thư.

Và đó là giải pháp chính xác ở ngay trong đầu ra trạng thái Git (trong đó, vâng, tôi đã che đậy như 'crap)

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

Và giải pháp thực sự là sử dụng git rm --cached FILE.

Lưu ý các cảnh báo khác ở đây - git rm xóa bản sao làm việc cục bộ của bạn, nhưng không phải nếu bạn dùng - cắt. Đây là kết quả của git help rm:

- cắt       Sử dụng tùy chọn này để unstage và loại bỏ đường dẫn chỉ từ chỉ mục.       Các tệp cây đang hoạt động, dù được sửa đổi hay không, sẽ bị bỏ lại.

Tôi tiến hành sử dụng

git rm --cached .

để xóa mọi thứ và bắt đầu lại. Mặc dù không hoạt động, bởi vì trong khi add . là đệ quy, hóa ra rm nhu cầu -r để tái chế. Thở dài.

git rm -r --cached .

Được rồi, giờ tôi quay lại nơi tôi đã bắt đầu. Lần tới tôi sẽ sử dụng -n để chạy khô và xem những gì sẽ được thêm vào:

git add -n .

Tôi đã nén mọi thứ đến một nơi an toàn trước khi tin tưởng git help rm về --cached không phá hủy bất cứ điều gì (và nếu tôi sai chính tả nó).


1954
2018-03-25 16:20



Hah. Tôi đã làm theo quá trình này. Ngoại trừ tôi đã từ bỏ và nói rm -rf .git, git init bởi vì tôi không tin tưởng git rm --cached để giữ bản sao làm việc của tôi. Nó nói một chút về cách git vẫn còn quá phức tạp ở một số nơi. git unstage chỉ nên là một lệnh tiêu chuẩn chứng khoán, tôi không quan tâm nếu tôi có thể thêm nó như là một bí danh. - Adrian Macneil
Đối với tôi git nói git reset HEAD <File>... - drahnr
git rm --cached <file> thực sự là câu trả lời đúng, nếu đó là lần nhập ban đầu của <file> vào kho lưu trữ. Nếu bạn đang cố gắng để unstage một sự thay đổi tập tin, git đặt lại là câu trả lời đúng. Mọi người nói rằng câu trả lời này là sai lầm đang nghĩ đến một câu hỏi khác. - Barry Kelly
Điều này thực sự sẽ hiệu quả, nhưng chỉ có trên cam kết đầu tiên, nơi tệp không tồn tại trước hoặc ở nơi git add lệnh đã thêm tệp mới, nhưng không thay đổi các tệp hiện có. - naught101
chỉ cần cho thấy git không trực quan và phức tạp như thế nào. thay vì có lệnh "hoàn tác" song song, bạn phải tìm hiểu cách hoàn tác chúng. Giống như cố gắng để giải phóng chân của bạn trong cát nhanh chóng, và sau đó nhận được cánh tay của bạn bị mắc kẹt, sau đó nhận được cánh tay khác của bạn bị mắc kẹt ... mỗi lệnh nên được thực hiện thông qua giao diện, với các menu thả xuống cho các tùy chọn ... Hãy suy nghĩ của tất cả các giao diện người dùng, tăng năng suất chúng tôi đã có, nhưng chúng tôi có mớ hỗn độn của một giao diện dòng lệnh retro. Nó không giống như các chương trình GUI git làm cho điều này trực quan hơn. - ahnbizcad


Nếu bạn gõ:

git status

git sẽ cho bạn biết những gì được dàn dựng, v.v., bao gồm các hướng dẫn về cách unstage:

use "git reset HEAD <file>..." to unstage

Tôi tìm thấy git làm một công việc khá tốt để thúc đẩy tôi làm điều đúng trong những tình huống như thế này.

Lưu ý: Các phiên bản git gần đây (1.8.4.x) đã thay đổi thông báo này:

(use "git rm --cached <file>..." to unstage)

484
2017-12-07 23:22



Thông báo sẽ khác nhau tùy thuộc vào việc addtệp ed đã được theo dõi ( add chỉ lưu phiên bản mới vào bộ nhớ cache - tại đây nó sẽ hiển thị thông báo của bạn). Ở những nơi khác, nếu tập tin không được dàn dựng trước đó, nó sẽ hiển thị use "git rm --cached <file>..." to unstage - leonbloy
Tuyệt quá! Các git reset HEAD <file> một trong số đó là người duy nhất sẽ làm việc trong trường hợp bạn muốn unstage một tập tin xóa - skerit
Phiên bản git của tôi 2.14.3 nói git reset HEAD để unstage. - seaturtle


Làm rõ: git add di chuyển các thay đổi từ thư mục làm việc hiện tại sang khu vực dàn dựng (mục lục).

Quá trình này được gọi là dàn dựng. Vì vậy, lệnh tự nhiên nhất để sân khấu các thay đổi (tệp đã thay đổi) là một thay đổi rõ ràng:

git stage

git add chỉ cần nhập bí danh dễ dàng hơn git stage

Tiếc là không có git unstage cũng không git unadd lệnh. Người có liên quan khó đoán hoặc nhớ, nhưng khá rõ ràng:

git reset HEAD --

Chúng tôi có thể dễ dàng tạo bí danh cho điều này:

git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'

Và cuối cùng, chúng tôi có các lệnh mới:

git add file1
git stage file2
git unadd file2
git unstage file1

Cá nhân tôi sử dụng các bí danh ngắn hơn:

git a #for staging
git u #for unstaging

220
2017-09-10 20:28



"di chuyển"? Điều này sẽ cho biết nó đã đi từ thư mục làm việc. Đó không phải là trường hợp. - Thomas Weller
Tại sao nó rõ ràng? - Lenar Hoyt


Ngoài câu trả lời được chấp nhận, nếu tệp được thêm nhầm của bạn là rất lớn, bạn có thể nhận thấy rằng, ngay cả sau khi xóa nó khỏi chỉ mục bằng 'git reset', nó vẫn có vẻ chiếm không gian trong .git danh mục. Điều này không có gì phải lo lắng, tệp thực sự vẫn còn trong kho lưu trữ, nhưng chỉ là một "đối tượng lỏng lẻo", nó sẽ không được sao chép sang các kho lưu trữ khác (qua bản sao, đẩy) và không gian sẽ được khôi phục - mặc dù có lẽ không sớm. Nếu bạn lo lắng, bạn có thể chạy:

git gc --prune=now

Cập nhật (những gì sau đây là nỗ lực của tôi để xóa một số nhầm lẫn có thể phát sinh từ các câu trả lời được bình chọn nhiều nhất):

Vì vậy, đó là thực tế hủy bỏ của git add?

git reset HEAD <file> ?

hoặc là

git rm --cached <file>?

Nói đúng ra, và nếu tôi không nhầm: không ai.

git add  không thể hoàn tác - nói chung, một cách an toàn.

Hãy nhớ lại những gì trước git add <file> thực sự:

  1. Nếu <file> là chưa được theo dõi trước đó, git add  thêm nó vào bộ đệm, với nội dung hiện tại của nó.

  2. Nếu <file> là đã được theo dõi, git add  lưu nội dung hiện tại (ảnh chụp nhanh, phiên bản) vào bộ nhớ cache. Trong GIT, hành động này vẫn được gọi thêm vào, (không phải chỉ cập nhật nó), bởi vì hai phiên bản khác nhau (ảnh chụp nhanh) của một tệp được coi là hai mục khác nhau: do đó, chúng tôi đang thực sự thêm một mục mới vào bộ nhớ cache, để cuối cùng được cam kết sau này.

Trong điều này, câu hỏi hơi mơ hồ:

Tôi đã thêm nhầm lẫn các tệp bằng lệnh ...

Kịch bản của OP có vẻ là tệp đầu tiên (tệp không được theo dõi), chúng tôi muốn "hoàn tác" để xóa tệp (không chỉ nội dung hiện tại) khỏi các mục được theo dõi. Nếu đây là trường hợp, sau đó nó là ok để chạy git rm --cached <file>.

Và chúng tôi cũng có thể chạy git reset HEAD <file>. Điều này nói chung là thích hợp hơn, bởi vì nó hoạt động trong cả hai kịch bản: nó cũng làm hoàn tác khi chúng tôi thêm sai một phiên bản của một mục đã được theo dõi.

Nhưng có hai cảnh báo.

Thứ nhất: Có (như được chỉ ra trong câu trả lời) chỉ có một kịch bản trong đó git reset HEAD không hoạt động, nhưng git rm --cached hiện: một kho lưu trữ mới (không có cam kết). Nhưng, thực sự, đây là một trường hợp thực tế không liên quan.

Thứ hai: Hãy nhận biết rằng git reset HEAD  không thể khôi phục một cách kỳ diệu các nội dung tập tin được lưu trong bộ nhớ cache trước đó, nó chỉ resyncs nó từ HEAD. Nếu sai lầm của chúng tôi git add ghi đè phiên bản không được cam kết trước đó, chúng tôi không thể khôi phục phiên bản đó. Đó là lý do tại sao, nói đúng, chúng tôi không thể hoàn tác.

Thí dụ:

$ git init
$ echo "version 1" > file.txt
$ git add file.txt   # first add  of file.txt
$ git commit -m 'first commit'
$ echo "version 2" > file.txt
$ git add  file.txt   # stage (don't commit) "version 2" of file.txt
$ git diff --cached file.txt
-version 1
+version 2
$ echo "version 3" > file.txt   
$ git diff  file.txt
-version 2
+version 3
$ git add  file.txt    # oops we didn't mean this
$ git reset HEAD file.txt  # undo ?
$ git diff --cached file.txt  # no dif, of course. stage == HEAD
$ git diff file.txt   # we have lost irrevocably "version 2"
-version 1
+version 3

Tất nhiên, điều này không quan trọng nếu chúng ta chỉ làm theo quy trình làm việc lười biếng thông thường khi thực hiện 'git add' để thêm tệp mới (trường hợp 1) và chúng tôi cập nhật nội dung mới thông qua cam kết, git commit -a chỉ huy.


137
2018-05-18 18:05



Nói đúng ra có một cách để khôi phục một tệp đã được dàn dựng đã được thay thế bằng git add. Khi bạn đề cập đến git add tạo ra một đối tượng git cho tập tin đó sẽ trở thành một đối tượng lỏng lẻo không chỉ khi loại bỏ các tập tin hoàn toàn mà còn khi được ghi đè bằng nội dung mới. Nhưng không có lệnh để tự động phục hồi nó. Thay vào đó, tệp phải được xác định và trích xuất thủ công hoặc bằng các công cụ được viết chỉ dành cho trường hợp này (libgit2 sẽ cho phép điều này). Nhưng điều này sẽ chỉ trả tiền nếu tệp rất quan trọng và lớn và không thể xây dựng lại bằng cách chỉnh sửa phiên bản trước đó. - Johannes Matokic
Để sửa bản thân mình: Khi tìm thấy tệp đối tượng lỏng lẻo (sử dụng siêu dữ liệu như ngày / giờ tạo) git cat-file có thể được sử dụng để khôi phục nội dung của nó. - Johannes Matokic
Một cách khác để khôi phục các thay đổi đã được dàn dựng nhưng không được cam kết và sau đó ghi đè bằng ví dụ: khác git add qua git fsck --unreachable sẽ liệt kê tất cả các obj không thể truy cập, mà bạn có thể kiểm tra bằng git show SHA-1_ID hoặc là git fsck --lost-found sẽ> Viết các đối tượng lơ lửng vào .git/lost-found/commit/ hoặc là .git/lost-found/other/, tùy thuộc vào loại. Xem thêm git fsck --help - iolsmit


git rm --cached . -r

sẽ "bỏ thêm" mọi thứ bạn đã thêm từ thư mục hiện tại của bạn đệ quy


85
2017-12-09 21:19



Tôi không tìm cách bỏ thêm mọi thứ, chỉ một tệp cụ thể. - paxos1977
Cũng hữu ích nếu bạn không có bất kỳ cam kết trước đó. Không có cam kết trước đó, git reset HEAD <file> sẽ nói fatal: Failed to resolve 'HEAD' as a valid ref. - Priya Ranjan Singh
Không, cái này bổ sung một sự xóa của mọi thứ trong thư mục hiện tại của bạn. Rất khác với những thay đổi không thay đổi. - Mark Amery


Chạy

git gui

và xóa tất cả các tệp theo cách thủ công hoặc bằng cách chọn tất cả chúng và nhấp vào unstage từ cam kết nút.


77
2017-10-12 01:12



Vâng, tôi hiểu điều đó. Tôi chỉ muốn ngầm gợi ý rằng bạn cho biết rằng câu trả lời của bạn như "Bạn có thể sử dụng git-gui.... ":) - Alexander Suraphel
Nó nói, "git-gui: lệnh không tìm thấy". Tôi không chắc chắn nếu điều này hoạt động. - Parinda Rajapaksha


Git có các lệnh cho mọi hành động có thể tưởng tượng được, nhưng cần kiến ​​thức sâu rộng để có được những điều đúng đắn và bởi vì nó có tính trực giác tốt nhất ...

Những gì bạn đã làm trước đây:

  • Đã thay đổi một tệp và được sử dụng git add ., hoặc là git add <file>.

Bạn muốn gì:

  • Loại bỏ các tập tin từ chỉ mục, nhưng giữ cho nó được phiên bản và để lại với những thay đổi không được cam kết trong bản sao làm việc:

    git reset head <file>
    
  • Đặt lại tệp về trạng thái cuối cùng từ HEAD, hoàn tác các thay đổi và xóa chúng khỏi chỉ mục:

    # Think `svn revert <file>` IIRC.
    git reset HEAD <file>
    git checkout <file>
    
    # If you have a `<branch>` named like `<file>`, use:
    git checkout -- <file>
    

    Điều này là cần thiết kể từ git reset --hard HEAD sẽ không hoạt động với các tệp đơn lẻ.

  • Tẩy <file> từ chỉ mục và phiên bản, giữ tập tin chưa được phiên bản với các thay đổi trong bản sao làm việc:

    git rm --cached <file>
    
  • Tẩy <file> từ bản sao và phiên bản làm việc hoàn toàn:

    git rm <file>
    

73
2018-03-29 11:14



Tôi không thể chịu được sự khác biệt của 'git reset head <file>' và 'git rm --cached <file>. Bạn có thể giải thích nó? - jeswang
@ jeswang tập tin hoặc là 'được biết đến' để git (thay đổi trong chúng đang được theo dõi.), hoặc họ không phải là 'phiên bản'. reset head undoes thay đổi hiện tại của bạn, nhưng tập tin vẫn đang được theo dõi bởi git. rm --cached lấy tập tin ra khỏi phiên bản, vì vậy git không còn kiểm tra nó để thay đổi (và cũng loại bỏ cuối cùng được lập chỉ mục thay đổi hiện tại, nói với git bởi trước add), nhưng tệp đã thay đổi sẽ được giữ trong bản sao làm việc của bạn, đó là trong thư mục tệp của bạn trên ổ cứng. - sjas
Sự khác biệt là git reset HEAD <file> là tạm thời - lệnh sẽ chỉ được áp dụng cho cam kết tiếp theo, nhưng git rm --cached <file> sẽ unstage cho đến khi nó được thêm một lần nữa với git add <file>. Cũng thế, git rm --cached <file> có nghĩa là nếu bạn đẩy chi nhánh đó vào điều khiển từ xa, bất kỳ ai kéo nhánh sẽ nhận được tệp ACTUALLY bị xóa khỏi thư mục của họ. - DrewT


Câu hỏi không được đặt ra rõ ràng. Lý do là git add có hai ý nghĩa:

  1. thêm một tập tin mới đến khu vực dàn dựng, sau đó hoàn tác với git rm --cached file.
  2. thêm một đã sửa đổi vào vùng dàn dựng, sau đó hoàn tác với git reset HEAD file.

nếu nghi ngờ, hãy sử dụng

git reset HEAD file

Bởi vì nó làm điều mong đợi trong cả hai trường hợp.

Cảnh báo: nếu bạn làm git rm --cached file trên một tệp đã sửa đổi (một tệp tồn tại trước đó trong kho lưu trữ), khi đó tệp sẽ bị xóa git commit! Nó sẽ vẫn tồn tại trong hệ thống tập tin của bạn, nhưng nếu bất kỳ ai khác kéo cam kết của bạn, tập tin sẽ bị xóa khỏi cây công việc của họ.

git status sẽ cho bạn biết liệu tệp có phải là tập tin mới hoặc là đã sửa đổi:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   my_new_file.txt
    modified:   my_modified_file.txt

62
2018-01-16 19:54



+1. Một số lượng lớn câu trả lời và nhận xét được đánh giá cao trên trang này chỉ là không đúng về hành vi của git rm --cached somefile. Tôi hy vọng câu trả lời này làm cho con đường của nó lên trang đến một vị trí nổi bật, nơi nó có thể bảo vệ người mới khỏi bị lừa bởi tất cả các tuyên bố sai. - Mark Amery


Hủy bỏ một tệp đã được thêm vào khá dễ sử dụng git, để đặt lại myfile.txt đã được thêm vào, sử dụng:

git reset HEAD myfile.txt

Giải thích:

Sau khi bạn dàn dựng (các) tệp không mong muốn, để hoàn tác, bạn có thể làm git reset, Head là người đứng đầu tệp của bạn ở địa phương và tham số cuối cùng là tên tệp của bạn.

Tôi tạo các bước trong hình ảnh bên dưới để biết thêm chi tiết cho bạn, bao gồm tất cả các bước có thể xảy ra trong những trường hợp sau:

git reset HEAD


60
2018-06-28 10:43