¿Cómo puedo guardar solo uno de los múltiples archivos modificados en mi sucursal?
Descargo de responsabilidad : la siguiente respuesta es para git antes de git 2.13. Para git 2.13 y más, mira otra respuesta más abajo .
Advertencia
Como se señaló en los comentarios, esto pone todo en el alijo, tanto en escena como en escena. --Keep-index solo deja el índice solo después de que se realiza el escondite. Esto puede causar conflictos de fusión cuando más tarde revienta el alijo.
Esto esconderá todo lo que no haya agregado previamente. Solo git add
las cosas que desea conservar, luego ejecútelo.
git stash --keep-index
Por ejemplo, si desea dividir una confirmación anterior en más de un conjunto de cambios, puede utilizar este procedimiento:
git rebase -i <last good commit>
edit
.git reset HEAD^
git add <files you want to keep in this change>
git stash --keep-index
git add
ningún cambio.git commit
git stash pop
git rebase --continue
git stash save -k
, sí, el índice (entrada verde git stat
) se conserva, pero todo el conjunto de cambios (tanto verde como rojo) entra en el alijo. Esto viola la solicitud del OP, "esconder solo algunos cambios". Quiero esconder solo algunos de los rojos (para uso futuro).
git stash -p
es exactamente lo que estaba buscando Me pregunto si este interruptor se agregó recientemente.
git stash --keep-index
está roto. Si realiza más cambios, intente git stash pop
luego obtener conflictos de fusión porque el alijo incluye los archivos modificados que guardó, no solo los que no guardó. Por ejemplo: cambio los archivos A y B, luego oculto B, porque quiero probar los cambios en A; Encuentro un problema con A que luego soluciono; Yo cometo A; Ahora no puedo deshacerme porque una versión antigua de A está en el alijo sin ninguna buena razón causando un conflicto de fusión. En la práctica, A y B pueden ser muchos archivos, tal vez incluso imágenes binarias o algo así, básicamente tengo que rendirme y perder B.
También puedes usar git stash save -p "my commit message"
. De esta manera, puede seleccionar qué trozos se deben agregar al alijo, también se pueden seleccionar archivos completos.
Se te indicarán algunas acciones para cada trozo:
y - stash this hunk
n - do not stash this hunk
q - quit; do not stash this hunk or any of the remaining ones
a - stash this hunk and all later hunks in the file
d - do not stash this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
stash -p
. Otorgo esta respuesta porque sigue siendo la más interactiva / fácil de usar.
git stash save -p my stash message
:; ya que el orden de los argumentos no es muy intuitivo ...
git log -p
, creo que la -p
bandera debe significar "hacer lo genial que quiero pero no sé cómo expresarme".
Dado que git se trata fundamentalmente de administrar un contenido e índice de todo el repositorio (y no uno o varios archivos), las git stash
ofertas, no sorprendentemente,con todo el directorio de trabajo.
En realidad, desde Git 2.13 (Q2 2017), puede guardar archivos individuales con git stash push
:
git stash push [--] [<pathspec>...]
Cuando
pathspec
se le da a 'git stash push
', el nuevo alijo registra los estados modificados solo para los archivos que coinciden con la especificación de la ruta. Consulte " Cambios del alijo a archivos específicos " para obtener más información.
Ejemplo simplificado:
git stash push path/to/file
El caso de prueba para esta función muestra algunas opciones más desactivadas:
test_expect_success 'stash with multiple pathspec arguments' '
>foo &&
>bar &&
>extra &&
git add foo bar extra &&
git stash push -- foo bar &&
test_path_is_missing bar &&
test_path_is_missing foo &&
test_path_is_file extra &&
git stash pop &&
test_path_is_file foo &&
test_path_is_file bar &&
test_path_is_file extra
La respuesta original (a continuación, junio de 2010) fue sobre seleccionar manualmente lo que desea guardar.
CasebashComentarios de :
Este el
stash --patch
solución original) es buena, pero a menudo modifico muchos archivos, por lo que usar parche es molesto
bukzor 's respuesta (upvoted, noviembre de 2011) sugiere una solución más práctica, en base a
git add
+git stash --keep-index
.
Ve a ver y vota su respuesta, que debería ser la oficial (en lugar de la mía).
Sobre esa opción, chhh señala un flujo de trabajo alternativo en los comentarios:
deberías "
git reset --soft
" después de un alijo para recuperar tu puesta en escena clara:
para llegar al estado original, que es un área de puesta en escena clara y con solo algunas modificaciones seleccionadas sin puesta en escena, uno podría restablecer suavemente el índice para obtener (sin cometer algo como tú, bukzor, lo hizo).
(Respuesta original de junio de 2010: alijo manual)
Sin embargo, git stash save --patch
podría permitirte lograr el alijo parcial que buscas:
Con
--patch
, puede seleccionar interactivamente trozos en la diferencia entre HEAD y el árbol de trabajo que se va a guardar.
La entrada oculta se construye de manera tal que su estado de índice es el mismo que el estado de índice de su repositorio, y su árbol de trabajo contiene solo los cambios que seleccionó interactivamente. Los cambios seleccionados se revierten de su árbol de trabajo.
Sin embargo, eso guardará el índice completo (que puede no ser lo que desea, ya que podría incluir otros archivos ya indexados) y un árbol de trabajo parcial (que podría parecerse al que desea guardar).
git stash --patch --no-keep-index
podría ser una mejor opción.
Si --patch
no funciona, un proceso manual podría:
Para uno o varios archivos, una solución intermedia sería:
git stash
git stash
# esta vez, solo se guardan los archivos que deseasgit stash pop stash@{1}
# vuelve a aplicar todas las modificaciones de tus archivosgit checkout -- afile
# restablecer el archivo al contenido HEAD, antes de cualquier modificación localAl final de ese proceso bastante engorroso, solo tendrá uno o varios archivos escondidos.
git is fundamentally about managing a all repository content and index and not one or several files
- esa es la implementación que eclipsa el problema que se está resolviendo; Es una explicación, pero no una justificación. Cualquier sistema de control de fuente es sobre "administrar varios archivos". Solo mira qué comentarios son los más votados.
Cuando git stash -p
(o git add -p
con stash --keep-index
) sería demasiado engorroso, me resultó más fácil de usar diff
, checkout
yapply
:
Para "esconder" solo un archivo / directorio particular:
git diff path/to/dir > stashed.diff
git checkout path/to/dir
Luego después
git apply stashed.diff
git add -p
que mencioné en mi propia respuesta anterior. +1.
git diff > file.diff
y git apply
son mis herramientas habituales de escondite parcial. Puede que tenga que considerar cambiar a git stash -p
conjuntos de cambios más grandes.
patch = log --pretty=email --patch-with-stat --reverse --full-index --binary
. Sin embargo, tenga en cuenta que esto requiere que se confirmen los cambios para el parche.
../../foo/bar.txt
. El parche genera OK, pero luego necesito moverme a la raíz del repositorio para que se aplique el parche. Entonces, si tiene problemas con esto, solo asegúrese de hacerlo desde el directorio raíz del repositorio.
Uso git stash push
, así:
git stash push [--] [<pathspec>...]
Por ejemplo:
git stash push -- my/file.sh
Está disponible desde Git 2.13, lanzado en la primavera de 2017.
git stash push
ya mencioné en mi respuesta anterior el pasado marzo, hace 5 meses. Y detallé ese nuevo comando Git 2.13 aquí: stackoverflow.com/a/42963606/6309 .
git stash apply
para recuperar los cambios escondidos?
Digamos que tienes 3 archivos
a.rb
b.rb
c.rb
y desea guardar solo b.rb y c.rb pero no a.rb
puedes hacer algo como esto
# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp"
# then stash the other files
git stash save "stash message"
# then undo the previous temp commit
git reset --soft HEAD^
git reset
Y ya está! HTH
Otra forma de hacer esto:
# Save everything
git stash
# Re-apply everything, but keep the stash
git stash apply
git checkout <"files you don't want in your stash">
# Save only the things you wanted saved
git stash
# Re-apply the original state and drop it from your stash
git stash apply stash@{1}
git stash drop stash@{1}
git checkout <"files you put in your stash">
Se me ocurrió esto después de que (una vez más) llegué a esta página y no me gustaron las dos primeras respuestas (la primera respuesta simplemente no responde la pregunta y no me gustó mucho trabajar con el -p
modo interactivo).
La idea es la misma que lo que @VonC sugirió usar archivos fuera del repositorio: guarda los cambios que desea en algún lugar, elimina los cambios que no desea en su escondite y luego vuelve a aplicar los cambios que quitó del camino. Sin embargo, utilicé el escondite de git como "en alguna parte" (y como resultado, hay un paso adicional al final: eliminar los depósitos que colocaste en el escondite, porque también los quitaste del camino).
Actualización (14/02/2015) - Reescribí el script un poco, para manejar mejor el caso de conflictos, que ahora deberían presentarse como conflictos no fusionados en lugar de archivos .rej.
A menudo me resulta más intuitivo hacer lo contrario del enfoque de @bukzor. Es decir, organizar algunos cambios y luego esconder solo esos cambios organizados.
Desafortunadamente, git no ofrece una reserva de git: solo index o similar, así que preparé un script para hacer esto.
#!/bin/sh
# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`
# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`
# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`
# get back to a clean state with no changes, staged or otherwise
git reset -q --hard
# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash
# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT
CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
# If there are no conflicts, it's safe to reset, so that
# any previously unstaged changes remain unstaged
#
# However, if there are conflicts, then we don't want to reset the files
# and lose the merge/conflict info.
git reset -q
fi
Puede guardar el script anterior como en git-stash-index
algún lugar de su ruta y luego invocarlo como git stash-index
# <hack hack hack>
git add <files that you want to stash>
git stash-index
Ahora el alijo contiene una nueva entrada que solo contiene los cambios que había organizado, y su árbol de trabajo aún contiene los cambios no organizados.
En algunos casos, los cambios del árbol de trabajo pueden depender de los cambios del índice, por lo que cuando oculta los cambios del índice, los cambios del árbol de trabajo tienen un conflicto. En este caso, obtendrá los conflictos no fusionados habituales que puede resolver con git merge / git mergetool / etc.
pushd
lugar de cd
y popd
al final del script, de modo que si el script tiene éxito, el usuario termina en el mismo directorio que antes de ejecutarlo.
Si no desea especificar un mensaje con sus cambios escondidos, pase el nombre del archivo después de un doble guión.
$ git stash -- filename.ext
Si se trata de un archivo nuevo / sin seguimiento, primero deberá organizarlo.
Este método funciona en git versiones 2.13+
Dado que crear ramas en Git es trivial, puede crear una rama temporal y verificar los archivos individuales en ella.
Simplemente puedes hacer esto:
git stash push "filename"
o con un mensaje opcional
git stash push -m "Some message" "filename"
Guarde el siguiente código en un archivo, por ejemplo, llamado stash
. El uso es stash <filename_regex>
. El argumento es la expresión regular para la ruta completa del archivo. Por ejemplo, para guardar a / b / c.txt, stash a/b/c.txt
o stash .*/c.txt
, etc.
$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml
Código para copiar en el archivo:
#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]
spawn git stash -p
for {} 1 {} {
expect {
-re "diff --git a/($filename_regexp) " {
set filename $expect_out(1,string)
}
"diff --git a/" {
set filename ""
}
"Stash this hunk " {
if {$filename == ""} {
send "n\n"
} else {
send "a\n"
send_user "$filename\n"
}
}
"Stash deletion " {
send "n\n"
}
eof {
exit
}
}
}
En caso de que realmente quiera decir cambios de descarte cada vez que usa git stash
(y realmente no usa git stash para guardarlo temporalmente), en ese caso puede usar
git checkout -- <file>
[ NOTA ]
Esa git stash
es solo una alternativa más rápida y simple para ramificarse y hacer cosas.
El problema con la solución `` intermedia '' de VonC de copiar archivos al exterior del repositorio de Git es que pierde la información de ruta, lo que hace que copiar un montón de archivos más tarde sea una molestia.
A resulta más fácil usar tar (herramientas similares probablemente lo harán) en lugar de copiar:
checkout -f
no es necesario, checkout
(sin -f
) es suficiente, he actualizado la respuesta.
A veces he realizado un cambio no relacionado en mi rama antes de comprometerlo, y quiero moverlo a otra rama y confirmarlo por separado (como maestro). Hago esto:
git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...
Tenga en cuenta que lo primero stash
y stash pop
puede eliminarse, puede llevar todos sus cambios a la master
sucursal cuando realice el pago, pero solo si no hay conflictos. Además, si está creando una nueva rama para los cambios parciales, necesitará el alijo.
Puede simplificarlo suponiendo que no haya conflictos ni una nueva rama:
git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...
El escondite ni siquiera es necesario ...
Esto se puede hacer fácilmente en 3 pasos usando SourceTree.
Todo esto se puede hacer en cuestión de segundos en SourceTree, donde puede hacer clic en los archivos (o incluso en las líneas individuales) que desea agregar. Una vez agregado, simplemente compromételos a una confirmación temporal. Luego, haga clic en la casilla de verificación para agregar todos los cambios, luego haga clic en esconder para guardar todo. Con los cambios ocultos fuera del camino, eche un vistazo a su lista de confirmación y observe el hash para la confirmación antes de su confirmación temporal, luego ejecute 'git reset hash_b4_temp_commit', que es básicamente como "hacer estallar" la confirmación restableciendo su rama al comprometerse justo antes de eso. Ahora, te quedan solo las cosas que no querías guardar.
Me gustaría utilizar git stash save --patch
. No creo que la interactividad sea molesta porque hay opciones durante la misma para aplicar la operación deseada a archivos completos.
git stash -p
permite guardar un archivo completo rápidamente y salir después.
Cada respuesta aquí es tan complicada ...
¿Qué pasa con esto para "esconder":
git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash
Esto para hacer estallar el cambio de archivo:
git apply /tmp/stash.patch
Exactamente el mismo comportamiento que guardar un archivo y volverlo a colocar.
git apply
tengo ningún error, pero los cambios tampoco se devuelven
He revisado las respuestas y comentarios para esto y una serie de hilos similares. Tenga en cuenta que ninguno de los siguientes comandos son correctos con el fin de poder ocultar cualquier archivo específico rastreado / no rastreado :
git stash -p (--patch)
: seleccione trozos manualmente, excluyendo archivos no rastreadosgit stash -k (--keep-index)
: esconde todos los archivos rastreados / no rastreados y mantenlos en el directorio de trabajogit stash -u (--include-untracked)
: esconde todos los archivos rastreados / no rastreadosgit stash -p (--patch) -u (--include-untracked)
: comando inválidoActualmente, el método más razonable para poder almacenar cualquier archivo específico rastreado / no rastreado es:
Escribí un script simple para este procedimiento en una respuesta a otra pregunta , y aquí hay pasos para realizar el procedimiento en SourceTree .
Cambios locales:
Para crear un alijo "my_stash" con solo los cambios en file_C :
1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop stash@#{1}
Hecho.
Puede usar el estado de git entre los pasos para ver qué está sucediendo.
Cuando intenta cambiar entre dos ramas, se produce esta situación.
Intente agregar los archivos usando " git add filepath
".
Más tarde ejecuta esta línea
git stash --keep-index
Para guardar un solo archivo, use git stash --patch [file]
.
Esto va a indicador: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
. Simplemente escriba a
(guarde este trozo y todos los trozos posteriores en el archivo) y estará bien.
push
como engit stash push --patch [file]
Situación similar. Se comprometió y se dio cuenta de que no está bien.
git commit -a -m "message"
git log -p
Basado en las respuestas esto me ayudó.
# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push
En esta situación, yo git add -p
(interactivo), git commit -m blah
y luego guardo lo que queda si es necesario.
No sé cómo hacerlo en la línea de comandos, solo usando SourceTree. Digamos que ha cambiado el archivo A y tiene dos cambios en el archivo B. Si desea guardar solo el segundo trozo en el archivo B y dejar todo lo demás intacto, haga lo siguiente:
git add . //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash //stash the file(s)
git reset . // unstage all staged files
git stash pop // unstash file(s)
Una forma complicada sería primero comprometer todo:
git add -u
git commit // creates commit with sha-1 A
Restablezca la confirmación original pero revise the_one_file desde la nueva confirmación:
git reset --hard HEAD^
git checkout A path/to/the_one_file
Ahora puedes esconder el_un_archivo:
git stash
Limpie guardando el contenido confirmado en su sistema de archivos mientras restablece la confirmación original:
git reset --hard A
git reset --soft HEAD^
Sí, algo incómodo ...
No encontré ninguna respuesta para ser lo que necesitaba y eso es tan fácil como:
git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash
Esto oculta exactamente un archivo.
Para revertir un archivo modificado específico en git, puede hacer la siguiente línea:
git checkout <branch-name> -- <file-path>
Aquí hay un ejemplo real:
git checkout master -- battery_monitoring/msg_passing.py
Si desea guardar algunos archivos modificados, simplemente
Agregue los archivos que no desea guardar, en el escenario , luego ejecute
git stash save --keep-index
Guardará todos los archivos modificados sin clasificar
git stash --keep-index
mantiene el índice, pero oculta todo , tanto dentro como fuera del índice.git diff -- *filename* > ~/patch
luegogit checkout -- *filename*
y luego puede volver a aplicar el parche congit apply ~/patch
git stash push [--] [<pathspec>...]
.