Como desfazer um grande número de arquivos sem excluir o conteúdo

454

Adicionei acidentalmente muitos arquivos temporários usando git add -A

Consegui desestabilizar os arquivos usando os seguintes comandos e consegui remover o índice sujo.

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

Os comandos acima estão listados no git help rm. Mas, infelizmente, meus arquivos também foram excluídos na execução, apesar de eu ter dado a opção de cache. Como posso limpar o índice sem perder o conteúdo?

Também seria útil se alguém pudesse explicar como essa operação de tubo funciona.

sarat
fonte
8
rm -fnão é um comando git e não tem uma --cachedopção. Seus arquivos locais foram excluídos antes da execução, git rmportanto, acho que você não pode legitimamente culpar git rmnada.
CB Bailey
8
@sarat, considere alterar a resposta correta para a resposta altamente votada de Ian Maddox , pois essa nãogit reset --hard é a resposta correta e, de fato, excluirá o conteúdo. Isso vai confundir os usuários - como eu.
Marco Pashkov 24/03
2
@sarat como Marco diz, continue. Esta página recebe muito tráfego.
Ross
@MarcoPashkov & Ross obrigado pessoal. Feito.
30515 sarat

Respostas:

986

git reset

Se tudo o que você deseja é desfazer uma execução "git add" excessivamente zelosa:

git reset

Suas alterações ficarão sem estágio e prontas para você adicionar novamente como desejar.


NÃO FUNCIONE git reset --hard.

Ele não apenas desestabiliza os arquivos adicionados, mas também reverte todas as alterações feitas no diretório de trabalho. Se você criou novos arquivos no diretório de trabalho, ele não os excluirá.

Ian Maddox
fonte
15
Devo-lhe um litro Ian
DasBooten
1
Costumo achar que tenho que me apresentar git checkout -- *também
Den-Jason
1
Você economizou muito esforço. Obrigado, homem
RajnikantDixit
35

Se você tem um repo intocado (ou HEAD não está definido) [1], você pode simplesmente

rm .git/index

Claro, isso vai exigir que você adicionar novamente os arquivos que você tinha quer ser adicionado.


[1] Observe (como explicado nos comentários) isso geralmente aconteceria apenas quando o repositório fosse novo em folha ("intocado") ou se nenhum comprometimento tivesse sido feito. Mais tecnicamente, sempre que não houver checkout ou árvore de trabalho.

Apenas deixando mais claro :)

ver
fonte
Sim, é mais como excluir o próprio índice criado. O bom é que não preciso reinicializar o git. Obrigado!
22411 sarat
Tem certeza de que é uma operação segura? Acabei de fazer isso (na verdade, movi o índice para fora do caminho) e obtive todos os outros arquivos preparados para exclusão.
Inker #
@inger "Se você tem um repo intocado". Você claramente não tinha isso.
sehe
Na verdade, eu queria saber o que você quis dizer com "repo intocado" (também não me sinto sortudo com o google) .. Então você quis dizer um repo vazio na verdade?
Inker #
1
@inger Concordo. Eu tive que assumir que o OP tinha essa situação exata - ele não a especifica, mas sua descrição deixa a possibilidade. De qualquer forma, estou apenas a partilha de informação, e não pode influenciar a votação :( adicionou uma palavra de advertência para o texto da resposta, no caso de ele ajuda os outros no futuro..
sehe
15

Use git reset HEADpara redefinir o índice sem remover arquivos. (Se você deseja redefinir apenas um arquivo específico no índice, pode git reset HEAD -- /path/to/filefazê-lo.)

O operador do tubo, em uma concha, pega o stdoutprocesso à esquerda e passa stdino processo à direita. É essencialmente o equivalente a:

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

mas, em vez disso $ proc1 | proc2, o segundo processo pode começar a obter dados antes que o primeiro seja finalizado, e não há nenhum arquivo real envolvido.

Âmbar
fonte
mas como usá-lo com vários arquivos. Nunca enviei esses arquivos antes.
18711 sarat
3
Basta digitar git reset HEADsem especificar mais nada e ele redefinirá todo o índice. Você pode apenas adicionar novamente apenas os arquivos que deseja.
22611 Amber
Eu recebi o seguinte erro. Eu nunca cometi esses itens antes. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
18711 sarat
1
Tente apenas git resetentão, sem o HEAD.
1827 Amber
Eu já tentei que acabei no seguinte erro. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
18711 sarat
9
git stash && git stash pop
Bijan
fonte
2
Eu faria 'git stash && git stash pop' para que o stash também fosse excluído. 'aplicar' deixaria o esconderijo na lista de esconderijo.
Chitti
8

Se HEAD não estiver definido (ou seja, você ainda não tem confirmações, mas não quer se surpreender .gitporque já definiu outra configuração de repo que deseja manter), você também pode

git rm -rf --cached .

desestabilizar tudo. Isso é efetivamente o mesmo que a solução da sehe, mas evita mexer com os internos do Git.

jjlin
fonte
na verdade, isso diz ao Git para excluir tudo na área em cache.
Visionary Software Solutions
1
O cache também é conhecido como área de preparação, portanto, não tenho certeza do que você está recebendo.
Jjlin 01/07
No sehe, rm .git / index é muito perigoso - leia a NOTA que ele tem sobre um novo repositório! Isso é muito mais seguro para os outros 99,999% do tempo. Não li com cuidado e tive que remover minha cópia de trabalho e clonar novamente depois de executar rm .git / index na minha cópia de trabalho.
Phpuruuru
NÃO use este comando! Ele mudará TODO o projeto para o estado não rastreado (incluindo aqueles que não foram testados). Esta não é uma solução para a pergunta original. A solução correta usando o comando 'git rm' é especificar SOMENTE os arquivos que você deseja desestagiar: git rm -rf --cached <arquivos que você deseja desestabilizar>.
Monte Creasor 20/01
Você só deve usar esse comando quando tiver um novo repositório sem confirmação ainda (isto é o que "HEAD não está definido" significa), mas você não quer se surpreender .gitporque definiu outra configuração de repositório quer manter. Eu editei para esclarecer isso.
jjlin 18/04
5

Aviso: não use o seguinte comando, a menos que queira perder trabalho não confirmado!

O uso git resetfoi explicado, mas você também pediu uma explicação dos comandos canalizados, então aqui vai:

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

O comando git ls-fileslista todos os arquivos que o git conhece. A opção -zimpõe um formato específico a eles, o formato esperado por xargs -0, que depois os chama rm -f, o que significa removê-los sem verificar sua aprovação.

Em outras palavras, "liste todos os arquivos que o git conhece e remova sua cópia local".

Em seguida, chegamos a git diff, que mostra as alterações entre as diferentes versões dos itens que o git conhece. Essas podem ser alterações entre diferentes árvores, diferenças entre cópias locais e cópias remotas, etc.
Conforme usado aqui, ele mostra as alterações não-estágios; os arquivos que você alterou, mas ainda não confirmou. A opção --name-onlysignifica que você deseja apenas os nomes dos arquivos (completos) e --diff-filter=Dsignifica que está interessado apenas nos arquivos excluídos. (Ei, não acabamos de excluir várias coisas?) Isso é canalizado para o xargs -0que vimos antes, o que os invoca git rm --cached, o que significa que eles são removidos do cache, enquanto a árvore de trabalho deve ser deixada em paz - exceto que você acabou de remover todos os arquivos da sua árvore de trabalho. Agora eles também são removidos do seu índice.

Em outras palavras, todas as alterações, preparadas ou não, desapareceram e sua árvore de trabalho está vazia. Grite, faça o check-out de seus arquivos originais ou remotos e refaça seu trabalho. Amaldiçoe o sádico que escreveu essas linhas infernais; Não tenho a menor idéia de por que alguém iria querer fazer isso.


TL; DR: você acabou de lavar tudo; começar de novo e usar a git resetpartir de agora.

SQB
fonte
2

Receio que a primeira dessas linhas de comando exclua incondicionalmente da cópia de trabalho todos os arquivos que estão na área de preparação do git. O segundo desempenhou todos os arquivos rastreados, mas que foram excluídos. Infelizmente, isso significa que você terá perdido quaisquer modificações não confirmadas nesses arquivos.

Se você deseja obter sua cópia de trabalho e indexar como estavam na última confirmação , você pode (com cuidado ) usar o seguinte comando:

git reset --hard

Digo "com cuidado", pois git reset --hard eliminará alterações não confirmadas na sua cópia de trabalho e índice. No entanto, nessa situação, parece que você deseja apenas retornar ao estado no seu último commit, e as alterações não confirmadas foram perdidas de qualquer maneira.

Atualização: parece que, pelos seus comentários sobre a resposta de Amber, você ainda não criou nenhum commit (já que HEAD não pode ser resolvido), então isso não vai ajudar, receio.

Quanto à forma como esses canais funcionam: git ls-files -ze git diff --name-only --diff-filter=D -zambos exibem uma lista de nomes de arquivos separados pelo byte 0. (Isso é útil, pois, diferentemente das novas linhas, 0é garantido que os bytes não ocorram nos nomes dos arquivos nos sistemas semelhantes ao Unix.) O programa xargsbasicamente constrói linhas de comando a partir de sua entrada padrão, por padrão, obtendo linhas da entrada padrão e adicionando-as ao final da linha de comando. A -0opção diz esperar que a entrada padrão seja separada por 0bytes. xargspode chamar o comando várias vezes para usar todos os parâmetros da entrada padrão, certificando-se de que a linha de comando nunca fique muito longa.

Como um exemplo simples, se você tiver um arquivo chamado test.txt, com o seguinte conteúdo:

hello
goodbye
hello again

... então o comando xargs echo whatever < test.txtchamará o comando:

echo whatever hello goodbye hello again
Mark Longair
fonte
Eu nunca fiz nenhum commit, então ele diz que não pode resolver o HEAD. O que fazemos em tais situações. Muito obrigado por explicar o tubo em detalhes.
18711 sarat
8
Se você acabou de alterar o git ignore e o git add --all para incluir muitos arquivos, NÃO execute o git reset --hard para desestabilizá-los. ELES SERÃO EXCLUÍDOS !!
Ajoy
5
Uwaaahh !! Talvez você precise destacar a palavra "cuidadosamente" . Eu acabei de ver essas três palavras "git reset --hard" e todos os meus arquivos em etapas são ... fufff !! foi!!!!!
Vineeth Chitteti
1

Se você deseja desfazer todas as alterações, use o comando abaixo,

git reset --soft HEAD

No caso de você desejar desestabilizar as alterações e revertê-las do diretório de trabalho,

git reset --hard HEAD
027
fonte