git seletivo reverter alterações locais de um arquivo

149

No meu repositório git, que está rastreando um repositório svn, fiz várias edições em um único arquivo.

Agora eu quero reverter essas alterações (como svn revert), mas apenas partes do arquivo.

Quero poder visualizar as diferenças no arquivo, descartar (reverter) as alterações que não desejo e manter as alterações que desejar.

a

git add -i 

O comando parece ter uma opção para fazer isso, mas eu não quero preparar isso ainda.

Pradeep
fonte

Respostas:

91

Você pode fazer isso diretamente com git checkout -p. Veja a resposta de Daniel Stutzbach abaixo.


Resposta antiga (antes da checkout -pintrodução):

Você pode fazer assim:

git add -i

(selecione os pedaços que você deseja manter)

git commit -m "tmp"

Agora você tem um commit apenas com as alterações que deseja manter, e o restante é sem etapas.

git reset --hard HEAD

Nesse ponto, as alterações não confirmadas foram descartadas, para que você tenha um diretório de trabalho limpo, com as alterações que deseja manter confirmadas no topo.

git reset --mixed HEAD^

Isso remove a última confirmação ('tmp'), mas mantém as modificações no seu diretório de trabalho, sem etapas.

EDIT: substituído --softpor --mixed, para limpar a área de preparação.

Paolo Capriotti
fonte
isso confirmará as alterações que eu quero manter, não é? Ainda não quero confirmar essas alterações. mm talvez eu esteja levando commits muito a sério. Talvez eu deva relaxar agora, pois está tudo em um repositório local. btw o que o git reset --soft HEAD ^ faz?
Pradeep
"git reset --soft HEAD ^" desfaz um commit no sentido de que ele mantém o diretório e índice de trabalho como era, e move o branch atual um commit de volta.
21749 Jakub Narębski
Obrigado Jakub. Paolo, por que uma redefinição suave da cabeça - 1 seria necessária aqui? a confirmação parcial e a redefinição definitiva devem ser suficientes, não é para manter algumas alterações e descartar outras?
Pradeep
1
A resposta de Daniel abaixo é muito simples e parece o caminho certo para fazê-lo.
Umang
309

Eu acredito que você pode fazer isso de maneira mais simples com:

git checkout -p <optional filename(s)>

Na página de manual:

   −p, −−patch
       Interactively select hunks in the difference between the <tree−ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree−ish> was specified, the index).
       This means that you can use git checkout −p to selectively discard
       edits from your current working tree.
Daniel Stutzbach
fonte
1
Além disso, se você não desejar fazer isso seletivamente, poderá usar "git checkout - <file> ..." para descartar as alterações.
dB42
Lida com diretórios?
9/12/12
1
Isso parece falhar muito para mim ao descartar alterações ("erro: falha no patch <arquivo>", "erro: o patch <arquivo> não se aplica"). Estranhamente, receberei esses erros ao usar a aopção no modo de patch para descartar um arquivo inteiro, mas git checkout -- <file>funciona conforme o esperado. Alguém sabe o porquê?
chrnola
Eu tive esse erro algumas vezes se o arquivo já estava corrigido e, portanto, o patch interativo estava desatualizado com os patches aplicados do arquivo atual. Aconteceu ao usar uma ferramenta de GUI como a árvore de origem se eu descartasse um pedaço duas vezes acidentalmente. A segunda vez produziria esse erro.
Phyatt
3

Você pode executar git diffno arquivo, salve o diff resultante, editá-lo para remover as alterações que deseja salvar, em seguida, executá-lo através patch -Rde desfazer os diffs restantes.

git diff file.txt> patch.tmp
# edite patch.tmp para remover os pedaços que você deseja manter
patch -R <patch.tmp
Greg Hewgill
fonte
Eu tinha dois pedaços no meu arquivo de patch e removi um. Não sei qual é o motivo, mas o patch -R continua sendo rejeitado com isso.
Pradeep
2
Você mencionou em outro comentário que git diffmostra o arquivo inteiro como alterado. Isso geralmente acontece quando você salva o arquivo usando diferentes finais de linha do que era anteriormente. Isso também causaria patcha rejeição do arquivo de correção. Isso soa como o que poderia ter acontecido?
9119 Greg Hewgill
você está certo. as terminações das linhas são alternadas sempre que uso o comando patch. Estou no windows e usando cream / vim. Precisa resolver isso primeiro, eu acho.
Pradeep
Não foi possível resolver o problema com o patch no Windows. Embora tenha certeza de que isso funciona, prefiro usar a receita de Paolo. Para que o amor desses comandos interativos trabalhe com os diffs usando git add -i.
Pradeep
3

Parece que você quer

 git revert --no-commit $REVSISON 

Você pode então usar

 git diff --cached

para ver que alteração será feita antes da confirmação (como reverter é apenas uma confirmação em uma direção avançada que replica o inverso de uma alteração no passado)

Se você estivesse com um repositório Git puro, poderia, dependendo de seus objetivos, utilizar rebase interativo ( git rebase -i) para voltar ao commit de que não gostava e editar o commit retroativamente, para que as mudanças de que você não gosta nunca acontecessem. , mas geralmente é apenas porque, se você SABE, nunca mais precisará vê-lo.

Kent Fredric
fonte
Revirei como você mencionou em uma revisão anterior (isso está correto?) E agora o git diff apenas mostra o arquivo inteiro como alterado. É suposto mostrar as edições que eu fiz?
Pradeep
1

Relendo a pergunta, parece que você deseja reverter as alterações que estão na sua árvore de trabalho e não as que foram confirmadas anteriormente, mas algumas das outras respostas fazem parecer que minha leitura pode estar errada. Você pode esclarecer?

Se as alterações estiverem apenas na sua cópia de trabalho, a maneira mais fácil de fazer isso é preparar as alterações com as quais você deseja manter:

git add -i <file>

Em seguida, jogue fora as alterações que você não deseja manter, verificando a versão do índice:

git checkout -- <file>

Em seguida, descompacte as alterações se você ainda não as deseja:

git reset -- <file>

Esta receita reverte apenas as alterações selecionadas no arquivo (ou arquivos que você especificar) e não cria nenhuma confirmação temporária que precisa ser revertida.

Se você deseja aplicar seletivamente apenas algumas das alterações feitas nas confirmações anteriores, poderá redefinir um arquivo para um estado confirmado anteriormente primeiro:

git reset <commit_before_first_unwanted_change> -- <file>

Em seguida, você pode seguir a receita anterior para preparar git add -i <file>as alterações que deseja manter, git checkout -- <file>jogar fora as alterações indesejadas e git reset -- <file>'desestabilizar' as alterações.

CB Bailey
fonte
0

As opções de linha de comando descritas nas respostas aqui são úteis quando o arquivo está em um servidor ao qual estou acessando através de um terminal ssh. No entanto, quando o arquivo está na minha máquina local, prefiro a seguinte maneira:

Abra o arquivo no editor netbeans (que vem com suporte ao git). O Netbeans coloca marcas vermelhas / verdes / azuis nos números das linhas para indicar onde as coisas foram excluídas / adicionadas / modificadas (respectivamente).

Clicar com o botão direito do mouse em qualquer uma dessas marcas oferece a opção de desfazer essa alteração. Além disso, você pode clicar com o botão direito do mouse nas marcas vermelhas e azuis para encontrar a versão antiga em um pop-up.

Abhishek Anand
fonte