it-swarm-vi.com

Làm cách nào để hoàn tác 'git add' trước khi xác nhận?

Tôi đã thêm nhầm 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 không, vì vậy những tệp này sẽ không được đưa vào cam kết?


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

8101
paxos1977

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

git reset <file>

sẽ loại bỏ 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 cứ điều gì khác.

Bạn có thể dùng

git reset

không có bất kỳ tên tập tin nào để bỏ qua tất cả các thay đổi do. Điều này có thể có í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>git reset HEAD và sẽ không thành công nếu HEAD không được xác định (vì bạn chưa thực hiện bất kỳ cam kết nào trong repo của mình) hoặc mơ hồ (vì bạn đã tạo một nhánh có tên 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.2 , tuy nhiên, 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 mình, nhưng giờ đây nó cung cấp cho bạn một 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).

9181
genehack

Bạn muốn:

git rm --cached <added_file_to_undo>

Lý do:

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

git reset .

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

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

Hóa ra điều này là do HEAD ref (nhánh?) Không tồn tại cho đến sau lần cam kết đầu tiên. Đó là, bạn sẽ gặp phải vấn đề tương tự như người mới bắt đầu nếu quy trình làm việc của bạn, như của tôi, là một cái gì đó như:

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

    ... rất nhiều cuộn tào lao bằng ...

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

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

    => tìm Stack Overflow - yay

  6. git reset .

    => gây tử vong: Không thể giải quyết 'ĐẦU' dưới dạng tham chiếu hợp lệ.

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

Và rằng giải pháp chính xác đã có ngay trong đầu ra trạng thái Git (trong đó, vâng, tôi đã nhấn mạnh là 'tào lao)

...
# 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 ở nơi khác tại đây - git rm xóa bản sao làm việc cục bộ của tệp, nhưng không nếu bạn sử dụng --cached . Đây là kết quả của git help rm:

--cached Sử dụng tùy chọn này để hủy bỏ và chỉ xóa các đường dẫn khỏi chỉ mục. Các tệp cây làm việc, cho dù có sửa đổi hay không, sẽ được để lại.

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

git rm --cached .

để loại bỏ mọi thứ và bắt đầu lại. Mặc dù vậy, nó không hoạt động, bởi vì trong khi add . là đệ quy, hóa ra rm cần -r để lặp lại. Thở dài.

git rm -r --cached .

Được rồi, bây giờ tôi trở 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ề việc --cached không phá hủy bất cứ thứ gì (và nếu tôi viết sai chính tả thì sao).

2047
Rhubarb

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 mở khóa:

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

Tôi thấy git làm một công việc khá tốt là thúc đẩy tôi làm điều đúng đắn 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)
507
Paul Beckingham

Để 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 (chỉ mục).

Quá trình này được gọi là dàn dựng . Vì vậy, lệnh tự nhiên nhất đến giai đoạn thay đổi (tệp đã thay đổi) là lệnh rõ ràng:

git stage

git add chỉ là một cách dễ dàng hơn để nhập bí danh cho git stage

Đáng tiếc không có lệnh git unstage hay git unadd. Cái có liên quan khó đoán hoặc khó nhớ hơn, nhưng khá rõ ràng:

git reset HEAD --

Chúng ta có thể dễ dàng tạo một bí danh cho việc này:

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

Và cuối cùng, chúng ta 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 thậm chí ngắn hơn:

git a #for staging
git u #for unstaging
238
takeshin

Ngoài ra, câu trả lời được chấp nhận, nếu tệp được thêm nhầm của bạn rất lớn, có thể bạn sẽ nhận thấy rằng, ngay cả sau khi xóa nó khỏi chỉ mục với 'git reset', nó dường như vẫn chiếm dung lượng trong thư mục .git. Điều này không có gì đáng lo ngại, tập tin 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 (thông qua bản sao, Push) và cuối cùng không gian sẽ được thu hồi 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 (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ậy, đâu là thực hoàn tác 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: none .

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

Trước tiên hãy nhớ lại những gì git add <file> thực sự làm:

  1. Nếu <file> không đượ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> đã đã đượ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ộ đệm. Trong GIT, hành động này vẫn được gọi là add , (không chỉ update it), 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 thực sự đang thêm một mục mới vào bộ đệm, cuối cùng sẽ được cam kết sau.

Trước vấn đề này, câu hỏi hơi mơ hồ:

Tôi đã thêm nhầm tệp bằng cách sử dụng lệnh ...

Kịch bản của OP dường như là kịch bản đầu tiên (tệp không bị 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, thì bạn có thể 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à tốt hơn, bởi vì nó hoạt động trong cả hai trường hợp: nó cũng 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 hãy cẩn thận.

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 không: 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: Lưu ý rằng git reset HEAD không thể phục hồi một cách kỳ diệu các nội dung tệp được lưu trong bộ nhớ cache trước đó, nó chỉ đồng bộ lại từ ĐẦU. Nếu git add sai lầm của chúng tôi ghi đè lên một phiên bản không được cam kết trước đó, chúng tôi không thể khôi phục nó. Đó là lý do tại sao, nói đúng ra, chúng ta 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 lắm nếu chúng ta chỉ tuân theo quy trình làm việc lười biếng thông thường là chỉ 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 lệnh git commit -a.


* (Chỉnh sửa: thực tế ở trên là chính xác, nhưng vẫn có thể có một số cách hơi bị hack/phức tạp để khôi phục các thay đổi đã được dàn dựng nhưng không được cam kết và sau đó được ghi đè - xem các bình luận của Johannes Matokic và iolsmit)

161
leonbloy
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 mình một cách đệ quy

91
braitsch

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ả các tệp và nhấp vào nút unstage từ cam kết .

85
Khaja Minhajuddin

Hoàn tác một tệp đã được thêm vào khá dễ dàng bằng cách sử dụng git , để đặt lại myfile.txt đã thêm, 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ể thực hiện git reset, Head là phần đầu của tệp của bạn ở địa phương và tham số cuối cùng là tên của 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 file

82
Alireza

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

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

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

Bạn muốn gì:

  • Xóa tệp khỏi chỉ mục, nhưng giữ nguyên phiên bản và để lại các 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ừ CHÍNH, 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 vì git reset --hard HEAD sẽ không hoạt động với các tệp đơn lẻ.

  • Xóa <file> khỏi chỉ mục và phiên bản, giữ tệp 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>
    
  • Xóa hoàn toàn <file> khỏi bản sao làm việc và phiên bản hoàn toàn:

    git rm <file>
    
80
sjas

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 mớivào khu vực tổ chức, sau đó hoàn tác với git rm --cached file.
  2. thêm một đã sửa đổitệp vào khu vực tổ chức, 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ữ), thì tệp sẽ bị xóa trong git commit! nếu bất kỳ ai khác thực hiện cam kết của bạn, tệp sẽ bị xóa khỏi cây công việc của họ.

git status sẽ cho bạn biết nếu tệp là tệp mớihoặc đã 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
71
Michael_Scharf

Nếu bạn đang cam kết ban đầu và bạn không thể sử dụng git reset, chỉ cần khai báo "Git phá sản" và xóa thư mục .git và bắt đầu lại

61
Paul Betts

Theo nhiều câu trả lời khác, bạn có thể sử dụng git reset

NHƯNG:

Tôi tìm thấy bài đăng nhỏ tuyệt vời này thực sự thêm lệnh Git (cũng là bí danh) cho git unadd: xem git unadd để biết chi tiết hoặc ..

Đơn giản,

git config --global alias.unadd "reset HEAD"

Bây giờ bạn có thể

git unadd foo.txt bar.txt
55
electblake

git remove hoặc git rm có thể được sử dụng cho việc này, với cờ --cached. Thử:

git help rm
46
gnud

Sử dụng git add -i để xóa các tệp vừa thêm khỏi cam kết sắp tới của bạn. Thí dụ:

Thêm tệp bạn không muốn:

$ git add foo
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   foo
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]#

Đi vào tương tác thêm để hoàn tác thêm (các lệnh được nhập tại git ở đây là "r" (hoàn nguyên), "1" (mục đầu tiên trong danh sách hoàn nguyên hiển thị), 'return' để thoát khỏi chế độ hoàn nguyên và "q" (bỏ):

$ git add -i
           staged     unstaged path
  1:        +1/-0      nothing foo

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> r
           staged     unstaged path
  1:        +1/-0      nothing [f]oo
Revert>> 1
           staged     unstaged path
* 1:        +1/-0      nothing [f]oo
Revert>> 
note: foo is untracked now.
reverted one path

*** Commands ***
  1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
  5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
What now> q
Bye.
$

Đó là nó! Đây là bằng chứng của bạn, cho thấy "foo" đã trở lại trong danh sách chưa được theo dõi:

$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# [...]
#       foo
nothing added to commit but untracked files present (use "git add" to track)
$
42
Alex North-Keys

Đây là một cách để tránh vấn đề khó chịu này khi bạn bắt đầu một dự án mới:

  • Tạo thư mục chính cho dự án mới của bạn.
  • Chạy git init.
  • Bây giờ hãy tạo một tệp .gitignore (ngay cả khi nó trống).
  • Cam kết tập tin .gitignore của bạn.

Git làm cho nó thực sự khó thực hiện git reset nếu bạn không có bất kỳ cam kết nào. Nếu bạn tạo một cam kết ban đầu nhỏ chỉ vì muốn có một, sau đó bạn có thể git add -Agit reset bao nhiêu lần bạn muốn để có được mọi thứ đúng.

Một ưu điểm khác của phương pháp này là nếu sau này bạn gặp phải rắc rối kết thúc dòng và cần làm mới tất cả các tệp của mình, thật dễ dàng:

  • Kiểm tra cam kết ban đầu. Điều này sẽ loại bỏ tất cả các tập tin của bạn.
  • Sau đó kiểm tra cam kết gần đây nhất của bạn một lần nữa. Điều này sẽ lấy các bản sao mới của các tệp của bạn, bằng cách sử dụng cài đặt kết thúc dòng hiện tại của bạn.
37
Ryan Lundy

Có lẽ Git đã phát triển kể từ khi bạn đăng câu hỏi của bạn.

$> git --version
git version 1.6.2.1

Bây giờ, bạn có thể thử:

git reset HEAD .

Đây phải là những gì bạn đang tìm kiếm.

33
Kokotte23

Lưu ý rằng nếu bạn không chỉ định sửa đổi thì bạn phải bao gồm một dấu phân cách. Ví dụ từ bảng điều khiển của tôi:

git reset <path_to_file>
fatal: ambiguous argument '<path_to_file>': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

git reset -- <path_to_file>
Unstaged changes after reset:
M   <path_to_file>

(phiên bản git 1.7.5.4)

33
powlo

Để xóa các tệp mới khỏi khu vực tổ chức (và chỉ trong trường hợp tệp mới), như được đề xuất ở trên:

git rm --cached FILE

Chỉ sử dụng rm --cached cho các tệp mới vô tình được thêm vào.

30
Ran

Để đặt lại mọi tệp trong một thư mục cụ thể (và các thư mục con của nó), bạn có thể sử dụng lệnh sau:

git reset *
24
Zorayr

sử dụng lệnh * để xử lý nhiều tệp cùng một lúc

git reset HEAD *.prj
git reset HEAD *.bmp
git reset HEAD *gdb*

v.v.

24
boulder_ruby

Chỉ cần gõ git reset nó sẽ trở lại và nó giống như bạn chưa bao giờ gõ git add . kể từ lần cam kết cuối cùng của bạn. Hãy chắc chắn rằng bạn đã cam kết trước đó.

22
Donovan

Giả sử tôi tạo một tệp mới newFile.txt.

 enter image description here

Giả sử tôi thêm tệp một cách vô tình, git add newFile.txt

 enter image description here

Bây giờ tôi muốn hoàn tác phần bổ sung này, trước khi xác nhận, git reset newFile.txt

 enter image description here

18
Vidura Mudalige

Đối với một tệp cụ thể:

  • git đặt lại my_file.txt
  • kiểm tra git my_file.txt

Đối với tất cả các tệp đã thêm:

  • git đặt lại.
  • kiểm tra git.

Lưu ý: kiểm tra thay đổi mã trong các tệp và chuyển sang trạng thái cập nhật (cam kết) mới nhất. đặt lại không thay đổi mã; nó chỉ đặt lại tiêu đề.

17
Hasib Kamal

Để hoàn tác git thêm sử dụng

git reset filename

13
Anirudh Sood

Lệnh này sẽ hủy bỏ các thay đổi của bạn:

git reset HEAD filename.txt

Bạn cũng có thể dùng

git add -p 

để thêm các phần của tập tin.

13
wallerjake

Tôi ngạc nhiên khi không ai đề cập đến chế độ tương tác:

git add -i

chọn tùy chọn 3 để bỏ tập tin Trong trường hợp của tôi, tôi thường muốn thêm nhiều tệp, với chế độ tương tác, bạn có thể sử dụng các số như thế này để thêm tệp. Điều này sẽ mất tất cả trừ 4: 1,2,3,5

Để chọn một chuỗi, chỉ cần gõ 1-5 để lấy tất cả từ 1 đến 5.

Tập tin phân tầng Git

13
Jonathan

git add myfile.txt # này sẽ thêm tệp của bạn vào danh sách được cam kết

Hoàn toàn ngược lại với lệnh này là,

git reset HEAD myfile.txt  # this will undo it. 

vì vậy, bạn sẽ ở trạng thái trước. được chỉ định sẽ một lần nữa trong danh sách không theo dõi (trạng thái trước đó).

nó sẽ thiết lập lại đầu của bạn với tập tin được chỉ định đó. vì vậy, nếu đầu của bạn không có ý nghĩa, nó sẽ đơn giản đặt lại nó

9
Silent Spectator
git reset filename.txt

Sẽ xóa một tệp có tên filename.txt khỏi chỉ mục hiện tại, khu vực "sắp được cam kết", mà không thay đổi bất cứ điều gì khác.

9
Rahul Sinha

Trong SourceTree bạn có thể làm điều này một cách dễ dàng thông qua gui. Bạn có thể kiểm tra lệnh sourcetree nào sử dụng để hủy tập tin.

Tôi đã tạo một tập tin mới và thêm nó vào git. Sau đó, tôi đã tạo ra nó bằng cách sử dụng gui của SourceTree. Đây là kết quả:

Các tập tin chưa được chỉnh sửa [08/12/15 10:43]
[.__.] git -c diff.mnemonicprefix = false -c core.quotepath = false -c bằng chứng

SourceTree sử dụng reset để bỏ qua các tệp mới.

8
miva2
git reset filename.txt  

Sẽ xóa một tệp có tên filename.txt khỏi chỉ mục hiện tại, khu vực "sắp được cam kết", mà không thay đổi bất cứ điều gì khác.

7
Joseph Mathew

Một trong những giải pháp trực quan nhất là sử dụng SourceTree .

Bạn chỉ có thể kéo và thả các tập tin từ dàn dựng và không được dàn dựng  enter image description here

7
Marcin Szymczak

Lệnh git reset giúp bạn sửa đổi khu vực tổ chức hoặc khu vực tổ chức và cây làm việc. Khả năng tạo thủ công của Git chính xác như bạn muốn có nghĩa là đôi khi bạn cần hoàn tác các thay đổi đối với các thay đổi bạn đã thực hiện với git add.

Bạn có thể làm điều đó bằng cách gọi git reset HEAD <file to change>. Bạn có hai lựa chọn để loại bỏ hoàn toàn các thay đổi. git checkout HEAD <file(s) or path(s)> là một cách nhanh chóng để hoàn tác các thay đổi đối với khu vực tổ chức và cây làm việc của bạn. Tuy nhiên, hãy cẩn thận với lệnh này vì nó loại bỏ tất cả các thay đổi đối với cây làm việc của bạn. Git không biết về những thay đổi đó vì chúng chưa bao giờ được cam kết. Không có cách nào để lấy lại những thay đổi đó khi bạn chạy lệnh này.

Một lệnh khác theo ý của bạn là git reset --hard. Nó cũng có sức tàn phá tương đương với cây làm việc của bạn - mọi thay đổi không được cam kết hoặc thay đổi theo giai đoạn sẽ bị mất sau khi chạy nó. Chạy git reset -hard HEAD thực hiện tương tự như git checkout HEAD. Nó chỉ không yêu cầu một tập tin hoặc đường dẫn để làm việc.

Bạn có thể sử dụng --soft với git reset. Nó đặt lại kho lưu trữ theo cam kết bạn chỉ định và thực hiện tất cả các thay đổi đó. Mọi thay đổi bạn đã dàn dựng đều không bị ảnh hưởng, cũng không phải là những thay đổi trong cây làm việc của bạn.

Cuối cùng, bạn có thể sử dụng --mixed để đặt lại cây làm việc mà không cần thay đổi bất kỳ thay đổi nào. Điều này cũng bỏ qua mọi thay đổi được dàn dựng.

1
SAIguru011