git stash -> fusionar el cambio oculto con los cambios actuales


187

Hice algunos cambios en mi sucursal y me di cuenta de que olvidé haber escondido algunos otros cambios necesarios en dicha sucursal. Lo que quiero es una forma de fusionar mis cambios escondidos con los cambios actuales.

¿Hay alguna forma de hacer esto?

Es más por conveniencia, finalmente me di por vencido y cometí primero mis cambios actuales, luego mis cambios escondidos, pero hubiera preferido incorporarlos de una sola vez.


Probablemente duplicado de stackoverflow.com/q/1360712/72178
ks1322

La respuesta de Joshua debe ser la respuesta aceptada. Esta publicación de stackoverflow es el primer enlace de Google para esta pregunta, ¡da la respuesta correcta a Internet!
Jérôme

Respuestas:


272

Acabo de descubrir que si sus cambios no comprometidos se agregan al índice (es decir, "en etapas", usando git add ...), entonces git stash apply(y, presumiblemente, git stash pop) realmente se fusionará correctamente. Si no hay conflictos, eres de oro. De lo contrario, resuélvalos como de costumbre git mergetoolo manualmente con un editor.

Para ser claros, este es el proceso del que estoy hablando:

mkdir test-repo && cd test-repo && git init
echo test > test.txt
git add test.txt && git commit -m "Initial version"

# here's the interesting part:

# make a local change and stash it:
echo test2 > test.txt
git stash

# make a different local change:
echo test3 > test.txt

# try to apply the previous changes:
git stash apply
# git complains "Cannot apply to a dirty working tree, please stage your changes"

# add "test3" changes to the index, then re-try the stash:
git add test.txt
git stash apply
# git says: "Auto-merging test.txt"
# git says: "CONFLICT (content): Merge conflict in test.txt"

... que es probablemente lo que estás buscando.


tl; dr

Corre git addprimero.


8
Tal truco, pero bueno, funciona y parece ser la única forma de hacerlo. Desearía que hubiera git stash apply --forceo algo.
Matt Kantor

13
En realidad, no es un truco, es una mejora sobre lo que desea, ya que puede volver fácilmente a los cambios en el índice.
hoffmanc

2
Wow, ¿este comportamiento es realmente intencionado por git?
edi9999

9
No creo que haya algo "intentado" por git. Mi presentimiento es que todo lo que Git hace lo hace por casualidad.
Profpatsch

55
Esta es la solución perfecta. Simplemente lo hice git add ., git stash applyluego git resetaplicar el alijo a mis cambios de trabajo y fusionarme sin tener que hacer commits.
Stephen Smith

70

Correr git stash popo git stash applyes esencialmente una fusión. No debería haber necesitado confirmar sus cambios actuales a menos que los archivos modificados en el alijo también se modifiquen en la copia de trabajo, en cuyo caso habría visto este mensaje de error:

error: Your local changes to the following files would be overwritten by merge:
       file.txt
Please, commit your changes or stash them before you can merge.
Aborting

En ese caso, no puede aplicar el alijo a sus cambios actuales en un solo paso. Puede confirmar los cambios, aplicar el alijo, confirmar de nuevo y aplastar esos dos compromisos git rebasesi realmente no desea dos compromisos, pero eso puede ser más problema de lo que vale.


1
Recibí ese mensaje: los cambios no entran en conflicto, pero comparten los mismos archivos, ¿alrededor de usar stashes / apply's?
Bemis

1
Lo siento, eso es lo que quise decir con "fusionar conflictos", pero esa fue una mala elección de palabras. Creo que el mensaje de error es bastante final: si los archivos cambiados en la copia de trabajo también se cambian en el alijo, no puede aplicar el alijo. He actualizado mi respuesta con una posible solución.
Brandan

3
No consideraría esto una respuesta en todos los casos. Es posible que haya ocultado solo una parte de un conjunto de cambios en un archivo específico porque quería probar algo durante el desarrollo. Y es posible que no desee confirmar el contenido actual del archivo en este momento (o nada) ya que es WIP. Es un problema real con git que los cambios escondidos no se pueden combinar en su rama actual
Thomas Watson,

21
La respuesta de Joshua Warner debe ser la marcada como correcta. Para fusionar un alijo, organice sus cambios, aplique el alijo, lidie con cualquier conflicto y luego (si lo desea) desarme sus cambios.
Vroo

44
"Puede confirmar los cambios, aplicar el alijo, comprometerse nuevamente y aplastar esos dos commits usando git rebase si realmente no desea dos commits, pero eso puede ser más problema de lo que vale". En lugar de esto, podría hacer: Confirmar los cambios, aplicar el alijo y luego git commit --amend.
gabe

27

Lo que quiero es una forma de fusionar mis cambios escondidos con los cambios actuales

Aquí hay otra opción para hacerlo:

git stash show -p|git apply
git stash drop

git stash show -pmostrará el parche del último alijo guardado. git applylo aplicará Una vez realizada la fusión, se puede soltar el alijo fusionado git stash drop.


1
Gracias por esto - No sé por qué git stash popno solo hace esto en casos donde la fusión se aplica limpiamente ...
Iguananaut

Versión extendida: git stash show -p --no-color | git apply --3way( --3way= recurrir a la fusión de 3 vías si falla el parche).
DmitrySandalov

Pero git stash show -pcrea una diferencia entre el contenido oculto y la confirmación cuando se creó por primera vez la entrada oculta . Por lo tanto, esto sobrescribiría los cambios en el archivo de trabajo que realizó el OP.
Paul F. Wood

¿Por qué sobrescribir? El diff producido con git stash show -pserá fusionado por git apply, si es posible hacerlo sin conflictos.
ks1322

1

La forma en que hago esto es a git addesto primero git stash apply <stash code>. Es la forma más simple.


44
¿Cómo es que esto no es una copia exacta de la respuesta aceptada?
RomainValeri

0

Según lo sugerido por @Brandan, esto es lo que necesitaba hacer para desplazarme

error: Your local changes to the following files would be overwritten by merge:
       file.txt
Please, commit your changes or stash them before you can merge.
Aborting

Sigue este proceso:

git status  # local changes to `file`
git stash list  # further changes to `file` we want to merge
git commit -m "WIP" file
git stash pop
git commit -m "WIP2" file
git rebase -i HEAD^^  # I always use interactive rebase -- I'm sure you could do this in a single command with the simplicity of this process -- basically squash HEAD into HEAD^
# mark the second commit to squash into the first using your EDITOR
git reset HEAD^

Y se quedará con cambios locales totalmente fusionados para file, listo para hacer más trabajo / limpieza o hacer una buena confirmación. O, si sabe que el contenido combinado de fileserá correcto, podría escribir un mensaje apropiado y omitirlo git reset HEAD^.


0

Puede ser, no es la peor idea fusionarse (a través de difftool) de ... sí ... ¡una rama!

> current_branch=$(git status | head -n1 | cut -d' ' -f3)
> stash_branch="$current_branch-stash-$(date +%yy%mm%dd-%Hh%M)"
> git stash branch $stash_branch
> git checkout $current_branch
> git difftool $stash_branch

0

tu puedes fácilmente

  1. Compromete tus cambios actuales
  2. Libera tu alijo y resuelve conflictos
  3. Confirmar cambios desde el alijo
  4. Restablecimiento parcial para confirmar de dónde viene (última confirmación correcta)

-1

Otra opción es hacer otro "git stash" de los cambios locales no comprometidos, luego combinar los dos git stashes. Desafortunadamente, git parece no tener una manera de combinar fácilmente dos escondites. Entonces, una opción es crear dos archivos .diff y aplicarlos a ambos, por lo menos no es una confirmación adicional y no implica un proceso de diez pasos: |

Cómo: https://stackoverflow.com/a/9658688/32453


Convierte el problema de aplicar un diff en un problema de aplicar dos diffs. Además, la solución aceptada no implica una confirmación, solo una etapa, y es solo un comando (git add). (No soy el votante negativo.)
Eike

Para mí al menos se siente más simple, menos magia vudú ... ¡salud!
rogerdpack
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.