Jak cofnąć scenę z dużej liczby plików bez usuwania zawartości

454

Przez przypadek dodałem wiele plików tymczasowych git add -A

Udało mi się wycofać pliki za pomocą poniższych poleceń i usunąć brudny indeks.

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

Powyższe polecenia są wymienione w git help rm. Ale niestety moje pliki zostały również usunięte podczas wykonywania, mimo że podałem opcję pamięci podręcznej. Jak mogę wyczyścić indeks bez utraty zawartości?

Byłoby również pomocne, gdyby ktoś mógł wyjaśnić sposób działania tej operacji potoku.

sarat
źródło
8
rm -fnie jest poleceniem git i nie ma --cachedopcji. Twoje lokalne pliki zostały usunięte przed wykonaniem, git rmwięc nie sądzę, abyś mógł git rmcokolwiek za to winić .
CB Bailey,
8
@sarat, zastanów się nad zmianą poprawnej odpowiedzi na wysoko ocenioną odpowiedź Iana Maddoxa , ponieważ niegit reset --hard jest to poprawna odpowiedź i faktycznie usunie treść. To wprowadzi użytkowników w błąd - tak jak ja to zrobiłem.
Marco Pashkov
2
@sarat, jak mówi Marco, kontynuuj. Ta strona generuje duży ruch.
Ross
@MarcoPashkov i Ross dzięki chłopaki. Gotowy.
sarat

Odpowiedzi:

986

git reset

Jeśli wszystko, czego chcesz, to cofnąć nadgorliwy bieg „git add”:

git reset

Twoje zmiany zostaną wycofane ze sceny i będą gotowe do ponownego dodania według uznania.


NIE URUCHAMIAJ git reset --hard.

Nie tylko cofnie inscenizację dodanych plików, ale cofnie wszelkie zmiany wprowadzone w katalogu roboczym. Jeśli utworzyłeś nowe pliki w katalogu roboczym, nie zostaną one jednak usunięte.

Ian Maddox
źródło
15
Jestem ci winien piwo Ian
DasBooten
1
I często muszę wykonać git checkout -- *, a także
Den-Jason
1
Zaoszczędziłeś dużo wysiłku. Dzięki człowieku
RajnikantDixit
35

Jeśli masz nieskazitelne repo (lub HEAD nie jest ustawiony) [1], możesz po prostu

rm .git/index

Oczywiście, będzie to wymagać, aby ponownie dodać pliki, które nie chcą być dodawane.


[1] Uwaga (jak wyjaśniono w komentarzach) zwykle dzieje się tak tylko wtedy, gdy repozytorium jest nowe („nieskazitelne”) lub jeśli nie dokonano żadnych zobowiązań. Z technicznego punktu widzenia, ilekroć nie ma kasy ani drzewa pracy.

Po prostu wyjaśnienie :)

sehe
źródło
Tak, to bardziej jak usunięcie samego utworzonego indeksu. Dobrze, że nie wymagam ponownej inicjalizacji git. Dzięki!
sarat
Czy na pewno jest to bezpieczna operacja? Właśnie to zrobiłem (faktycznie odsunąłem indeks na bok) i przygotowałem wszystkie inne pliki do usunięcia.
inger
@inger „Jeśli masz nieskazitelne repo”. Najwyraźniej tego nie miałeś.
patrz
Właściwie zastanawiałem się, co masz na myśli przez „dziewicze repo” (nie mam też szczęścia w Google). Więc miałeś na myśli puste repo?
inger
1
@inger Zgadzam się. Musiałem założyć, że OP miał dokładnie taką sytuację - nie precyzuje jej, ale jego opis pozostawia taką możliwość. Tak czy inaczej, ja tylko wymiany informacji i nie mogą wpływać na głosowanie :( dodałem słowo ostrzeżenia do tekstu odpowiedzi, w przypadku, gdy pomaga innym w przyszłości..
sehe
15

Służy git reset HEADdo resetowania indeksu bez usuwania plików. (Jeśli chcesz zresetować tylko określony plik w indeksie, możesz git reset HEAD -- /path/to/fileto zrobić.)

Operator potoku w powłoce przejmuje stdoutproces z lewej strony i przekazuje go stdindo procesu z prawej. Jest to w zasadzie odpowiednik:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

ale zamiast tego $ proc1 | proc2drugi proces może zacząć pobierać dane, zanim pierwszy zakończy ich wysyłanie, i nie jest w to zaangażowany żaden plik.

Bursztyn
źródło
ale jak używać go z wieloma plikami. Nigdy wcześniej nie zatwierdzałem tych plików.
sarat
3
Wystarczy wpisać git reset HEADbez określania niczego innego, a to zresetuje cały indeks. Następnie możesz ponownie dodać tylko wybrane pliki.
Amber
Wystąpił następujący błąd. Nigdy wcześniej nie popełniłem tych przedmiotów. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
sarat
1
Spróbuj właśnie git resetwtedy, bez HEAD.
Amber
Próbowałem już, że skończyło się na następującym błędzie. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
sarat
9
git stash && git stash pop
Bijan
źródło
2
Zrobiłbym „git stash && git stash pop”, aby skrytka również została usunięta. „zastosuj” spowoduje pozostawienie skrytki na liście skrytek.
chitti
8

Jeśli HEAD nie jest ustawiony (tzn. Nie masz jeszcze żadnych zatwierdzeń, ale nie chcesz po prostu wysadzić w powietrze, .gitponieważ masz już skonfigurowaną inną konfigurację repozytorium, którą chcesz zachować), możesz również zrobić

git rm -rf --cached .

wszystko zepsuć. Jest to efektywnie to samo, co rozwiązanie sehe, ale pozwala uniknąć zlewania się z wewnętrznymi elementami Git.

jjlin
źródło
w rzeczywistości mówi Gitowi, aby usunął wszystko z obszaru buforowanego.
Visionary Software Solutions
1
Pamięć podręczna jest również znana jako obszar przejściowy, więc nie jestem pewien, do czego zmierzasz.
jjlin
Sehe, rm .git / index jest bardzo niebezpieczny - przeczytaj UWAGA, którą on ma na temat zupełnie nowego repo! Jest to znacznie bezpieczniejsze dla pozostałych 99,999% czasu. Nie przeczytałem uważnie i musiałem zdmuchnąć moją kopię roboczą i ponownie sklonować po wykonaniu rm .git / index na mojej kopii roboczej.
phpguru
NIE używaj tego polecenia! Zmieni WSZYSTKIE projekty do stanu bez śledzenia (w tym tych, które nie były inscenizowane). To nie jest rozwiązanie pierwotnego pytania. Prawidłowe rozwiązanie za pomocą polecenia „git rm” polega na TYLKO określeniu plików, które mają być niestabilne: git rm -rf --cached <pliki, które chcesz rozpakować>.
Monte Creasor,
Powinieneś używać tego polecenia tylko wtedy, gdy masz nowe repozytorium bez zatwierdzeń (to znaczy „HEAD nie jest ustawiony”), ale nie chcesz po prostu wysadzić, .gitponieważ skonfigurowałeś inną konfigurację repo chce zatrzymać. Zredagowałem to, aby to wyjaśnić.
jjlin
5

Ostrzeżenie: nie używaj następującego polecenia, chyba że chcesz stracić nieprzyznaną pracę!

Używanie git resetzostało wyjaśnione, ale poprosiłeś o wyjaśnienie potokowych poleceń, więc oto:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

Polecenie git ls-fileswyświetla listę wszystkich plików, o których git wie. Opcja -znakłada na nie określony format, oczekiwany format xargs -0, który następnie się rm -fna nich wywołuje , co oznacza usunięcie ich bez sprawdzania Twojej zgody.

Innymi słowy, „wyświetl listę wszystkich plików, o których git wie i usuń lokalną kopię”.

Następnie przechodzimy do git diff, który pokazuje zmiany między różnymi wersjami przedmiotów, o których wie git. Mogą to być zmiany między różnymi drzewami, różnice między kopiami lokalnymi a zdalnymi i tak dalej.
W użytym tutaj znaczeniu pokazuje nieustawione zmiany; pliki, które zmieniłeś, ale jeszcze nie zatwierdziłeś. Ta opcja --name-onlyoznacza, że ​​chcesz tylko (pełne) nazwy plików i --diff-filter=Dże interesują Cię tylko usunięte pliki. (Hej, czy nie usunęliśmy po prostu kilku rzeczy?) To jest następnie przesyłane strumieniowo do tego, xargs -0co widzieliśmy wcześniej, co git rm --cachedje wywołuje , co oznacza, że ​​są usuwane z pamięci podręcznej, podczas gdy działające drzewo powinno zostać pozostawione w spokoju - poza tym, że właśnie usunąłeś wszystkie pliki z działającego drzewa. Teraz są również usuwane z Twojego indeksu.

Innymi słowy, wszystkie zmiany, etapowe lub niestacjonarne, zniknęły, a twoje drzewo robocze jest puste. Wypłacz się, sprawdź swoje pliki od początku lub ze źródła, i ponownie wykonaj swoją pracę. Przeklnij sadystę, który napisał te piekielne linie; Nie mam pojęcia, dlaczego ktoś chciałby to zrobić.


TL; DR: po prostu wszystko nosiłeś; zacznij od nowa i używaj git resetod teraz.

SQB
źródło
2

Obawiam się, że pierwsza z tych linii poleceń bezwarunkowo usunęła z kopii roboczej wszystkie pliki znajdujące się w obszarze testowym gita. Drugi usunął ze sceny wszystkie pliki, które były śledzone, ale zostały teraz usunięte. Niestety oznacza to, że utracisz wszelkie niezatwierdzone modyfikacje tych plików.

Jeśli chcesz odzyskać kopię roboczą i indeksować z powrotem do poprzedniego zatwierdzenia , możesz ( ostrożnie ) użyć następującego polecenia:

git reset --hard

Mówię „ostrożnie”, ponieważ git reset --hard spowoduje to usunięcie niezatwierdzonych zmian w kopii roboczej i indeksie. Jednak w tej sytuacji brzmi to tak, jakbyś chciał po prostu wrócić do stanu przy ostatnim zatwierdzeniu, a nieprzyjęte zmiany i tak zostały utracone.

Aktualizacja: z twoich komentarzy do odpowiedzi Amber brzmi, że nie stworzyłeś jeszcze żadnych zatwierdzeń (ponieważ HEAD nie można rozwiązać), więc obawiam się, że to nie pomoże.

Jeśli chodzi o działanie tych potoków: git ls-files -zi git diff --name-only --diff-filter=D -zoba generują listę nazw plików oddzielonych bajtem 0. (Jest to przydatne, ponieważ w odróżnieniu od znaków nowej linii 0bajty nie mogą występować w nazwach plików w systemach uniksowych). Program xargszasadniczo buduje wiersze poleceń ze standardowego wejścia, domyślnie pobierając wiersze ze standardowego wejścia i dodając je na końcu z wiersza poleceń. Ta -0opcja mówi, że należy oczekiwać standardowego wejścia oddzielonego przez0 bajtami. xargsmoże kilkakrotnie wywołać polecenie, aby zużyć wszystkie parametry ze standardowego wejścia, upewniając się, że linia poleceń nigdy nie będzie zbyt długa.

Jako prosty przykład, jeśli masz plik o nazwie test.txt, z następującą zawartością:

hello
goodbye
hello again

... wtedy polecenie xargs echo whatever < test.txtwywoła polecenie:

echo whatever hello goodbye hello again
Mark Longair
źródło
Nigdy nie dokonywałem żadnych zatwierdzeń, więc powiesz, że nie mogę rozwiązać HEAD. Co robimy w takich sytuacjach. Wielkie dzięki za szczegółowe wyjaśnienie fajki.
sarat
8
Jeśli właśnie zmieniłeś git ignore i zrobiłeś git add --all, aby dołączyć wiele plików, NIE uruchamiaj git reset --hard, aby je wycofać. ZOSTANĄ USUNIĘTE !!
Ciesz się
5
Uwaaahh !! Może musisz podkreślić słowo „ostrożnie” . Właśnie widziałem te trzy słowa „git reset --hard” i wszystkie moje nieustawione pliki są… fufff !! odszedł!!!!!
Vineeth Chitteti,
1

Jeśli chcesz wycofać wszystkie zmiany, użyj polecenia poniżej,

git reset --soft HEAD

W przypadku, gdy chcesz wycofać zmiany i przywrócić je z katalogu roboczego,

git reset --hard HEAD
027
źródło