¿Cómo resolver el conflicto de git stash sin commit?

495

Como se preguntó en esta pregunta , también quiero saber cómo resolver un conflicto git stash popsin agregar todas las modificaciones a una confirmación (al igual que "git stash pop" sin conflicto).

Mi enfoque actual es muy poco interesante porque lo hago de esta manera:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Actualización] Una forma de reproducirlo:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

2016-06-27: se agregó un nuevo archivo llamado 'tercero' al ejemplo para mostrar que soluciones alternativas como la solución de scy solo funcionan para HEADs vacías pero no solucionan el problema inicial de que HEAD no tiene el mismo contenido como para un git stash popsin conflicto.

Sven
fuente
¿Entonces git addresolvió sus archivos de conflicto, organizándolos efectivamente en el índice, y no desea tenerlos en nuestro índice?
Romain
Si, eso es correcto. Solo quiero el comportamiento que git stash poptiene cuando no se produce ningún conflicto (pero con la notificación de qué archivos deben fusionarse).
Sven
2
Parece que la respuesta para esto está aquí: stackoverflow.com/questions/3945826/git-stash-questions . En la respuesta elegida, en el cuarto comentario, Adam explica por qué git hace esto.
Patrick
@Patrick Gracias por esta información, por lo que parece que no habrá una solución disponible porque es "por diseño"
Sven

Respuestas:

510

No sigas otras respuestas

Bueno, puedes seguirlos :). Pero no creo que hacer una confirmación y luego restablecer la rama para eliminar esa confirmación y soluciones similares sugeridas en otras respuestas sean la forma más clara de resolver este problema.

Solución limpia

La siguiente solución parece ser mucho más limpia para mí y también es sugerida por el propio Git : intente ejecutar git statusen el repositorio con un conflicto:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Entonces, hagamos lo que Git sugiere (sin hacer ninguna confirmación inútil):

  1. Manualmente (o usando alguna herramienta de fusión , ver más abajo) resuelve los conflictos.
  2. Se usa git resetpara marcar los conflictos como resueltos y desestabilizar los cambios. Puede ejecutarlo sin ningún parámetro y Git eliminará todo del índice. No tienes que ejecutar git addantes.
  3. Finalmente, elimine el alijo con git stash drop, porque Git no lo hace en caso de conflicto.

Traducido a la línea de comandos:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Explicación del comportamiento predeterminado.

Hay dos formas de marcar los conflictos como resueltos: git addy git reset. Mientras git resetmarca los conflictos como resueltos y elimina los archivos del índice, git addtambién marca los conflictos como resueltos, pero mantiene los archivos en el índice.

Agregar archivos al índice después de resolver un conflicto es a propósito. De esta manera, puede diferenciar los cambios del alijo anterior y los cambios que realizó después de que se resolvió el conflicto. Si no le gusta, siempre puede usar git resetpara eliminar todo del índice.

Herramientas de fusión

Recomiendo usar cualquiera de las herramientas de combinación de 3 vías para resolver conflictos, por ejemplo , KDiff3 , Meld , etc., en lugar de hacerlo manualmente. Por lo general, resuelve todos o la mayoría de los conflictos automáticamente. ¡Es un gran ahorro de tiempo!

David Ferenczy Rogožan
fuente
32
@kamalpal parece ser necesario cuando git stash popfalla con los conflictos.
Emile Bergeron
21
@kamalpal sí, Git incluso te notifica que el alijo no se ha eliminado en caso de conflicto. Y la pregunta era sobre ese caso, por lo que realmente debe ejecutar agit stash drop menos que desee mantener ese alijo.
David Ferenczy Rogožan
@ DavidFerenczyRogožan Git no me notificó en absoluto que no dejó caer la entrada de alijo. Versión 2.17.1 aquí.
Robert Siemer
298

Supongamos que tiene este escenario en el que oculta sus cambios para extraerlos del origen. Posiblemente porque sus cambios locales son solo debug: trueen algunos archivos de configuración. Ahora tiras y alguien ha introducido una nueva configuración allí, creando un conflicto.

git status dice:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

Bueno. Decidí seguir con lo que Git sugirió: resolví el conflicto y me comprometí:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Ahora mi copia de trabajo está en el estado que quiero, pero he creado una confirmación que no quiero tener. ¿Cómo me deshago de esa confirmación sin modificar mi copia de trabajo? ¡Espera, hay un comando popular para eso!

git reset HEAD^

Mi copia de trabajo no ha cambiado, pero la confirmación WIP se ha ido. Eso es exactamente lo que quería! (Tenga en cuenta que no lo estoy usando --softaquí, porque si hay archivos fusionados automáticamente en su alijo, se almacenan automáticamente y, por lo tanto, terminaría con estos archivos nuevamente reset).

Pero queda una cosa más: la página del manual git stash popnos recuerda que "la aplicación del estado puede fallar con los conflictos; en este caso, no se elimina de la lista oculta. Es necesario resolver los conflictos a mano y llamar git stash dropmanualmente después". Entonces eso es exactamente lo que hacemos ahora:

git stash drop

Y hecho.

scy
fuente
34
Hay una gran cantidad de fealdad hereditaria en tener que hacer deliberadamente reset reset HEAD ^ ... para algo que solo debería afectar el árbol de trabajo.
66
¿Por qué no simplemente resolver los conflictos y luego git add <resolved conflict files>seguir git reset HEAD?
BoltzmannBrain
Gracias por la sugerencia, pero esto no soluciona el problema inicial de que este no es el mismo comportamiento que git stash popsin un conflicto. Simplemente agregue otro archivo a HEAD antes de hacer el conflicto git stash popy git commit -a -m WIPluego también agregaría el nuevo archivo al commit. Pero sin un conflicto, solo el nuevo archivo permanecería en HEAD pero no los git stash poparchivos.
Sven
77
No creo que sea necesario comprometerse primero y luego deshacer el compromiso. Simplemente restablecer desde Dawid Ferenczy respuesta hará lo mismo
vladkras
3
Para los usuarios de Windows, ^se usa como una continuación de línea especial y lo dejará sentado en un Más? preguntar en lugar de ejecutar el comando. En lugar de utilizar: git reset --soft HEAD~1. ¿
mrfelis
87

En lugar de agregar los cambios que realice para resolver el conflicto, puede usarlo git reset HEAD filepara resolver el conflicto sin organizar sus cambios.

Sin embargo, es posible que deba ejecutar este comando dos veces. Una vez para marcar el conflicto como resuelto y una vez para desestimar los cambios organizados por la rutina de resolución de conflictos.

Es posible que haya un modo de reinicio que haga ambas cosas simultáneamente, aunque ahora no hay ninguno.

ComputerDruid
fuente
2
El modo de reinicio es el que busco; otras soluciones son como la que describí y no son prácticas para más de 5 archivos.
Sven
25
Y luego use "git stash drop" para terminar el "git stash pop".
David Liu
2
Aunque la pregunta no pide esto explícitamente, podría ser útil actualizar la respuesta para incluir "git stash drop", ya que el alijo no se elimina automáticamente en caso de conflicto.
Abhishek Pathak
29
git checkout stash -- .

trabajó para mi.

Nota : esto puede ser peligroso ya que no intenta fusionar los cambios del alijo en su copia de trabajo, sino que lo sobrescribe con los archivos escondidos. Para que pueda perder sus cambios no comprometidos.

stevenspiel
fuente
Esto ayudó cuando "git pull --autostash" introduce commits de fusión no deseados y git checkout stash -. sobrescribe incondicionalmente los conflictos del alijo
Alec Istomin
11
git add .
git reset

git add . organizará TODOS los archivos diciéndole a git que ha resuelto el conflicto

git reset desestabilizará TODOS los archivos organizados sin crear una confirmación

Aaron Goldman
fuente
Esto no es realmente una mala respuesta, que es muy parecido a git add -ucontinuacióngit reset
eBob
4

Parece que esta puede ser la respuesta que estás buscando, aún no lo he intentado personalmente, pero parece que puede ser el truco. Con este comando, GIT intentará aplicar los cambios como estaban antes, sin intentar agregarlos todos para confirmar.

git stash apply --index

Aquí está la explicación completa:

http://git-scm.com/book/en/Git-Tools-Stashing

Marco Ponti
fuente
Gracias por esta pista, pero esto no ayudará cuando ya lo hice git stash pop, o ¿hay alguna forma de revertir esto y hacerlo git stash apply --indexcuando descubrí que git stash popse encontrará con un conflicto?
Sven
He agregado un ejemplo sobre cómo producir esto: imagine que está editando más de 10 archivos, por lo que no sabe cuál de ellos modificó fuera del alijo.
Sven
3
Si miras al final de esta publicación AQUÍ , dice que si ejecutas git stash popy termina con conflictos, el alijo no se elimina ... para que puedas ejecutar git reset --hardpara deshacer el pop y luego probar la solución que sugerí.
Marco Ponti
Acabo de probar esto y no funciona después de tener un archivo en estado de conflicto. Incluso si arreglas el conflicto manualmente.
Sam3k
2

git stash branchwill works, que crea una nueva rama para usted, comprueba el commit en el que estaba cuando escondió su trabajo, vuelve a aplicar su trabajo allí y luego deja caer el alijo si se aplica con éxito. mira esto

apreciar
fuente
2

La forma más rápida que he encontrado es resolver el conflicto, luego hacer git add -u, y luego hacer git reset HEAD, que ni siquiera implica un compromiso.

Jammer
fuente
1

Según las preguntas de git stash , después de arreglar el conflicto, git add <file>es el curso de acción correcto.

Fue después de leer este comentario que entendí que los cambios se agregan automáticamente al índice (por diseño). Es por eso que git add <file>completa el proceso de resolución de conflictos.

samgrigg
fuente
-1

No es la mejor manera de hacerlo, pero funciona:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file
Bishwas Mishra
fuente
esta respuesta me parece totalmente errónea, ya que descartaría todos los cambios file/path/to/your/file, que no es lo que el OP preguntó, AFAIU
oromoiluig