Deshacer parte de cambios no organizados en git

158

¿Cómo deshago partes de mis cambios no organizados en git pero mantengo el resto como no organizado? La forma en que me di cuenta es:

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 bueno si hubiera algo como git commit --interactivesolo para revertir los cambios. ¿Algún mejor método?

asmeurer
fuente

Respuestas:

265

Puede usar git checkout -p, que le permite elegir trozos individuales de la diferencia entre su copia de trabajo y el índice para revertir. Del mismo modo, le git add -ppermite elegir trozos para agregar al índice y le git reset -ppermite elegir trozos individuales de la diferencia entre el índice y HEAD para retroceder fuera del índice.

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

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

$ git stash; git stash apply

Si usa eso a menudo, es posible que desee asignarle un alias:

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

Revertir trozos o líneas individuales puede ser aún más fácil si usa un buen modo de editor o complemento, que puede proporcionar soporte para seleccionar líneas directamente para revertir, ya -pque a veces puede ser un poco torpe usarlo. Uso Magit , un modo Emacs que es muy útil para trabajar con Git. En Magit, puede ejecutar magit-status, encontrar las diferencias para 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 en lugar de una línea a la vez) y presione kpara revertir esas líneas específicas. Recomiendo encarecidamente Magit si usa Emacs.

Brian Campbell
fuente
Creo que esto es tan complejo como la solución que originalmente se me ocurrió, pero creo que mi solución original tiene la ventaja de guardar las líneas eliminadas durante 30 días porque están comprometidas. Sin embargo, estoy pensando que tal vez sería bueno tener un script de shell escrito a su alrededor.
Asmeurer 01 de
1
Lo siento, me acabo de dar cuenta de que git checkouttambién tiene una -pbandera, que hace exactamente lo que pedías en un solo comando. Disculpas por el complejo conjunto de pasos anteriores; solo puedes 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 creo un alias que hace eso como git checkpointo algo) para registrar el árbol actual en un alijo para poder volver a él si algo sale mal.
Brian Campbell el
Ahí tienes, ¡esa es la solución! En cuanto al alias, estoy pensando que algo así 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 tenga el SHA1, puede elegirlo dentro de los próximos 30 días. --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 registro de git, así que supongo que es una compensación basada en lo que haces.
asmeurer
El alias de punto de control no funciona para mí: solo se ejecuta el primer comando, no el segundo. Eso es triste, porque me hubiera gustado. Estoy usando git versión 1.7.10.4.
Fabien
¿Hay alguna manera de hacer que git checkout -pno se apliquen los parches al índice sino que solo se los escalone?
Geremia
28
git diff > patchfile

Luego edite el archivo de parche y elimine las partes que no desea deshacer, luego:

patch -R < patchfile
octoberblu3
fuente
66
Sin embargo, esta respuesta es particularmente admirable por su simplicidad y facilidad de uso. +1
tholy
¡El generado se patchfileve muy bien en vim y realmente ayuda!
Bily
Perfecto. Puede confirmar que también funciona en Windows con Cygwin y Ubuntu bash para Windows.
Checo R
1
Tenga en cuenta que también puede usar en git apply -Rlugar de patch(solo para permanecer dentro de los reinos de git, o en el caso diferente que patchno está disponible)
user1556435
patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace
5

Podrías hacerlo

git checkout master -- path/to/file

Para cada archivo que desea restablecer.

Drew Hoskins
fuente
O use HEAD en lugar de master si trabaja en una rama. Como dice en el informe 'git status' (al menos en versiones recientes).
Jonathan Leffler
1

Qué tal si

  1. Retroceda los archivos afectados con cambios del índice
  2. use git add -ppara volver a agregar los cambios que desea al índice.
Abizern
fuente
1

Cuando ejecuto 'git status', 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")
$

Entonces, para cancelar las ediciones no preparadas, me dice que ejecute:

git checkout -- makefile
Jonathan Leffler
fuente
3
Creo que se preguntaba cómo revertir los 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.
Brian Campbell el
Sí, sospecho que tienes razón. Las opciones 'git checkout -p' y 'git add -p' parecen ser lo que se desea, como usted dijo.
Jonathan Leffler
1

La respuesta de Brian Campbell bloquea mi git, versión 1.9.2.msysgit.0, por razones desconocidas, por lo que mi enfoque es poner en escena a los trozos que quiero conservar, descartar los cambios en la copia de trabajo y luego quitar el escenario.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .
G-Wiz
fuente
1
También existe git stash -p. Usted podría hacer git stash -p; git reset --hard; git stash pop. Esto es efectivamente lo mismo que estás haciendo, excepto que no tienes que escribir un mensaje de confirmación.
Asmeurer
@asmeurer aplausos. El mío no requiere un mensaje de confirmación, pero es probable que tenga más sentido usar el alijo que el índice para esto.
G-Wiz
0

puede hacer git checkouty darle nombres de las partes que desea deshacer.

Andrés
fuente