modificados - ¿Guardar solo un archivo de varios archivos que han cambiado con Git?
ignorar cambios git (27)
¿Cómo puedo guardar solo uno de los múltiples archivos modificados en mi rama?
Respuesta rápida
Para revertir un archivo modificado específico en git, puedes hacer la siguiente línea:
git checkout <branch-name> -- <file-path>
Aquí hay un ejemplo real:
git checkout master -- battery_monitoring/msg_passing.py
Solución
Cambios locales:
- file_A (modificado) no en escena
- file_B (modificado) no en escena
- file_C (modificado) no en escena
Para crear un stash "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.
Explicación
- añadir file_C al área de preparación
- cree un alijo temporal llamado "temp_stash" y mantenga los cambios en file_C
- cree el alijo deseado ("my_stash") con solo los cambios en file_C
- aplique los cambios en "temp_stash" (archivo_A y archivo_B) en su código local y elimine el alijo
Puedes usar el estado de git entre los pasos para ver qué está pasando.
A veces he realizado un cambio no relacionado en mi rama antes de haberlo realizado, y quiero moverlo a otra rama y cometerlo 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 puede eliminar el primer stash
& stash pop
, puede llevar todos sus cambios a la rama master
cuando realiza el proceso de pago, pero solo si no hay conflictos. Además, si está creando una nueva rama para los cambios parciales, necesitará el alijo.
Puede simplificarlo asumiendo que no hay conflictos y no hay una nueva rama:
git checkout master
git add <files that you want to commit>
git commit -m ''Minor feature''
git checkout topic1
...<resume work>...
Stash ni siquiera es necesario ...
Actualización (14/02/2015) - He reescrito el script un poco, para manejar mejor el caso de conflictos, que ahora deberían presentarse como conflictos no combinados en lugar de archivos .rej.
A menudo me parece más intuitivo hacer lo inverso al enfoque de @ bukzor. Es decir, para realizar algunos cambios y luego esconder solo los cambios en etapas.
Desafortunadamente, git no ofrece un alijo de git - solo índice o similar, así que hice 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 git-stash-index
algún lugar de su ruta, y luego puede 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 programado, y su árbol de trabajo aún contiene cambios no programados.
En algunos casos, los cambios en el árbol de trabajo pueden depender de los cambios en el índice, por lo que cuando se ocultan los cambios en el índice, los cambios en el árbol de trabajo tienen un conflicto. En este caso, obtendrá los conflictos no combinados habituales que puede resolver con git merge / git mergetool / etc.
Cada respuesta aquí es tan complicada ...
¿Qué hay de 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 que el archivo cambie de nuevo:
git apply /tmp/stash.patch
Exactamente el mismo comportamiento que esconder un archivo y volver a insertarlo.
Cuando git stash -p
(o git add -p
con stash --keep-index
) sería demasiado engorroso, me resultó más fácil usar diff
, checkout
y apply
:
Para "esconder" un archivo / directorio en particular solamente:
git diff path/to/dir > stashed.diff
git checkout path/to/dir
Luego despues
git apply stashed.diff
Cuando intenta cambiar entre dos ramas, se produce esta situación.
Intenta agregar los archivos usando " git add filepath
".
Mas tarde ejecuta esta linea
git stash --keep-index
Dado que crear sucursales en Git es trivial, puedes crear una sucursal temporal y revisar los archivos individuales en ella.
Dado que git se basa fundamentalmente en la gestión de un contenido e índice de todo el repositorio (y no uno o varios archivos), git stash
trata, como es lógico, con todo el directorio de trabajo .
En realidad, desde Git 2.13 (Q2 2017), puede esconder archivos individuales, con git stash push
:
git stash push [--] [<pathspec>...]
Cuando se
pathspec
a ''git stash push
'', el nuevo stash registra los estados modificados solo para los archivos que coinciden con el pathspec
Consulte " Cambios ocultos en archivos específicos " para obtener más información.
El caso de prueba se explica por sí mismo:
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 esconder.
Casebash comenta:
Esta (la solución original de
stash --patch
) es buena, pero a menudo he modificado muchos archivos, por lo que usar el parche es molesto
La answer bukzor (upvoted, noviembre de 2011) sugiere una solución más práctica, basada en
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).
Acerca de esa opción, chhh señala un flujo de trabajo alternativo en los comentarios:
debe "
git reset --soft
" después de tal escondite para recuperar su clara puesta en escena:
Para llegar al estado original, que es un área de almacenamiento clara y con solo algunas modificaciones no programadas seleccionadas, uno podría restablecer suavemente el índice para obtener (sin cometer nada como usted - bukzor - lo hizo).
(Respuesta original de junio de 2010: alijo manual)
Sin embargo, git stash save --patch
podría permitirte lograr el ocultamiento parcial que buscas:
Con
--patch
, puede seleccionar de forma interactiva trozos en la diferencia entre HEAD y el árbol de trabajo que se va a esconder.
La entrada de alijo se construye de tal manera que su estado de índice es el mismo que el estado de índice de su repositorio, y su área de trabajo contiene solo los cambios que seleccionó de manera interactiva. Los cambios seleccionados se retrotraen 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 esconder).
git stash --patch --no-keep-index
podría ser un mejor ajuste.
Si --patch
no funciona, un proceso manual podría:
Para uno o varios archivos, una solución intermedia sería:
- copiarlos fuera del repositorio de Git
(En realidad, eleotlecram propone una alternativa interesante ) -
git stash
- copiarlos de nuevo
-
git stash
# esta vez, solo se guardan los archivos que desea -
git stash pop stash@{1}
# vuelve a aplicar todas las modificaciones de tus archivos -
git checkout -- afile
# restablece el archivo al contenido HEAD, antes de realizar modificaciones locales
Al final de ese proceso bastante engorroso, solo tendrá uno o varios archivos ocultos.
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.
El problema con la solución ''intermedia'' de VonC de copiar archivos fuera del repositorio de Git es que se pierde información de ruta, lo que hace que copiar un montón de archivos más tarde sea una molestia.
A encontrarlo es más fácil de usar tar (probablemente herramientas similares) en lugar de copiar:
- tar cvf /tmp/stash.tar path / to / some / file path / to / some / other / file (... etc.)
- git checkout ruta / a / algo / archivo ruta / a / algo / otro / archivo
- git stash
- tar xvf /tmp/stash.tar
- etc. (vea la sugerencia ''intermedia'' de VonC)
En caso de que realmente signifique descartar los cambios cada vez que use git stash
(y no use realmente git stash para esconderlo temporalmente), en ese caso puede usar
git checkout -- <file>
[ NOTA ]
Ese git stash
es solo una alternativa más rápida y simple a bifurcar y hacer cosas.
En esta situación, git add -p
(interactivo), git commit -m blah
y luego guardo lo que queda si es necesario.
Esto se puede hacer fácilmente en 3 pasos usando SourceTree.
- Temporalmente cometer todo lo que no quieres escondido.
- Git agregar todo lo demás, luego esconderlo.
- Despliegue su confirmación temporal ejecutando git reset, dirigiéndose a la confirmación antes de la temporal.
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 agregados, simplemente comprométalos a un compromiso temporal. A continuación, haga clic en la casilla de verificación para agregar todos los cambios, luego haga clic en Stash para esconder todo. Con los cambios ocultos fuera del camino, eche un vistazo a su lista de confirmación y anote 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 reiniciando su rama en el cometer justo antes de ello. Ahora, te quedas con las cosas que no querías que se escondieran.
Guarde el siguiente código en un archivo, por ejemplo, denominado stash
. El uso es stash <filename_regex>
. El argumento es la expresión regular para la ruta completa del archivo. Por ejemplo, para esconder un / b / c.txt, stash a/b/c.txt
o un 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
}
}
}
He revisado respuestas y comentarios para esto y una serie de hilos similares. Tenga en cuenta que ninguno de los siguientes comandos es correcto con el fin de poder esconder ningún archivo rastreado / no rastreado específico :
-
git stash -p (--patch)
: selecciona hunks manualmente, excluyendo archivos no rastreados -
git stash -k (--keep-index)
: guarda todos los archivos rastreados / no rastreados y los guarda en el directorio de trabajo -
git stash -u (--include-untracked)
: guarda todos los archivos rastreados / no rastreados -
git stash -p (--patch) -u (--include-untracked)
: comando inválido
Actualmente, el método más razonable para poder esconder cualquier archivo rastreado / no rastreado específico es:
- Confirma temporalmente los archivos que no quieres esconder
- Añadir y esconder
- Pop el compromiso temporal
Escribí un script simple para este procedimiento en una respuesta a otra pregunta , y hay pasos para realizar el procedimiento en SourceTree aquí .
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 esconde exactamente un archivo.
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 fragmento en el archivo B y dejar todo lo demás intacto, haga lo siguiente:
- Poner en escena todo
- Realice los cambios a su copia de trabajo que deshace todos los cambios en el archivo A. (por ejemplo, inicie la herramienta de diferencias externas y haga coincidir los archivos).
- Haga que el archivo B se vea como si solo se le aplicara un segundo cambio. (Ej. lanzar la herramienta de diferencias externas y deshacer el primer cambio).
- Crea un alijo usando "Mantener cambios por etapas".
- Deshacer todo
- ¡Hecho!
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 primeras dos respuestas (la primera respuesta simplemente no responde la pregunta y no me gustó mucho trabajar con el modo interactivo -p
) .
La idea es la misma que lo que sugirió @VonC al usar archivos fuera del repositorio, usted guarda los cambios que desea en algún lugar, elimina los cambios que no desea en su alijo y luego vuelve a aplicar los cambios que eliminó. Sin embargo, utilicé el alijo de git como el "en algún lugar" (y como resultado, hay un paso adicional al final: eliminar las pilas que pusiste en el alijo, porque también las retiraste del camino).
Para esconder un solo archivo usa git stash --patch [file]
.
Esto va a aparecer: ¿ Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
. Simplemente escriba a
(esconda este trozo y todos los trozos posteriores en el archivo) y estará bien.
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
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 hunk:
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
Una forma complicada sería primero cometer todo:
git add -u
git commit // creates commit with sha-1 A
Restablecer de nuevo a la confirmación original, pero verifique the_one_file desde la nueva confirmación:
git reset --hard HEAD^
git checkout A path/to/the_one_file
Ahora puedes esconder el archivo
git stash
Para limpiar, guarde el contenido confirmado en su sistema de archivos y restablezca la confirmación original:
git reset --hard A
git reset --soft HEAD^
Sí, un poco incómodo ...
Usa git stash push
, como este:
git stash push [--] [<pathspec>...]
Por ejemplo:
git stash push -- my/file.sh
Esto está disponible desde Git 2.13, lanzado en la primavera de 2017.
Yo usaría git stash save --patch
. No encuentro que la interactividad sea molesta porque hay opciones para aplicar la operación deseada a archivos completos.
Advertencia
Como se señaló en los comentarios, esto pone todo en el escondite, tanto en escena como en ausencia. El índice de mantenimiento solo deja el índice solo después de que se haya hecho el alijo. Esto puede causar conflictos de combinación cuando más tarde se abre el alijo.
Esto guardará todo lo que no hayas agregado previamente. Simplemente git add
las cosas que desea conservar y luego ejecútelo.
git stash --keep-index
Por ejemplo, si desea dividir una confirmación antigua en más de un conjunto de cambios, puede utilizar este procedimiento:
-
git rebase -i <last good commit>
- Marque algunos cambios como
edit
. -
git reset HEAD^
-
git add <files you want to keep in this change>
-
git stash --keep-index
- Arregla las cosas como sea necesario. No olvides
git add
cualquier cambio. -
git commit
-
git stash pop
- Repita, desde el # 5, según sea necesario.
-
git rebase --continue
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)