Redefinição definitiva de um único arquivo

1006

Atualmente, tenho três arquivos modificados no meu diretório de trabalho. No entanto, quero que um deles seja redefinido para o status HEAD.

No SVN, eu usaria svn revert <filename>(seguido por, svn update <filename>se necessário), mas no Git eu deveria usar git reset --hard. No entanto, este comando não pode operar em um único arquivo.

Existe alguma maneira no Git de descartar as alterações em um único arquivo e substituí-lo por uma cópia HEAD nova?

Emiliano
fonte
3
git checkoutabaixo está a resposta. No git, "reverter" é algo que você faz em um commit. "Revert" repete o inverso de uma confirmação histórica em seu diretório de trabalho, para que você possa fazer uma nova confirmação que "desfaça" a confirmação revertida. Acho que esse é um ponto frequente de confusão para as pessoas que vêm para o gn a partir do svn.
Dan Ray
Se você está interessado em saber por que não pode fazer uma reinicialização completa com caminhos, confira minha resposta .
usuário
Esta pergunta assume que se sabe o que é uma reinicialização por hardware.

Respostas:

1810

Você pode usar o seguinte comando:

git checkout HEAD -- my-file.txt

... que atualizará a cópia de trabalho my-file.txte seu estado no índice com o do HEAD.

--basicamente significa: trate todos os argumentos após esse ponto como um nome de arquivo . Mais detalhes nesta resposta . Agradecemos ao VonC por apontar isso.

Mark Longair
fonte
58
Resposta mais completa. +1;) Para o '-', consulte também stackoverflow.com/questions/6561142/… (e, mais geralmente, stackoverflow.com/questions/1192180/… )
VonC
8
Além disso, não esqueça que você pode fazer referência a um commit anterior HEAD~1para indicar o penúltimo commit.
21915 Ryanmt
14
Você pode deixar de fora HEADse você está na cabeça do ramo atual - ver norbauer.com/rails-consulting/notes/...
CXW
4
Alguma idéia de por que o resetcomando (como está escrito) "não pode fazer redefinições forçadas com caminhos" e por que o checkoutcomando não é (não pode ser?) Usado para redefinir com firmeza todo o conjunto? (Quero dizer, por que foi projetado assim.)
Sz.
1
@cxw Infelizmente, isso não é bem verdade. Na página de manual de git checkout: "Substitua caminhos na árvore de trabalho substituindo pelo conteúdo no índice ou no <tree-ish>". Ou seja, se <tree-ish>for omitido, qualquer conteúdo no índice será usado para atualizar a árvore de trabalho. Isso pode ou não diferir do HEAD.
tuntap
137

Redefinir para a cabeça:

Para redefinir um único arquivo para HEAD:

git checkout @ -- myfile.ext

Note que @é a abreviação deHEAD . Uma versão mais antiga do git pode não suportar o formato abreviado.

Redefinir para o índice:

Para redefinir com firmeza um único arquivo para o índice , assumindo que o índice não esteja vazio, caso contrário, para HEAD:

git checkout -- myfile.ext

O ponto é que, para ser seguro, você não deseja excluir @ouHEAD usar o comando, a menos que queira especificamente redefinir apenas o índice .

Acumenus
fonte
1
O que há com o "-" antes do myfile.ext?
Lance Tipo
3
@LanceKind Pelo que entendi, isso é usado para demarcar uma lista de nomes de arquivos a seguir. Sem ele, há casos em que o git interpreta os argumentos incorretamente.
Acumenos
2
Não apenas nomes de arquivos. A convenção amplamente usada separa opções de argumentos posicionais em muitos utilitários. Veja a man bashpágina. Também mencionado nesta resposta: unix.stackexchange.com/a/187548/142855
boweeb
1
Convencionalmente, o --é usado para informar o programa I've finished specifying "options", and from here on, everything will be a positional argument.. Convencionalmente, "opções" são os tokens --recursiveque podem aparecer em qualquer ordem ou até mesmo serem combinados em sua forma abreviada, como com rm -rf. Pelo contrário, "argumentos posicionais" são muito mais parecidos com argumentos passados ​​para uma função em uma linguagem de programação: sua posição na lista de tokens define o que exatamente o programa fará com eles (geralmente são nomes de arquivos). --remove a ambiguidade de qual é qual.
iono
42

Para reverter para upstream / master, faça:

git checkout upstream/master -- myfile.txt
Ann Raiho
fonte
19

Desde o Git 2.23 (agosto de 2019), você pode usar restore( mais informações ):

git restore pathTo/MyFile

O acima será restaurado MyFileemHEAD (o último commit) no ramo atual.

Se você deseja obter as alterações de outro commit, você pode voltar no histórico de commit. O comando abaixo terá MyFiledois commits anteriores ao último. Você precisa agora da opção -s( --source), já que agora usa master~2e não master(o padrão) ao restaurar a fonte:

git restore -s master~2 pathTo/MyFile

Você também pode obter o arquivo de outro ramo!

git restore -s my-feature-branch pathTo/MyFile
AxeEffect
fonte
1
A maneira mais fácil até agora. Infelizmente, esta resposta não está recebendo atenção suficiente.
singrium 12/02
5

A referência ao HEAD não é necessária.

git checkout -- file.js é suficiente

Emanuel Friedrich
fonte
4

você pode usar o comando abaixo para redefinir o arquivo único

git checkout HEAD -- path_to_file/file_name

Listar todos os arquivos alterados para obter path_to_file/filenamecom o comando abaixo

git status
HariKishore
fonte
1

Você pode usar o seguinte comando:

git reset -- my-file.txt

que atualizará a cópia de trabalho de my-file.txtquando adicionada.

ADDYQU
fonte
Não altera o conteúdo do arquivo modificado, conforme solicitado.
Rafael
Quando você adiciona ao stash Você editou o arquivo?
ADDYQU 29/08/19
1
Esse não é especificamente o ponto @ADDQU. A questão é como "redefinir o hardware" de um arquivo, não removê-lo da lista faseada.
Rafael
@ Rafael Você está correto, mas eu quero que você saiba que existe um caminho também.
ADDYQU 30/08/19
0

Você pode usar o seguinte comando:

git checkout filename

Se você possui uma ramificação com o mesmo nome de arquivo, deverá usar este comando:

git checkout -- filename
Milad Rahimi
fonte
1
Isso não "reinicializará" o arquivo - ele copia apenas o estado do índice para a árvore de trabalho. Um "hard reset" redefiniria primeiro o índice.
AH
-21

Uma maneira simples, fácil e prática de tirar você da água quente, especialmente se você não está tão confortável com o git:

  1. Veja o log do seu arquivo

    git log myFile.js

    confirmar 1023057173029091u23f01w276931f7f42595f84f Autor: kmiklas Data: terça-feira, 7 de agosto de 09:29:34 2018 -0400

    JIRA-12345 - Refatorar com nova arquitetura.

  2. Observe o hash do arquivo:

    1023057173029091u23f01w276931f7f42595f84f

  3. Mostre o arquivo usando o hash. Certifique-se de que é o que você deseja:

    git show 1023057173029091u23f01w276931f7f42595f84f: ./ myFile.js

  4. Redirecionar arquivo para uma cópia local

    git show 1023057173029091u23f01w276931f7f42595f84f: ./ myFile.js> myFile.07aug2018.js

  5. Faça backup do seu arquivo atual.

    cp myFile.js myFile.bak.js

  6. Abra os dois arquivos no seu editor de texto favorito.

    vim myFile.js
    vim myFile.07aug2018.js

  7. Copie e cole o código de myFile.07aug2018.js para myFile.js e salve.

  8. Confirme e envie myFile.js

  9. Mais uma vez, visualize o log e confirme se seu arquivo está no lugar correto.

  10. Diga aos seus clientes para obterem a versão mais recente e observem com satisfação que ele funciona com a versão antiga.

Não é a solução mais sexy ou mais centrada no git, e definitivamente uma redefinição / reversão "manual", mas funciona. Requer conhecimento mínimo de git e não perturba o histórico de consolidação.

kmiklas
fonte
2
Essa resposta é muito mais complexa e propensa a erros do que qualquer uma das soluções anteriores a anos.
Artif3x #
2
Por que alguém deveria usar esta solução !? a resposta verdadeira é apenas um comando simples.
Milad Rahimi
1
Esta é a solução ideal para determinadas circunstâncias. Ele tem mérito para aqueles em conflito, onde o git está com defeito, e para aqueles que precisam de uma solução alternativa.
Kmiklas