Desfazer um commit particular no Git que foi enviado para repositorys remotos

Qual é a maneira mais simples de desfazer um commit específico que é:

  • não na cabeça ou na cabeça
  • Foi empurrado para o controle remoto.

Porque se não for o commit mais recente,

git reset HEAD 

não funciona. E porque foi empurrado para um controle remoto,

 git rebase -i 

e

 git rebase --onto 

causará algum problema nos controles remotos.

Mais ainda, não quero modificar realmente a história. Se houvesse código ruim, ele estava lá na história e pode ser visto. Eu só quero isso na cópia de trabalho, e não me importo com um commit de merge reverso.

Em outras palavras, qual é o equivalente Git dos seguintes comandos svn:

 svn merge -r 303:295 http://svn.example.com/repos/calc/trunk 

que remove todas as alterações de 295 para 302 pela mesclagem reversa de todas as alterações nessas revisões, como um novo commit.

 svn merge -c -302 ^/trunk 

que desfaz o 302 commit, é claro, adicionando outro commit que reverta as mudanças do respectivo commit.

Eu pensei que deveria ser uma operação bastante simples no Git e um caso de uso bastante comum. O que mais é o ponto dos commits atômicos?

Nós temos staging stashing e tudo para garantir que os commits sejam perfeitamente atômicos, você não deveria ser capaz de desfazer facilmente um ou mais desses commits atômicos?

Identifique o hash do commit, usando git log , então use git revert para criar um novo commit que remova essas mudanças. De certo modo, git revert é o inverso do git cherry-pick – o último aplica o patch a um branch que está faltando, o primeiro remove de um branch que o possui.

Eu não gosto do auto-commit que o git revert faz, então isso pode ser útil para alguns.

Se você quer apenas que os arquivos modificados não sejam auto-commit , você pode usar --no-commit

 % git revert --no-commit  

que é o mesmo que o -n

 % git revert -n  

Como já foi pressionado, você não deve manipular diretamente o histórico. git revert irá reverter mudanças específicas de um commit usando um novo commit, para não manipular o histórico de commits.