2009-12-30 17 views
117

¿Cómo deshago partes de mis cambios no ejecutados en git pero mantengo el resto sin editar? La forma en que me di cuenta es:Deshacer parte de los cambios sin estado en git

git commit --interactive 
# Choose the parts I want to delete 
# Commit the changes 
git stash 
git rebase -i master # (I am an ancestor of master) 
# Delete the line of the most recent commit 
git stash apply 

Esto funciona, pero sería agradable si había algo así como sólo para revertir los cambios. ¿Algún método mejor?

Respuesta

199

Puede usar git checkout -p, que le permite elegir trozos individuales desde la diferencia entre su copia de trabajo e índice para revertir. Del mismo modo, git add -p le permite elegir lo que desea agregar al índice, y git reset -p le permite elegir entre las diferencias individuales entre el índice y HEAD para salir del índice.

$ git checkout -p file/to/partially/revert 
# or ... 
$ git checkout -p . 

Si desea crear una instantánea de su repositorio git de antemano para preservar estos cambios antes de volver ellos, me gusta hacer:

$ git stash; git stash apply 

Si se utiliza muy a menudo, es posible que desee crear un alias que:

[alias] 
    checkpoint = !git stash; git stash apply 

Volviendo trozos o líneas individuales pueden ser aún más fácil si utiliza un buen modo de edición o plug-in, que puede proporcionar apoyo para la selección de líneas directamente a revertir, como -p puede ser un poco torpe para usar a veces. Yo uso Magit, un modo Emacs que es muy útil para trabajar con Git. En Magit, puede ejecutar magit-status, encontrar los diffs de los cambios que desea revertir, seleccionar las líneas que desea revertir (o simplemente colocar el cursor en los trozos que desea revertir si desea revertir un trozo a la vez) de una línea a la vez), y presione k para revertir esas líneas específicas. Recomiendo Magit si usas Emacs.

+0

Creo que esto es tan complejo como la solución que se me ocurrió originalmente, pero creo que mi solución original tiene el beneficio de guardar las líneas eliminadas durante 30 días porque están comprometidas. Estoy pensando que tal vez sería bueno tener un guión de shell escrito alrededor de él, sin embargo. – asmeurer

+1

Disculpa, me acabo de dar cuenta de que 'git checkout' también tiene un indicador' -p', que hace exactamente lo que pedías en un solo comando. Disculpas por el complejo conjunto de pasos anterior; simplemente puede usar 'git checkout -p'. En cuanto a guardar cosas, antes de hacer algo potencialmente destructivo, a menudo hago un 'git stash'; git stash apply' (o crea un alias que hace eso como 'git checkpoint' o algo así) para registrar el árbol actual en un escondite para que pueda volver a él si algo sale mal. –

+0

¡Ahí va, esa es la solución! En cuanto al alias, estoy pensando en algo como 'git commit -a -m" Backup Commit "--edit; git reset HEAD^' sería mejor, porque entonces no ensuciaría mi estado oculto, que podría estar usando para otra cosa. Luego, siempre que tengas SHA1 puedes elegirlo en los próximos 30 días. El --edit le permite agregar información al mensaje de confirmación para ayudarlo a encontrar el SHA1 más adelante si lo desea. Por otro lado, esto ensuciaría el refrito de git, así que supongo que es una compensación basada en lo que haces. – asmeurer

0

puede hacer git checkout y darle los nombres de las piezas que desea deshacer.

1

¿Qué tal

  1. Volver a cabo los archivos afectados con los cambios del índice de
  2. uso git add -p a añadir de nuevo solamente los cambios que desea para el índice.
5

Usted podría hacer

git checkout master -- path/to/file 

Para cada archivo que desea restablecer.

+0

O use HEAD en lugar de maestro si trabaja en una rama. Como dice en el informe 'git status' (al menos en versiones recientes). –

1

Cuando corro 'git status', que dice:

$ git status 
# On branch fr/fr.002 
# Changed but not updated: 
# (use "git add <file>..." to update what will be committed) 
# (use "git checkout -- <file>..." to discard changes in working directory) 
# 
# modified: makefile 
# 
no changes added to commit (use "git add" and/or "git commit -a") 
$ 

Así, para cancelar los cambios unstaged, me dice a ejecutar:

git checkout -- makefile 
+3

Creo que se preguntaba cómo revertir trozos individuales, no un archivo completo a la vez. Esta es, por supuesto, la solución si solo necesita deshacer todos los cambios en un archivo. –

+0

Sí, sospecho que tienes razón. Las opciones 'git checkout -p' y 'git add -p' parecen ser lo que se quiere, como dijiste. –

15
git diff > patchfile 

luego editar el fichero de parche y quite las partes que no desea deshacer, entonces:

patch -R < patchfile 
+4

Sin embargo, esta respuesta es particularmente admirable por su simplicidad y facilidad de uso. +1 – tholy

+0

¡El 'archivo de parche' generado se ve muy bien en vim y realmente ayuda! – Bily

+0

Perfecto. Puede confirmar que también funciona en Windows con Cygwin y Ubuntu bash para Windows. –

0

Brian Campbell's answer bloquea mi git, versión 1.9.2.msysgit.0, por razones desconocidas, por lo que mi enfoque consiste en evaluar los cambios que quiero mantener, descartar los cambios en la copia de trabajo y luego dejar de grabar.

$ git add -p 
    ... select the hunks to keep 
$ git checkout -- . 
$ git reset HEAD . 
+1

También hay' git stash -p' . Podrías hacer 'git stash -p; git reset --hard; git stash pop'. Esto es efectivamente lo mismo que lo que está haciendo, excepto que no tiene que escribir un mensaje de compromiso. – asmeurer

+0

@asmeurer cheers. El mío no requiere un mensaje de compromiso, pero tiene más sentido usar el alijo que el índice para esto. –

Cuestiones relacionadas