Remover arquivos do commit do Git

1613

Estou usando o Git e comprometi alguns arquivos usando

git commit -a

Mais tarde, descobri que um arquivo foi adicionado por engano ao commit.

Como posso remover um arquivo da última confirmação?

Lolly
fonte
2
Este link é perfeito para sua pergunta: stackoverflow.com/questions/307828/…
b3h3m0th
@CharlesB: sim, esta é a minha última confirmação
Lolly
8
você enviou o commit para o servidor?
Paritosh Singh
4
Eu apenas faço isso usando:git reset filepath
felipekm 6/06/16

Respostas:

3090

Eu acho que outras respostas aqui estão erradas, porque essa é uma questão de mover os arquivos confirmados por engano de volta para a área de preparação do commit anterior, sem cancelar as alterações feitas neles. Isso pode ser feito como sugerido por Paritosh Singh:

git reset --soft HEAD^ 

ou

git reset --soft HEAD~1

Redefina os arquivos indesejados para excluí-los da confirmação:

git reset HEAD path/to/unwanted_file

Agora confirme novamente, você pode até reutilizar a mesma mensagem de confirmação:

git commit -c ORIG_HEAD  
juzzlin
fonte
86
Obrigado por isso. Vale a pena acrescentar que, se você já enviou seu commit (errado) anterior e agora tenta git pushconsertar seu repo, ele irá reclamar Updates were rejected because the tip of your current branch is behind its remote counterpart.. Se você tem certeza de que deseja empurrá-los (por exemplo, é o seu garfo), pode usar a -fopção para forçar o empurrão, por exemplo git push origin master -f. (Não faça isto a um repo montante que os outros estão buscando de)
andy Magoon
57
git reset --soft HEAD^é a minha mais comum de desfazer a operação
funroll
2
@ PabloFernandez, em primeiro lugar, a resposta aceita poderia ter sido o que o OP estava procurando (além disso, foi publicado meses antes). Em segundo lugar, as respostas aceitas estão sempre no topo, independentemente do número de votos positivos.
MITjanitor
4
@PabloFernandez, na parte superior de todas as respostas, possui três guias que permitem controlar a ordem das respostas: ativa , mais antiga e votos . Meu palpite é que o seu está definido como o mais antigo . Alterne para votos mesmo que a resposta aceita ainda esteja no topo, essa resposta será a segunda.
ahsteele
15
Eu sabia disso, git resetmas queria uma maneira de afetar o commit existente "no local". Eu acabei de aprender git commit -C. Então, para mim, o que eu quero é sua receita exata com mais uma etapa, o "novo commit novamente" explicitado como git commit -C [hash of original HEAD commit from first step].
precisa saber é o seguinte
323

ATENÇÃO ! Se você deseja apenas remover um arquivo do commit anterior e mantê-lo em disco , leia a resposta do juzzlin logo acima.

Se este é seu último commit e você deseja excluir completamente o arquivo do repositório local e remoto , você pode:

  1. remova o arquivo git rm <file>
  2. confirmar com alterar bandeira: git commit --amend

O sinalizador de alteração diz ao git para confirmar novamente, mas "mescla" (não no sentido de mesclar duas ramificações) esse commit com o último commit.

Conforme declarado nos comentários, usar git rmaqui é como usar o rmpróprio comando!

CharlesB
fonte
120
você também pode usar git rm --cachedpara manter os arquivos no disco
Arkadiy Kukarkin
14
Aviso para aqueles que navegam nesta resposta: verifique se você deseja EXCLUIR o arquivo (como se foi!), Não apenas remova-o da lista Confirmar.
21815 Scott Junta
8
Para acrescentar ao que os outros dizem (e torná-lo mais fácil de lembrar para não fazer isso a menos que você realmente quer): A rmno gitcomando está fazendo o que rmem si faz!
yo
@CharlesB Você pode adicionar a nota do comentário de Arkadiy Kukarkin à sua resposta para dar mais visibilidade?
precisa saber é o seguinte
2
Observe que os arquivos ainda podem ser restaurados, caso você tenha mudado de idéia, o commit anterior git commit --amendainda está lá e pode ser encontrado, por exemplo, com git reflog. Portanto, não é tão ruim quanto os outros comentários sugerem.
Steohan
165

As respostas existentes estão falando sobre remover os arquivos indesejados da última confirmação.

Se você deseja remover arquivos indesejados de uma confirmação antiga (mesmo enviada por push) e não deseja criar uma nova confirmação, o que é desnecessário, devido à ação:

1

Encontre a confirmação com a qual você deseja que o arquivo esteja em conformidade.

git checkout <commit_id> <path_to_file>

você pode fazer isso várias vezes se quiser remover muitos arquivos.

2)

git commit -am "remove unwanted files"

3)

Encontre o commit_id do commit no qual os arquivos foram adicionados por engano , digamos "35c23c2" aqui

git rebase 35c23c2~1 -i  // notice: "~1" is necessary

Este comando abre o editor de acordo com as suas configurações. O padrão é vim.

Mova o último commit, que deve ser "remover arquivos indesejados", para a próxima linha do commit incorreto ("35c23c2" no nosso caso) e defina o comando como fixup:

pick 35c23c2 the first commit
fixup 0d78b28 remove unwanted files

Você deve ser bom depois de salvar o arquivo.

Terminar :

git push -f

Se, infelizmente, você tiver conflitos, precisará resolvê-los manualmente.

Brian
fonte
2
Fazer isso com o nano é fabuloso! Ctrl + K, Ctrl + U, coloque um 'f', Ctrl + X, coloque 'y' e pronto!
sequielo 4/16
6
Se você realmente deseja remover os arquivos do repositório (não o sistema de arquivos), em vez de apenas revertê-los para uma versão anterior, em vez da etapa 1, faça git rm --cached <file(s)>.
waldyrious
2
Espere, você pode simplesmente mover confirmações pelo arquivo de rebase interativa à vontade?
Dan Rosenstark
2
Você pode totalmente, mas pode (ou não) ter conflitos.
28717 Brian
6
Esse processo pode ser facilitado adicionando --fixup=35c23c2ao git commitcomando Isso configurará a confirmação automaticamente como uma correção da confirmação necessária e, portanto, você não precisará especificá-lo na nova base. Além disso, se você adicionar --autosquashao git rebasecomando, o git moverá automaticamente o seu commit para o local correto, para que você não precise fazer nada no rebase interativo - salve o resultado (o que significa que você nem precisa -isinalizar, embora eu goste de usá-lo de qualquer maneira para garantir que tudo esteja como eu esperava).
Guss
144

Como a resposta aceita indica, você pode fazer isso redefinindo todo o commit. Mas essa é uma abordagem bastante pesada.
Uma maneira mais limpa de fazer isso seria manter a confirmação e simplesmente remover os arquivos alterados.

git reset HEAD^ -- path/to/file
git commit --amend --no-edit

Ele git resetpegará o arquivo como estava na confirmação anterior e o preparará no índice. O arquivo no diretório de trabalho é intocado.
O git commitirá confirmar e compactar o índice no commit atual.

Essencialmente, pega a versão do arquivo que estava na confirmação anterior e a adiciona à confirmação atual. Isso resulta em nenhuma alteração líquida e, portanto, o arquivo é efetivamente removido da confirmação.

Patrick
fonte
5
Essa é uma resposta muito melhor para remover apenas um único arquivo, sem revisar todo o commit.
Nimish 30/05
Este é exatamente o mesmo que esta resposta: D stackoverflow.com/a/27340569/1623984
ThatsAMorais
@ThatsAMorais de fato :-). Gostaria de saber se esta questão foi mesclada com outra, e é por isso que eu não a vi. Ou talvez eu esteja apenas cego. Em ambos os casos, acho que estou inclinado a deixá-lo, pois com base nos votos, parece ser mais popular (talvez as pessoas prefiram a resposta curta e direta).
Patrick
Por todos os meios, deixe-o! :) Tivemos claramente a ideia certa e o objetivo é ajudar. Eu acho que mesclar é uma boa teoria.
ThatsAMorais
Como você faz isso se já enviou para um ramo no github? Tentei fazer o push depois de fazer essa correção e recebi a mensagem "As atualizações foram rejeitadas porque a dica de sua ramificação atual está por trás da dica: sua contraparte remota".
Ollie Williams
41

Se você não enviou as alterações no servidor, pode usar

git reset --soft HEAD~1

Ele redefinirá todas as alterações e reverterá para uma confirmação

Se você enviou suas alterações, siga as etapas conforme respondidas por @CharlesB

Paritosh Singh
fonte
2
-1 git remover a reinicialização mudanças aconteceram arquivo de área de preparo, aqui a mudança tenha sido cometido
charlesb
OK, mas vou manter o meu downvote uma vez que não é o que o OP quer :) desculpe
charlesb
ok, está bem para mim, mas por que o oponente não quer isso? Qual é o problema?
Paritosh Singh
não é grande coisa, mas porque o OP deseja remover o arquivo indesejado da última confirmação e apenas redefine o estado antes de confirmar. você ainda precisa refazer o commit.
22712 CharlesB
3
@Aris usar <git diff --cached> para ver as alterações
Paritosh Singh
37

Remover o arquivo usando rm o excluirá!

Você está sempre adicionando a uma confirmação no git, em vez de removê-la, portanto, nesse caso, retorne o arquivo ao estado em que estava antes da primeira confirmação (pode ser uma ação de exclusão 'rm' se o arquivo for novo) e, em seguida, re-confirmar e o arquivo irá.

Para retornar o arquivo para algum estado anterior:

    git checkout <commit_id> <path_to_file>

ou para devolvê-lo ao estado no HEAD remoto:

    git checkout origin/master <path_to_file>

em seguida, corrija o commit e você deverá encontrar o arquivo desaparecido da lista (e não excluído do seu disco!)

Bob Flannigon
fonte
36
git checkout HEAD~ path/to/file
git commit --amend
Denis Shchepetov
fonte
1
Essa é a melhor maneira de modificar o último commit, aquele que não foi enviado por push. Isso redefinirá as alterações em um arquivo, removendo efetivamente o arquivo da última confirmação.
Alex Bravo
Isso também mudou o arquivo. Como preservar as alterações locais no arquivo?
theonlygusti
29

O seguinte mostrará o estágio do arquivo pretendido, que é o que o OP pediu.

git reset HEAD^ /path/to/file

Você verá algo como o seguinte ...

Alterações a serem confirmadas: (use "git reset HEAD ..." para unstage)

modificado: / caminho / para / arquivo

Alterações não preparadas para confirmação: (use "git add ..." para atualizar o que será confirmado) (use "git checkout - ..." para descartar as alterações no diretório de trabalho)

modificado: / caminho / para / arquivo

  • "Alterações a serem confirmadas" é a versão anterior do arquivo antes da confirmação. Isso parecerá uma exclusão se o arquivo nunca existir. Se você confirmar essa alteração, haverá uma revisão que reverte a alteração no arquivo em sua ramificação.
  • "Alterações não preparadas para confirmação" é a alteração que você confirmou e o estado atual do arquivo

Nesse ponto, você pode fazer o que quiser no arquivo, como redefinir para uma versão diferente.

Quando você estiver pronto para confirmar:

git commit --amend -a

ou (se você tiver outras alterações que ainda não deseja confirmar)

git commit add /path/to/file
git commit --amend
ThatsAMorais
fonte
3
A resposta de juzzlin é ótima, mas é excessivo desestabilizar todo o commit quando você deseja desestabilizar apenas um. A desagregação de toda a consolidação pode causar problemas se você tiver alterações atualmente desagregadas nos arquivos nessa consolidação que não deseja perder.
ThatsAMorais
27

Vou explicar para você com exemplo.
Sejam A, B, C três confirmações sucessivas. A confirmação B contém um arquivo que não deveria ter sido confirmado.

git log  # take A commit_id
git rebase -i "A_commit_ID" # do an interactive rebase
change commit to 'e' in rebase vim # means commit will be edited
git rm unwanted_file
git rebase --continue
git push --force-with-lease <branchName>    
Moaz Rashad
fonte
Se o arquivo específico não estiver na confirmação anterior ou anterior, esta é a maneira mais elegante. Eu diria até que é a maneira mais elegante em geral. Eu gosto de rebasing interativo.
precisa saber é o seguinte
Para um único commit, mude nooppara edit [A_commit_ID]oue [A_commit_ID]
TamusJRoyce 19/02
23

Você pode simplesmente tentar.

git reset --soft HEAD~1

e crie um novo commit.

No entanto, existe um incrível software "gitkraken". o que facilita o trabalho com o git.

HamzaMushtaq
fonte
1
E apenas para observar: depois disso, você faria git commit --amendpara que a remoção do arquivo fosse atualizada no seu último commit; e depois, você pode verificar se ele foi realmente removido comgit log -1 --stat
sdbbs 13/11/19
13
git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "removed unwanted file from git"

deixará o arquivo local ainda. Se você também não deseja o arquivo localmente, pode pular a opção --cached.

Se todo o trabalho estiver em sua filial local, você precisará manter o arquivo em uma consolidação posterior e, como um histórico limpo, acho que uma maneira mais simples de fazer isso:

git rm --cached <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit --squash <commit_id>
git add <file_to_remove_from_commit_<commit_id>_which_added_file>
git commit -m "brand new file!"
git rebase --interactive <commit_id>^

e, em seguida, você pode concluir o rebase com facilidade, sem precisar se lembrar de comandos mais complexos ou confirmar a mensagem ou digitar o mesmo.

Bryan Buckley
fonte
Isso funciona para mim. Suponho que se você deseja adicionar os arquivos novamente à mistura, use git add -A ou git add. e eles estão de volta.
Alexander Mills
11

O uso da GUI do git pode simplificar a remoção de um arquivo da confirmação anterior.

Supondo que este não seja um ramo compartilhado e você não se importe em reescrever o histórico , execute:

git gui citool --amend

Você pode desmarcar o arquivo que foi confirmado por engano e clicar em "Confirmar".

insira a descrição da imagem aqui

O arquivo é removido da confirmação, mas será mantido no disco . Portanto, se você desmarcou o arquivo após adicioná-lo por engano, ele será exibido na sua lista de arquivos não rastreados (e se você desmarcou o arquivo após modificá-lo por engano, ele será exibido nas alterações que não foram preparadas para a lista de confirmação).

JDiMatteo
fonte
2
No Ubuntu, você pode instalar o git gui comsudo apt-get install git-gui
JDiMatteo
Obrigado! Eu estava com um problema (bug?) Em que uma pasta contendo um repositório .git foi adicionada e todos os comandos regulares de remoção não funcionaram. Isso, no entanto, ajudou. Sendo algumas confirmações, eu usei primeiro git rebase -i HEAD~4e depois executei seu comando para abrir o editor. Outra observação: "Unstaging" pode ser encontrado no menu "Commit".
Johny Skovdal
A solução mais fácil de todas. Mais simples de lembrar. E muito menos propenso a erros do que usar git reset --soft HEAD^(lembrando-se do --soft arg), seguido por git commit -c ORIG_HEAD(em vez de --amend, que estraga tudo).
Brent Faust
9

Se você deseja preservar seu commit (talvez você já tenha passado algum tempo escrevendo uma mensagem de commit detalhada e não queira perdê-lo), e só deseja remover o arquivo do commit, mas não inteiramente do repositório:

git checkout origin/<remote-branch> <filename>
git commit --amend
mattexx
fonte
6

Execute uma sequência dos seguintes comandos:

//to remove the last commit, but preserve changes  
git reset --soft HEAD~1

//to remove unneded file from the staging area  
git reset HEAD `<your file>` 

//finally make a new commit  
git commit -m 'Your message'
Sergey Onishchenko
fonte
Tentei fazer essas etapas e vejo este erro de erro: falha ao enviar algumas referências ao 'git ....' Para impedir que você perca o histórico, as atualizações de avanço rápido não foram rejeitadas Mesclar as alterações remotas (por exemplo, 'git pull') antes de pressionar novamente. Consulte a seção 'Nota sobre avanço rápido' de 'git push --help' para obter detalhes. (após git pull eu têm as mesmas alterações)
Dezigo
Isso significa que o estado do seu repo remoto mudou enquanto você fazia o trabalho local. E depois do 'git pull', as alterações locais devem ser mescladas com as remotas, é isso. Obviamente, suas alterações devem permanecer.
Sergey Onishchenko
Em outras palavras, se você receber esse erro @Dezigo, adicione o sinalizador -f para forçar a atualização.
#
5

Só queria complementar a resposta superior, pois tive que executar um comando extra:

git reset --soft HEAD^
git checkout origin/master <filepath>

Felicidades!

andrepo
fonte
Bem-vinda. Essa resposta seria melhor se você explicasse o que os comandos realmente fazem.
Mark Chorley
3

Algo que funcionou para mim, mas ainda acho que deveria haver uma solução melhor:

$ git revert <commit_id>
$ git reset HEAD~1 --hard

Apenas deixe a alteração que deseja descartar no outro commit, confira outros

$ git commit --amend // or stash and rebase to <commit_id> to amend changes
saiyancoder
fonte
3

git reset --soft HEAD^devolve seu commit e, quando você digita git status, ele diz o que fazer:

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
cardamomo
fonte
2

Na verdade, acho que uma maneira mais rápida e fácil é usar o modo interativo git rebase.

git rebase -i head~1  

(ou cabeça ~ 4, até onde você quer ir)

e então, em vez de 'escolher', use 'editar'. Eu não percebi o quão poderoso 'editar' é.

https://www.youtube.com/watch?v=2dQosJaLN18

Espero que você ache útil.

Matt
fonte
o vídeo é de 10 minutos e não é tão útil
MolbOrg
2

Tive o mesmo problema em que tenho alterações em uma filial local em que queria reverter apenas um arquivo. O que funcionou para mim foi -

( feature / target_branch abaixo é onde eu tenho todas as minhas alterações, incluindo aquelas que eu queria desfazer para um arquivo específico)

( origin / feature / target_branch é a ramificação remota para a qual desejo enviar minhas alterações)

(o recurso / armazenamento temporário é meu ramo de armazenamento temporário, onde enviarei todas as alterações desejadas, excluindo a alteração nesse arquivo)

  1. Crie uma filial local a partir da minha origem / recurso / target_branch - chamada de recurso / estadiamento

  2. Mesclou meu recurso de filial local de trabalho / target_branch à filial de recurso / preparo

  3. Efetuou check-out do recurso / teste e git reset --soft ORIG_HEAD (Agora todas as alterações do recurso / teste 'serão testadas, mas não confirmadas.)

  4. Desempenhou o arquivo que eu registrei anteriormente com alterações desnecessárias

  5. Foi alterada a ramificação upstream do recurso / preparação para origem / recurso / target_branch

  6. Confirmei o restante das alterações em etapas e enviei a montante para minha origem / recurso / target_branch remoto

user1201303
fonte
1

Se você não precisar mais desse arquivo, poderá fazer

git rm file
git commit --amend
git push origin branch
tven
fonte
1

Se você estiver usando o GitHub e ainda não enviou a confirmação, o GitHub Desktop resolve esse problema facilmente:

  1. Escolha Repositório -> Desfazer confirmação mais recente
  2. Desmarque o arquivo que você adicionou por engano. Sua mensagem de confirmação anterior já estará na caixa de diálogo.
  3. Pressione o botão Confirmar!
Ron
fonte
1

Se você deseja remover arquivos de confirmações anteriores, use filtros

git filter-branch --prune-empty --index-filter 'git rm --ignore-unmatch --cached "file_to_be_removed.dmg"'

Se você vir este erro:

Não é possível criar um novo backup. Um backup anterior já existe em refs / original / Force sobrescrevendo o backup com -f

Basta remover os backups de refs no seu repositório local

$ rm -rf .git/refs/original/refs
wilo087
fonte
1

se você não enviar suas alterações para o git ainda

git reset --soft HEAD~1

Ele redefinirá todas as alterações e reverterá para uma confirmação

Se este é o último commit que você fez e deseja excluir o arquivo do repositório local e remoto, tente o seguinte:

git rm <file>
 git commit --amend

ou melhor ainda:

redefinir primeiro

git reset --soft HEAD~1

redefinir o arquivo indesejado

git reset HEAD path/to/unwanted_file

comprometer novamente

git commit -c ORIG_HEAD  
TanvirChowdhury
fonte
o mesmo que acima, mas até realmente ajudou a checar
Reshma
0

Isso funcionou para remover o arquivo do repositório de buckets de bits que eu empurrei o arquivo para ramificar inicialmente.

git checkout origin/develop <path-to-file>
git add <path-to-file>
git commit -m "Message"
git push
swathi
fonte
0

Copiei os arquivos atuais em uma pasta diferente e depois me livrei de todas as alterações não pressionadas:

git reset --hard @{u}

Então copie as coisas de volta. Confirmar, pressionar.

Miranda
fonte
0

Você pode simplesmente usar este comando:

git restore --staged <file>
suulisina
fonte
0
Here is the step to remove files from Git Commit.

>git reset --soft HEAD^1(either commitid ) -- now files moved to the staging area.
>git rm --cached filename(it will removed the file from staging area)
>git commit -m 'meaningfull message'(Now commit the required files)
Sheo Dayal Singh
fonte
-1

Nenhuma das respostas no momento é razoável. Parece que há demanda suficiente para que uma solução real seja proposta: https://github.com/git/git/blob/master/Documentation/SubmittingPatches

git --uncommit <nome do arquivo>

seria bom. Entendo que não queremos modificar o histórico, mas se eu for local e adicionar acidentalmente o arquivo "hack" local e quiser removê-lo do commit, isso seria super útil.

Bob9630
fonte