Posso fazer uma reversão parcial no GIT

156

É possível reverter apenas um único arquivo ou certas alterações em um arquivo na confirmação de vários arquivos?

História completa Eu cometi um monte de arquivos. Um número de confirmações posteriores alguém que permanecerá sem nome (JACK !!!) copiou um arquivo em seu repositório e comprometeu vários arquivos, substituindo algumas das alterações que fiz. Quero reverter o arquivo que foi derrotado ou melhor ainda, entrar e reverter duas alterações nesse arquivo. Isso terá que ser uma confirmação de reversão separada desde que foi puxada e enviada.

Embreagem
fonte
Brian me colocou no caminho certo. Acabei usando o git add --patch e usando a função de edição no patch para obter o que queria.
Embreagem
2
Estou muito atrasado para o jogo, mas acho que encontrei a resposta "certa" .
Ntc2
@ ntc2 Estranhamente, a resposta aceita funcionou para mim muito melhor do que a que você vinculou - ela criou conflitos de mesclagem para eu resolver, em vez de simplesmente não aplicar os patches.
Iiridayn
@liridayn Você leu toda a minha resposta? Na seção "variações", afirmo que adicionar --3wayresultados resulta em conflitos de mesclagem em vez de falha na aplicação de patches.
Ntc2 8/05/19

Respostas:

204

Você pode reverter o commit sem criar um novo adicionando a opção '--no-commit'. Isso deixa todos os arquivos revertidos na área de preparação. A partir daí, eu faria uma reinicialização suave e adicionaria as alterações que realmente queria. Para um exemplo de fluxo de trabalho:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit
bobDevil
fonte
42
Após a reinicialização suave, você também pode git add -piniciar uma sessão interativa que permite adicionar seletivamente pedaços de arquivos, em vez de arquivos inteiros. (Há também git reset -pa mudanças seletivamente unstage É bom saber, mas provavelmente não o que você quer neste cenário..)
Stéphan Kochen
1
Era exatamente isso que eu estava procurando: reverter para a cópia de trabalho, selecionar blocos interativamente, confirmar. Você merece um beijo grande e salgado por isso: *
das_weezul 25/06
Outra solução inspirado por esta seria revert, reset, stash -p(esconderijo "cancela que eu não quero fazer actualy"), addo resto,commit
Cyril CHAPON
82

Você pode aplicar interativamente a versão antiga de um arquivo usando o checkoutcomando

Por exemplo, se você souber COMMITonde o código a ser adicionado foi removido, você pode executar o seguinte comando:

git checkout -p COMMIT^ -- FILE_TO_REVERT

O Git solicitará que você adicione novamente os pedaços ausentes da versão atual do arquivo. Você pode usar epara criar um patch da alteração antes de aplicá-la novamente.

cmcginty
fonte
Muito útil se você quiser reverter apenas parte do arquivo! Basicamente, para obter pedaços da cabeça,git checkout -p path/to/file
falstaff
40

Você pode apenas verificar manualmente o conteúdo antigo e bom dos arquivos que deseja reverter usando git checkout. Por exemplo, se você deseja reverter my-important-filepara a versão em que estava abc123, pode fazer

git checkout abc123 -- my-important-file

Agora você tem o conteúdo antigo de my-important-filevolta e pode até editá-lo, se quiser, e confirmar como de costume fazer um commit que reverterá as alterações que ele fez. Se houver apenas algumas partes do commit dele que você deseja reverter, use git add -ppara selecionar apenas alguns pedaços do patch que você está comprometendo.

Brian Campbell
fonte
19
Este não é um revert, você está apenas recuperando uma versão antiga do arquivo. Um correto revertremoverá as modificações incorretas de confirmação no arquivo, mesmo que tenham sido modificadas várias vezes desde a confirmação incorreta, e você não deseja perder essas modificações.
Totor 8/03/2013
2
Totor, veja minha resposta. Você pode usar '-p' para salvar as modificações. A resposta está muito próxima dessa, na verdade.
cmcginty
1
Ou você pode combinar isso git checkout -p.
Léo Lam
31

Eu encontrei uma maneira de fazer isso na lista de discussão do Git:

git show <commit> -- <path> | git apply --reverse

Fonte: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Variações

Esse comando falha (sem causar alterações) se o patch não for aplicado corretamente, mas com --3wayvocê, em vez disso, você poderá obter conflitos que poderão ser resolvidos manualmente (nesse caso, a resposta de Casey pode ser mais prática):

git show <commit> -- <path> | git apply --reverse --3way

Você também pode usar isso para reverter parcialmente várias confirmações, por exemplo:

git log -S<string> --patch | git apply --reverse

reverter arquivos com alterações correspondentes <string>em qualquer confirmação. Isso é exatamente o que eu precisava no meu caso de uso (algumas confirmações separadas introduziram alterações semelhantes em arquivos diferentes, juntamente com alterações em outros arquivos de maneiras não relacionadas que eu não queria reverter).

Se você diff.noprefix=trueconfigurou o seu ~/.gitconfig, precisará adicionar -p0ao git applycomando, por exemplo

git show <commit> -- <path> | git apply -p0 --reverse
ntc2
fonte
Esta resposta é muito melhor que a aceita: "melhor ainda, entre e reverta duas alterações nesse arquivo".
reescrito
Queria reverter apenas parte de um commit, então fiz: (1) git show ... > foo.txt (2) editar foo.txtpara remover os diffs. Queria não reverter (3) git apply --reverse foo.txt para reverter os diffs ainda listados em foo.txt.
CXW
A adição de --binary --full-index à parte do git show também pode ser uma variação útil
Laurynas Biveinis