Desfazer modificações na cópia de trabalho de um arquivo no Git?

1634

Após a última confirmação, modifiquei vários arquivos na minha cópia de trabalho, mas quero desfazer as alterações em um desses arquivos, pois redefini-lo para o mesmo estado que a confirmação mais recente.

No entanto, só quero desfazer as alterações na cópia de trabalho apenas desse arquivo, nada mais.

Como faço isso?

hasen
fonte

Respostas:

2215

Você pode usar

git checkout -- file

Você pode fazer isso sem o --(como sugerido pelo nimrodm), mas se o nome do arquivo se parecer com uma ramificação ou marca (ou outro identificador de revisão), ele poderá ficar confuso, portanto, --é melhor usar .

Você também pode verificar uma versão específica de um arquivo:

git checkout v1.2.3 -- file         # tag v1.2.3
git checkout stable -- file         # stable branch
git checkout origin/master -- file  # upstream master
git checkout HEAD -- file           # the version from the most recent commit
git checkout HEAD^ -- file          # the version before the most recent commit
Brian Campbell
fonte
34
qual é a diferença entre HEAD e HEAD ^?
hasen
62
HEAD é a confirmação mais recente na ramificação atual e HEAD ^ é a confirmação antes disso na ramificação atual. Para a situação que você descreve, você pode usar o git checkout HEAD - nome do arquivo.
Paul
16
Resumindo, "git checkout sha-reference - filename", onde a sha-reference é uma referência ao sha de um commit, sob qualquer forma (branch, tag, parent, etc.)
Lakshman Prasad
29
NOTA: Se o arquivo já estiver preparado, é necessário redefini-lo primeiro. git reset HEAD <filename> ; git checkout -- <filename>
Olie
14
@gwho Sim, você pode fazer HEAD^^por 2 confirmações das mais recentes ou HEAD^^^por 3 confirmações. Você também pode usar HEAD~2, ou HEAD~3, o que for mais conveniente se você quiser voltar mais confirmações, enquanto HEAD^2significa "o segundo pai dessa confirmação"; por causa das confirmações de mesclagem, uma confirmação pode ter mais de uma confirmação anterior; portanto, com HEAD^um número seleciona qual desses pais, enquanto com HEAD~um número sempre seleciona o primeiro pai, mas esse número de confirmações. Veja git help rev-parsepara mais detalhes.
Brian Campbell
139

Apenas use

git checkout filename

Isso substituirá o nome do arquivo pela versão mais recente da ramificação atual.

AVISO: suas alterações serão descartadas - nenhum backup é mantido.

nimrodm
fonte
22
@ Duckx é desambiguar nomes de ramificações de nomes de arquivos. se você diz que git checkout xx é um nome de ramificação e um nome de arquivo, não tenho certeza qual é o comportamento padrão, mas acho que o git assumirá que você deseja alternar para a ramificação x. Quando você usa, --está dizendo que o seguinte é o nome dos arquivos.
hasen
1
ic obrigado por esclarecer isso. todo mundo assume que você sabe o que significa - quando mostra exemplos. e não é algo que você possa pesquisar facilmente no Google.
Patoshiパトシ
1
Parece que a resposta foi editada para removê ---la. Enquanto ainda estiver correto, como @hasen aponta, se houver uma ambiguidade entre o nome do arquivo e os nomes das filiais, você poderá ter um comportamento muito indesejado aqui!
BrainSlugs83
2
Eu gosto do jeito que é, sem --, agradável e fácil. Quando o nome de ramos usando nomes de arquivo, deve haver algum pensamento ruim ...
Marco Faustinelli
133
git checkout <commit> <filename>

Eu usei isso hoje porque percebi que meu favicon havia sido substituído há alguns commits atrás, quando atualizei para o drupal 6.10, então tive que recuperá-lo. Aqui está o que eu fiz:

git checkout 088ecd favicon.ico
neoneye
fonte
1
Como obtenho o commit (de um arquivo excluído anteriormente), exceto a rolagem, que gera toneladas de resultados "git log --stat"?
Alex
4
Na IMO, é meio difícil, através da linha de comando, verificar o log do gits e encontrar o arquivo certo. É muito mais fácil com um aplicativo GUI, como sourcetreeapp.com
neoneye
6
git log --oneline <filename>vai lhe dar um log mais compacto, e incluem apenas alterações no arquivo específico
rjmunro
1
alternativamente, você pode usargit reflog <filename>
ygesher
70

Se o seu arquivo já estiver preparado (acontece quando você faz um git add etc após a edição do arquivo) para desestabilizar suas alterações.

Usar

git reset HEAD <file>

Então

git checkout <file>

Se ainda não estiver preparado, basta usar

git checkout <file>
thanikkal
fonte
2
Isso tem sido mais útil do que o aceito, haha. É fácil esquecer quais mudanças foram realizadas e quais não foram, portanto, a redefinição ajudou. Embora eu também tenha tentado o "git reset --hard" antes, ele não fez o que o "git reset HEAD" fez. Eu quero saber porque?
Arman Bimatov
20

Se você quiser apenas desfazer as alterações do commit anterior nesse arquivo, tente:

git checkout branchname^ filename

Isso fará o checkout do arquivo como era antes da última confirmação. Se você quiser voltar mais algumas confirmações, use a branchname~nnotação.

sykora
fonte
Isso não removerá as alterações do commit, apenas aplicará o diff à versão no HEAD.
FernandoEscher
2
Embora verdadeiro, o pôster original só queria reverter suas modificações na cópia de trabalho (acho), não reverter as alterações do último commit. A pergunta do pôster original era um pouco obscura, para que eu possa entender a confusão.
talvez não utilização do OP, mas eu estava procurando para saber como substituir o meu ramo com a cópia do master - isso funciona muito bem quando substituirbranchname^
Alex
15

Eu fiz através do git bash:

(use "git checkout -- <file>..." to discard changes in working directory)

  1. Status Git. [Então, vimos um arquivo modificado.]
  2. git checkout - index.html [eu mudei no arquivo index.html:
  3. status git [agora essas alterações foram removidas]

insira a descrição da imagem aqui

Shiva
fonte
8

Sempre fico confuso com isso, então aqui está um caso de teste de lembrete; digamos que temos esse bashscript para testar git:

set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email [email protected]
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt

Nesse ponto, a alteração não é preparada no cache, assim git statuscomo:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Se a partir deste ponto git checkout, o resultado é este:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Se o fizermos git reset, o resultado é:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Portanto, neste caso - se as alterações não forem testadas, git resetnão faz diferença, enquanto as git checkoutsubstitui.


Agora, digamos que a última alteração do script acima seja preparada / armazenada em cache, ou seja, também fizemos git add b.txtno final.

Nesse caso, git statusneste momento é:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   b.txt

Se a partir deste ponto git checkout, o resultado é este:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Se o fizermos git reset, o resultado é:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Portanto, neste caso - se as alterações forem git resetpreparadas , basicamente as transformadas serão transformadas em etapas - enquanto git checkoutsubstituem completamente as alterações.

sdaau
fonte
7

Esta resposta é para o comando necessário para desfazer alterações locais que estão em vários arquivos específicos na mesma ou em várias pastas (ou diretórios). Essas respostas abordam especificamente a pergunta em que um usuário tem mais de um arquivo, mas o usuário não deseja desfazer todas as alterações locais:

se você tiver um ou mais arquivos, poderá aplicar o mesmo comando ( git checkout -- file) a cada um desses arquivos, listando cada um de seus locais separados por espaço, como em:

git checkout -- name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext

lembre-se do espaço acima entre name1 / name2 / fileOne.ext nameA / subFolder / fileTwo.ext

Para vários arquivos na mesma pasta:

Se você precisar descartar as alterações para todos os arquivos em um determinado diretório, use o git checkout da seguinte maneira:

git checkout -- name1/name2/*

O asterisco acima faz o truque de desfazer todos os arquivos nesse local em nome1 / nome2.

Da mesma forma, o seguinte pode desfazer alterações em todos os arquivos para várias pastas:

git checkout -- name1/name2/* nameA/subFolder/*

lembre-se novamente do espaço entre nome1 / nome2 / * nomeA / subpasta / * acima.

Nota: nome1, nome2, nomeA, subpasta - todos esses nomes de pastas de exemplo indicam a pasta ou o pacote em que os arquivos em questão podem estar residindo.

Nirmal
fonte
5

Eu restauro meus arquivos usando o ID SHA. O que faço é git checkout <sha hash id> <file name>

Beto
fonte
3

Para mim, apenas este funcionou

git checkout -p filename

insira a descrição da imagem aqui

Ramesh Bhupathi
fonte
2

Se você ainda não enviou ou compartilhou seu commit:

git diff --stat HEAD^...HEAD | \
fgrep filename_snippet_to_revert | cut -d' ' -f2 | xargs git checkout HEAD^ --
git commit -a --amend
Jesse Glick
fonte
0

Se ele já estiver confirmado, você poderá reverter a alteração para o arquivo e confirmar novamente e depois esmagar o novo commit com o último commit.

Gina
fonte
1
Adicionar comandos específicos ao uso ajudaria o pôster original e futuros visitantes.
26617 Adrian
0

Não sei por que, mas quando tento inserir meu código, ele aparece como uma imagem.

insira a descrição da imagem aqui

Gene
fonte