Pytanie Jak cofnąć "git add" przed zatwierdzeniem?


Przez pomyłkę dodałem pliki do git za pomocą polecenia:

git add myfile.txt

Jeszcze nie uciekłem git commit. Czy istnieje sposób, aby to cofnąć, więc te pliki nie zostaną uwzględnione w zatwierdzeniu?


Na razie jest 48 odpowiedzi (niektóre usunięte). Nie dodawaj nowego, chyba że masz jakieś nowe informacje.


7464
2017-12-07 21:57


pochodzenie


Począwszy od Git v1.8.4, wszystkie odpowiedzi poniżej tego wykorzystania HEAD lub head może teraz używać @ zamiast HEAD zamiast. Widzieć ta odpowiedź (ostatnia sekcja) dowiedzieć się, dlaczego możesz to zrobić.
Zrobiłem mały summery, który pokazuje wszystkie sposoby na otworzenie pliku: stackoverflow.com/questions/6919121/... - Daniel Alder
Dlaczego nie git checkout? - Erik Reppen
@ErikReppen git checkout nie usuwa etapowych zmian z indeksu commit. Przywraca tylko niezamknięte zmiany do ostatniej zatwierdzonej rewizji - co zresztą nie jest tym, czego ja chcę, chcę te zmiany, chcę je po prostu w późniejszym zatwierdzeniu. - paxos1977
Jeśli używasz Eclipse, jest to tak proste, jak odznaczenie plików w oknie dialogowym zatwierdzenia - Hamzahfrq


Odpowiedzi:


Możesz cofnąć git add przed zatwierdzeniem

git reset <file>

który usunie go z bieżącego indeksu (lista "do zatwierdzenia") bez zmiany czegokolwiek innego.

Możesz użyć

git reset

bez nazwy pliku, aby anulować wszystkie należne zmiany. Może się to przydać, gdy w rozsądnym czasie znajduje się zbyt wiele plików, które można wymienić.

W starszych wersjach Git powyższe polecenia są równoważne git reset HEAD <file> i git reset HEAD odpowiednio i nie powiedzie się, jeśli HEAD jest niezdefiniowana (ponieważ nie dokonałeś jeszcze żadnych zatwierdzeń w repozytorium) lub niejednoznaczna (ponieważ utworzyłeś gałąź o nazwie HEAD, co jest głupią rzeczą, której nie powinieneś robić). To został zmieniony w Git 1.8.2, jednak we współczesnych wersjach Gita możesz użyć powyższych komend nawet przed pierwszym zatwierdzeniem:

"git reset" (bez opcji lub parametrów), którego błąd może wystąpić, gdy      nie masz żadnych zobowiązań w historii, ale teraz daje ci to      pusty indeks (w celu dopasowania nieistniejącego zatwierdzenia, którego nie masz nawet na).


8379
2017-12-07 22:30



Oczywiście nie jest to prawdziwe cofnięcie, ponieważ jeśli coś jest nie tak git add nadpisać poprzednią, zainscenizowaną wersję nieprzyznaną, nie możemy jej odzyskać. Próbowałem to wyjaśnić w mojej odpowiedzi poniżej. - leonbloy
git reset HEAD *.ext gdzie ext to pliki danego rozszerzenia, które chcesz usunąć. Dla mnie to było *.bmp & *.zip - boulder_ruby
@ Jonny, zawiera indeks (aka obszar przemieszczania) wszystko pliki, a nie tylko zmienione pliki. "Rozpoczyna życie" (kiedy wypisujesz commit lub klonujesz repozytorium) jako kopię wszystkich plików w commitach wskazanych przez HEAD. Więc jeśli ty usunąć plik z indeksu (git rm --cached) oznacza to, że przygotowujesz się do popełnienia tego usuwa ten plik. git reset HEAD <filename> z drugiej strony skopiuje plik z HEAD do indeksu, aby następny commit nie wyświetlał żadnych zmian w tym pliku. - Wildcard
Właśnie odkryłem, że istnieje git reset -p tak jak git add -p. To jest niesamowite! - donquixote
Właściwie to może odzyskać nadpisane uprzednio zmiany etapowe, ale niezamówione ale nie w przyjazny dla użytkownika sposób, a nie w 100% bezpieczny (przynajmniej żaden nie znalazłem): goto .git / objects, wyszukiwanie plików utworzonych w czasie git add chcesz odzyskać (61/3AF3... -> identyfikator obiektu 613AF3...), następnie git cat-file -p <object-id> (Może warto byłoby odzyskać kilka godzin pracy, ale także lekcję, aby częściej angażować się ...) - Peter Schneider


Chcesz:

git rm --cached <added_file_to_undo>

Rozumowanie:

Kiedy byłem nowy, po raz pierwszy spróbowałem

git reset .

(aby cofnąć całe moje początkowe dodanie), tylko po to, aby uzyskać tę (nie tak) pomocną wiadomość:

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

Okazuje się, że dzieje się tak dlatego, że ref HEAD (branch?) Nie istnieje do czasu pierwszego zatwierdzenia. Oznacza to, że napotkasz problem tego samego początkującego co ja, jeśli twój przepływ pracy, taki jak mój, był podobny do:

  1. cd do mojego świetnego nowego katalogu projektu, aby wypróbować Git, nową gorliwość
  2. git init
  3. git add .
  4. git status

    ... dużo zwojów do crapów ...

    => Cholera, nie chciałem dodawać tego wszystkiego.

  5. google "cofnij git dodaj"

    => znajdź przepełnienie stosu - yay

  6. git reset .

    => fatal: Nie udało się rozwiązać "HEAD" jako poprawnego ref.

Okazuje się ponadto, że jest zgłoszony błąd wbrew temu nieprzydatności na liście mailingowej.

I że poprawne rozwiązanie znalazło się właśnie na wyjściu statusu Git (które, tak, przeszedłem jako "bzdura")

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

A rozwiązanie rzeczywiście jest do użycia git rm --cached FILE.

Uwaga ostrzeżenia w innym miejscu tutaj - git rm usuwa lokalną kopię roboczą pliku, ale nie Jeśli użyjesz --cached. Oto wynik git help rm:

--cached       Użyj tej opcji, aby zrestartować i usunąć ścieżki tylko z indeksu.       Pliki drzewa roboczego, zmodyfikowane lub nie, pozostaną.

I przejść do użycia

git rm --cached .

aby usunąć wszystko i zacząć od nowa. Nie działał jednak, ponieważ podczas gdy add . jest rekursywny, okazuje się rm wymagania -r powtarzać. Westchnienie.

git rm -r --cached .

W porządku, teraz wracam do miejsca, w którym zacząłem. Następnym razem będę używał -n zrobić suchy bieg i zobaczyć, co zostanie dodane:

git add -n .

Zapakowałem wszystko do bezpiecznego miejsca, zanim zaufałem git help rm o --cached nie niszcząc niczego (a co jeśli go pomyłkowo).


1954
2018-03-25 16:20



Hah. Postępowałem zgodnie z tym samym procesem. Tylko że się poddałem i powiedziałem rm -rf .git, git init ponieważ nie ufałem git rm --cached zachować kopię roboczą. Mówi trochę o tym, jak git jest nadal zbyt skomplikowany w niektórych miejscach. git unstage powinien być zwykłym standardowym poleceniem, nie obchodzi mnie, czy mogę dodać go jako alias. - Adrian Macneil
Dla mnie mówi git git reset HEAD <File>... - drahnr
git rm --cached <plik> jest właściwie poprawną odpowiedzią, jeśli jest to początkowy import pliku <file> do repozytorium. Jeśli próbujesz wprowadzić zmiany w pliku, reset git jest poprawną odpowiedzią. Ludzie, którzy twierdzą, że ta odpowiedź jest błędna, myślą o innym pytaniu. - Barry Kelly
To zadziała, ale tylko przy pierwszym zatwierdzeniu, gdy plik nie istniał wcześniej lub gdzie git add polecenie dodało nowe pliki, ale nie zmiany w istniejących plikach. - naught101
po prostu pokazuje, jak niezrozumiały i zawiły git. zamiast poleceń równoległych "cofnij", musisz dowiedzieć się, jak je cofnąć. Np. Próbując uwolnić nogę w szybkim piasku, a następnie zablokować rękę, a następnie zablokować drugą rękę ... każde polecenie powinno zostać wykonane poprzez GUI, z rozwijanymi menu dla opcji ... Pomyśl o całym interfejsie, wzrost wydajności, jaki mieliśmy, ale mamy ten bałagan w interfejsie retro linii poleceń. To nie jest tak, że programy GUI git sprawiają, że jest to bardziej intuicyjne. - ahnbizcad


Jeśli wpiszesz:

git status

git powie ci, co jest wystawiane, itp., w tym instrukcje, jak się przebiega poza scenę:

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

Uważam, że git nieźle namawia mnie do robienia tego, co należy, w takich sytuacjach.

Uwaga: Najnowsze wersje git (1.8.4.x) zmieniły ten komunikat:

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

484
2017-12-07 23:22



Wiadomość będzie się różnić w zależności od tego, czy addPlik ed był już śledzony (plik add tylko zapisał nową wersję do pamięci podręcznej - tutaj pokaże twoją wiadomość). Gdzie indziej, jeśli plik nie był wcześniej wystawiony, wyświetli się use "git rm --cached <file>..." to unstage - leonbloy
Wspaniały! The git reset HEAD <file> jeden jest jedynym, który zadziała, jeśli chcesz usunąć plik z procesu usuwania - skerit
Moja wersja 2.14.3 git mówi git reset HEAD do odprawy. - seaturtle


W celu wyjaśnienia: git add przenosi zmiany z bieżącego katalogu roboczego do pliku miejsce postoju (indeks).

Ten proces jest wywoływany inscenizacja. Więc najbardziej naturalne polecenie do etap zmiany (zmienione pliki) są oczywiste:

git stage

git add jest po prostu łatwiejsze do wpisania aliasu git stage

Szkoda, że ​​nie ma git unstage ani git unadd polecenia. Odpowiedni jest trudniejszy do odgadnięcia lub zapamiętania, ale jest dość oczywiste:

git reset HEAD --

Możemy łatwo stworzyć alias do tego:

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

I wreszcie mamy nowe polecenia:

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

Osobiście używam jeszcze krótszych aliasów:

git a #for staging
git u #for unstaging

220
2017-09-10 20:28



"porusza się"? To wskazywałoby, że zniknęło z katalogu roboczego. Nie o to chodzi. - Thomas Weller
Dlaczego jest to oczywiste? - Lenar Hoyt


Dodatek do zaakceptowanej odpowiedzi, jeśli Twój błędnie dodany plik był ogromny, prawdopodobnie zauważysz to, nawet po usunięciu go z indeksu za pomocą 'git reset", nadal wydaje się zajmować miejsce w .git informator. Nie ma się czym martwić, plik jest rzeczywiście nadal w repozytorium, ale tylko jako "luźny obiekt", nie zostanie skopiowany do innych repozytoriów (przez klon, push), a przestrzeń zostanie ostatecznie odzyskana - choć może niedługo. Jeśli jesteś niespokojny, możesz uruchomić:

git gc --prune=now

Aktualizacja (Poniżej znajduje się moja próba wyjaśnienia pewnych nieporozumień, które mogą wyniknąć z najbardziej przegłosowanych odpowiedzi):

Tak więc, co jest prawdziwe Cofnij z git add?

git reset HEAD <file> ?

lub

git rm --cached <file>?

Ściśle mówiąc, a jeśli się nie mylę: Żaden.

git add  nie może być cofnięty - bezpiecznie, ogólnie.

Przypomnijmy sobie najpierw co git add <file> faktycznie robi:

  1. Gdyby <file> był wcześniej nie śledzone, git add  dodaje go do pamięci podręcznej, z obecną zawartością.

  2. Gdyby <file> był już śledzone, git add  zapisuje bieżącą zawartość (migawka, wersja) do pamięci podręcznej. W GIT ta akcja jest nadal wywoływana Dodaj(nie tylko aktualizacja it), ponieważ dwie różne wersje (snapshoty) pliku są traktowane jako dwa różne elementy: dlatego faktycznie dodajemy nowy element do pamięci podręcznej, aby ostatecznie zostać zatwierdzony później.

W związku z tym pytanie jest nieco niejednoznaczne:

Pomyłkowo dodałem pliki, używając polecenia ...

Scenariusz OP wydaje się być pierwszym (niepotwierdzonym plikiem), chcemy "cofnąć", aby usunąć plik (nie tylko bieżącą zawartość) z śledzonych elementów. Gdyby tak jest, wtedy można uruchomić git rm --cached <file>.

I możemy też biec git reset HEAD <file>. Jest to na ogół lepsze, ponieważ działa w obu scenariuszach: wykonuje także operację cofania, gdy błędnie dodaliśmy wersję już śledzonego elementu.

Ale są dwie zastrzeżenia.

Po pierwsze: istnieje (jak wskazano w odpowiedzi) tylko jeden scenariusz, w którym git reset HEAD nie działa, ale git rm --cached robi: nowe repozytorium (bez zatwierdzania). Ale tak naprawdę to praktycznie nieistotna sprawa.

Po drugie: Bądź tego świadomy git reset HEAD  nie może magicznie odzyskać poprzednio buforowanej zawartości pliku, po prostu zsynchronizuje ją z HEAD. Jeśli nasz błąd git add zastąpić poprzednią, ustaloną, niezatwierdzoną wersję, nie możemy jej odzyskać. Dlatego, ściśle mówiąc, nie możemy tego cofnąć.

Przykład:

$ 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

Oczywiście nie jest to bardzo istotne, jeśli po prostu podążamy za zwykłym leniwym przepływem pracy polegającym na dodawaniu "git add" tylko w celu dodania nowych plików (przypadek 1), a my aktualizujemy nową zawartość za pomocą zatwierdzenia, git commit -a dowództwo.


137
2018-05-18 18:05



Ściśle mówiąc istnieje sposób na odzyskanie już zainscenizowanego pliku, który został zastąpiony przez dodanie git. Jak już wspomniano, git add tworzy obiekt git dla tego pliku, który stanie się luźnym obiektem nie tylko przy całkowitym usunięciu pliku, ale także przy nadpisywaniu go nową treścią. Ale nie ma polecenia, aby automatycznie je odzyskać. Zamiast tego plik musi zostać zidentyfikowany i wyodrębniony ręcznie lub za pomocą narzędzi napisanych tylko dla tego przypadku (zezwoli na to libgit2). Ale to się wypłaci, jeśli plik jest bardzo ważny i duży i nie można go odbudować poprzez edycję poprzedniej wersji. - Johannes Matokic
Aby poprawić siebie: Po znalezieniu luźnego pliku obiektu (użyj meta-danych, takich jak data / godzina utworzenia) git cat-file może zostać użyty do odzyskania treści. - Johannes Matokic
Inny sposób odzyskaj zmiany, które zostały zainscenizowane, ale nie zostały zatwierdzone, a następnie nadpisane przez np. inne git add jest via git fsck --unreachable który wyświetli listę wszystkich nieosiągalnych obiektów, które można następnie sprawdzić git show SHA-1_ID lub git fsck --lost-found to> Zapisuje wiszące obiekty w .git/lost-found/commit/ lub .git/lost-found/other/, w zależności od rodzaju. Zobacz też git fsck --help - iolsmit


git rm --cached . -r

będzie "usuwać" rekurencyjnie wszystko, co dodasz z bieżącego katalogu


85
2017-12-09 21:19



Nie chciałem odłączyć wszystkiego, tylko JEDEN konkretny plik. - paxos1977
Jest to również przydatne, jeśli nie masz żadnych wcześniejszych zatwierdzeń. W przypadku braku poprzedniego zatwierdzenia, git reset HEAD <file> powiedziałbym fatal: Failed to resolve 'HEAD' as a valid ref. - Priya Ranjan Singh
Nie to dodaje za usunięcie wszystkiego w bieżącym katalogu. Bardzo różni się po prostu od edycji zmian. - Mark Amery


Biegać

git gui

i usuń wszystkie pliki ręcznie lub wybierając je wszystkie i klikając przycisk unstage z commit przycisk.


77
2017-10-12 01:12



Tak rozumiem to. Chciałem tylko pośrednio zasugerować, że twój wskazuje, że w twojej odpowiedzi brzmi: "Możesz użyć git-gui.... ":) - Alexander Suraphel
Mówi "git-gui: command not found". Nie jestem pewien, czy to działa. - Parinda Rajapaksha


Git ma polecenia dla każdego działania, które można sobie wyobrazić, ale potrzebuje rozległej wiedzy, aby wszystko było w porządku, a co za tym idzie, jest w najlepszym razie sprzeczne z intuicją ...

Co wcześniej zrobiłeś:

  • Zmieniono plik i użyłem go git add ., lub git add <file>.

Czego chcesz:

  • Usuń plik z indeksu, ale zachowaj go wersjonowany i pozostawiony z niezatwierdzonymi zmianami w kopii roboczej:

    git reset head <file>
    
  • Zresetuj plik do ostatniego stanu HEAD, cofając zmiany i usuwając je z indeksu:

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

    Jest to konieczne, ponieważ git reset --hard HEAD nie będzie działać z pojedynczymi plikami.

  • Usunąć <file> z indeksu i wersji, zachowując nieskatalogowany plik ze zmianami w kopii roboczej:

    git rm --cached <file>
    
  • Usunąć <file> z kopii roboczej i wersji całkowicie:

    git rm <file>
    

73
2018-03-29 11:14



Nie mogę znieść różnicy "git reset head <plik>" i "git rm --cached <plik>. Czy możesz to wyjaśnić? - jeswang
Pliki @jeswang są albo "znane" git (śledzone są zmiany w nich), albo nie są "wersjonowane". reset head cofa twoje bieżące zmiany, ale plik jest nadal monitorowany przez git. rm --cached wyjmuje plik z wersji, więc git nie sprawdza go już pod kątem zmian (a także usuwa ostatecznie zindeksowane obecne zmiany, polecane przez poprzednika add), ale zmieniony plik będzie przechowywany w kopii roboczej, czyli w folderze plików na dysku twardym. - sjas
Różnica jest git reset HEAD <file> jest tymczasowy - polecenie zostanie zastosowane tylko do następnego zatwierdzenia, ale git rm --cached <file> będzie unstage, dopóki nie zostanie ponownie dodane z git add <file>. Również, git rm --cached <file> oznacza, że ​​jeśli przełączysz tę gałąź do zdalnego, każdy, kto ciągnie gałąź, otrzyma plik RZECZYWIŚCIE skasowany z folderu. - DrewT


Pytanie nie jest jasno postawione. Powód jest taki, że git add ma dwa znaczenia:

  1. dodawanie nowy plik do obszaru pomostowego, a następnie cofnij za pomocą git rm --cached file.
  2. dodawanie zmodyfikowany plik do obszaru pomostowego, a następnie cofnij za pomocą git reset HEAD file.

w razie wątpliwości użyj

git reset HEAD file

Ponieważ w obu przypadkach robi to, czego można się spodziewać.

Ostrzeżenie: Jeśli zrobisz git rm --cached file na pliku, który był zmodyfikowany (plik, który istniał wcześniej w repozytorium), wtedy plik zostanie usunięty git commit! Nadal będzie istnieć w twoim systemie plików, ale jeśli ktokolwiek inny wyciągnie twoje zatwierdzenie, plik zostanie usunięty z ich drzewa roboczego.

git status powie ci, czy plik był nowy plik lub zmodyfikowany:

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. Niezwykła liczba bardzo przestawionych odpowiedzi i komentarzy na tej stronie jest po prostu błędem w stosunku do zachowania git rm --cached somefile. Mam nadzieję, że ta odpowiedź przenosi się na stronę, która zajmuje czołowe miejsce, gdzie może chronić początkujących przed wprowadzaniem w błąd przez wszystkie fałszywe twierdzenia. - Mark Amery