2011-01-25 14 views
96

Quiero revertir una confirmación en particular en git. Desafortunadamente, nuestra organización todavía usa CVS como estándar, por lo que cuando me comprometo nuevamente con CVS, múltiples commit de git se combinan en uno solo. En este caso, me encantaría destacar el commit original de git, pero eso es imposible.Revertir parte de una confirmación con git

¿Existe un enfoque similar al git add --patch que me permita editar selectivamente las diferencias para decidir qué partes de un compromiso revertir?

+0

Más soluciones [aquí] (http://stackoverflow.com/q/5669358/470844), pero centrándose en limitar la reversión parcial a archivos específicos. – ntc2

Respuesta

160

Utilice la opción --no-commit (-n) a git revert, entonces unstage los cambios, a continuación, utilizar git add --patch:

$ git revert -n $bad_commit # Revert the commit, but don't commit the changes 
$ git reset HEAD .    # Unstage the changes 
$ git add --patch .   # Add whatever changes you want 
$ git commit     # Commit those changes 

Nota: Los archivos que añada usando git add --patch son los archivos que desea revertir, no los archivos que quieres conservar

+12

Puede valer la pena agregar el último comando requerido, para aquellos que no estén tan familiarizados con git: después de confirmar, 'git reset --hard' para descartar los otros cambios que no desea revertir. – tremby

+10

'git reset --hard' es peligroso para los novatos, ya que podría perder ediciones deseadas. En cambio, acostúmbrate a 'git status', esto sugiere que' git checkout - FILE..' revierte las cosas de forma más segura. – Tino

+0

¡Qué gran omisión en 'git'; 'git revert' solo debería tomar un argumento' --patch'. – Kaz

1

Puede usar git-revert -n, y luego usar add --patch para seleccionar hunks.

32

He utilizado lo siguiente con éxito.

Primero invierta la confirmación completa (lo pone en el índice) pero no se comprometa.

git revert -n <sha1> # -n is short for --no-commit 

A continuación, retire de forma interactiva el bien revertidas cambios con respecto al índice de

git reset -p   # -p is short for --patch 

Entonces cometer diff reverso de las malas cambios

git commit -m "Partially revert <sha1>..." 

Finalmente los revertidas buenos cambios (que han sido unstaged por el comando de reinicio) todavía están en el árbol de trabajo. Ellos necesitan ser limpiados. Si no hay otros cambios no se dejan en el árbol de trabajo, esto se puede hacer por

git reset --hard 
+5

¿No es esta una alternativa superior a la respuesta aceptada (que usa 'reset HEAD .'), porque no requiere la limpieza final del directorio de trabajo? –

+2

Esta respuesta es superior, porque 'reset -p' es más corto que' reset HEAD' seguido de 'add -p'. Pero aún requiere la limpieza, ya que los "buenos" tíos que se han reiniciado todavía están en el directorio de trabajo después de la confirmación. –

+0

Esta respuesta no es superior porque eliminar interactivamente los cambios que ** desea ** suele ser confuso y propenso a errores, especialmente si alguno de ellos requiere una edición. – Kaz

4

Solución:

git revert --no-commit <commit hash> 
git reset -p  # every time choose 'y' if you want keep the change, otherwise choose 'n' 
git commit -m "Revert ..." 
git checkout -- . # Don't forget to use it. 
+0

Ayudaría a la gente si dijera cómo es diferente de la solución aceptada – CharlesB

+1

@Krzysztof ¿Por qué es importante el pago al final y por qué esta solución es diferente de la del usuario1338062? – martin

3

Personalmente, prefiero esta versión, que reutiliza el mensaje de auto-generada comprometerse y da el usuario tiene la oportunidad de editar y pegar la palabra "Parcialmente" antes de comprometerse finalmente.

# generate a revert commit 
# note the hash printed to console on success 
git revert --no-edit <hash to revert> 

# undo that commit, but not its changes to the working tree 
# (reset index to commit-before-last; that is, one graph entry up from HEAD) 
git reset HEAD~1 

# interactively add reversions 
git add -p 

# commit with pre-filled message 
git commit -c <hash from revert commit, printed to console after first command> 

# reset the rest of the current directory's working tree to match git 
# this will reapply the excluded parts of the reversion to the working tree 
# you may need to change the paths to be checked out 
# be careful not to accidentally overwrite unsaved work 
git checkout -- . 
Cuestiones relacionadas