untracked stash name files git git-stash

stash - ¿Guardar automáticamente cambios guardados/pop en git rebase?



git stash untracked files (5)

mi flujo de trabajo git utiliza rebase mucho. Siempre recojo los cambios en sentido ascendente (el repositorio principal desde el que se bifurcó) y luego me fusiono con mis sucursales, y luego rebase para eliminar inútiles (para mí: D) fusionar confirmaciones y divisiones de árboles.

Una cosa en este flujo de trabajo que me molesta es:

$ git rebase upstream/master Cannot rebase: You have unstaged changes. Please commit or stash them. $ git stash Saved working directory and index state WIP on cc: abc1234 Merge remote-tracking branch ''upstream/master'' into local_branch HEAD is now at abc1234 Merge remote-tracking branch ''upstream/master'' into local_branch $ git rebase upstream/master First, rewinding head to replay your work on top of it... Applying: awesome code change $ git stash pop

así que aquí tenemos 4 comandos, 1 = rebase fallido, 2 = stash, 3 = rebase, 4 = stash pop. Cualquier cosa menos 3 es solo un trabajo sin sentido.

Entonces, la pregunta es: ¿Cuál es la forma más recomendada de automatizarlo? un alias para ejecutar git stash / rebase / pop cada vez? ¿Alguna configuración de git que obliga a rebase a esconderse o tratarlo como otro compromiso para volver a aplicar después? ¿algo más?


Edición: a partir de la versión 1.8.4 de Git, pero con un error secundario importante corregido en la versión 2.0.1 de Git, ahora git rebase tiene --autostash . También puede configurar git rebase para usar --autostash de forma predeterminada, con git config --global rebase.autoStash true . Tenga en cuenta la siguiente oración de la documentación :

Sin embargo, úselo con cuidado: la aplicación de almacenamiento final después de una reconfiguración exitosa podría resultar en conflictos no triviales.

(Sigo prefiriendo solo hacer confirmaciones).

TL; respuesta de DR: simplemente haga un compromiso (luego deséchelo más tarde)

Puede ayudarlo a darse cuenta de que el git stash es realmente git commit (en una forma más complicada, que primero ejecuta el índice, luego el árbol de trabajo). Cuando aplica un alijo, puede mantener la separación entre el índice y el árbol de trabajo. , o combinarlos en solo un cambio de arbol de trabajo).

Lo que hace que un escondite sea especial es que las confirmaciones que realiza (las dos o, con -u o -a , incluso tres confirmaciones) se realizan de forma inusual (como una confirmación de fusión que no es realmente una fusión) y no se colocan en ninguna rama (en cambio, la refs/stash especial refs/stash se usa para retener y encontrarlos).

Como no están en una rama, la rebase no los toca, y en su flujo de trabajo, es el git stash pop que trae los cambios del árbol de trabajo a su nuevo árbol de trabajo. Sin embargo, si realiza su propio compromiso (normal), en una rama, y ​​rebase e incluye ese compromiso, este compromiso normal se volverá a basar junto con cualquier otro. Llegaremos a un último problema en un momento; por ahora, dibujemos esto, como una serie de confirmaciones que se vuelven a basar:

... do some work ... ... make some commits ... ... more work ... ... do something that causes upstream/master to update, such as git fetch upstream $ git stash

En este punto, esto es lo que tienes:

... - o - * - A - B - C <-- HEAD=master / |/ / i-w <-- stash / @-@-@ <-- upstream/master

Aquí, A , B y C son tus confirmaciones (asumiré que has hecho 3), todas en el master sucursal. El iw cuelga de commit C es su alijo, que no se encuentra en la sucursal, pero sigue siendo un "gash stash bag" de doble commit y está adjunto a su último commit ( C ). Los @comites (puede haber solo uno) son los nuevos confirmaciones anteriores.

(Si no ha realizado ninguna confirmación, su bolsa de alijo se bloquea de la confirmación * , y su rama actual apunta a la confirmación * , por lo que git rebase no tiene trabajo que hacer más que mover el puntero de su rama actual hacia adelante. Todo funciona de la misma manera, en este caso, pero asumiré que hay algunos compromisos.)

Ahora ejecuta git rebase upstream/master . Esto copia sus confirmaciones a nuevas confirmaciones, con nuevas identificaciones y nuevas identificaciones principales, para que se coloquen encima de la última @ . El stash-bag no se mueve, por lo que el resultado se ve así:

... - o - * - A - B - C [abandoned, except for the stash] / |/ / i-w <-- stash / @-@-@ <-- upstream/master / A''-B''-C'' <-- HEAD=master

Ahora usas git stash pop , que restaura las cosas de i / w a medida que cambian los árboles de trabajo, borrando la etiqueta de stash (más precisamente, haciendo estallar para que stash@{1} , si existe, ahora sea stash , etc.) . Eso libera las últimas referencias a la cadena original A - B - C , y significa que tampoco necesitamos el bit iw , lo que nos permite volver a dibujar esto como mucho más simple:

... - @ <-- upstream/master / A''-B''-C'' <-- HEAD=master plus work tree changes

Ahora dibujemos lo que sucede si, en lugar de git stash save , solo haces un git commit -a (o git add y git commit sin -a) para crear un commit real D Empiezas con:

... - o-*-A-B-C-D <-- HEAD=master / @-@-@ <-- upstream/master

Ahora git rebase upstream/master , que copia de A a D para git rebase upstream/master al final de la última @ , y tiene esto:

... - o-*-@-@-@ <-- upstream/master / A''-B''-C''-D'' <-- HEAD=master

El único problema es que tiene este compromiso adicional D no deseado (bueno, D'' ahora), en lugar de cambios no comprometidos en el árbol de trabajo. Pero esto es trivialmente deshecho con git reset para retroceder un commit. Podemos usar un reinicio --mixed (el valor predeterminado) para restablecer también el índice (área de --mixed ), a fin de "quitar-agregar" todos los archivos, o si desea que permanezcan git add , un --soft reset. (Ninguno afecta al gráfico de confirmación resultante, solo el estado del índice es diferente).

git reset --mixed HEAD^ # or leave out `--mixed` since it''s the default

Esto es lo que parece:

... - o-*-@-@-@ <-- upstream/master / A''-B''-C'' <-- HEAD=master / D'' [abandoned]

Puedes pensar que esto es ineficiente, pero cuando usas git stash estás haciendo al menos dos confirmaciones, que luego abandonas cuando haces git stash pop . La verdadera diferencia es que al hacer confirmaciones temporales, no para publicación, se vuelven a clasificar automáticamente.

No tengas miedo de los compromisos temporales.

Hay una regla general con git: hacer muchos compromisos temporales, para guardar tu trabajo a medida que avanzas. Siempre puedes rebaselas más tarde. Es decir, en lugar de esto:

... - * - A - B - C <-- mybranch

donde A , B y C son confirmaciones perfectas y finales sobre comillas * (de otra persona o material publicado anteriormente), haga esto:

... - * - a1 - a2 - b1 - a3 - b2 - a4 - b3 - c1 - b4 - c2 - c3

donde a1 es una puñalada inicial en A , a2 corrige un error en a1 , b1 es un intento inicial de hacer que b funcione, a3 se da cuenta de que b1 requiere que A sea ​​diferente después de todo, b2 corrige un error en b1 , a4 corrige a error en el cambio de a3 a a2 , y b3 es lo que b1 debería haber hecho; entonces c1 es un intento inicial en C , b4 es otra solución para b1 , c2 es un refinamiento, y así sucesivamente.

Digamos que después de c3 piensas que está casi listo. Ahora ejecuta git rebase -i origin/master o lo que sea, mezcle las líneas de pick para poner orden de a1 a4 en orden, de b1 a b4 en orden, y de c1 a c3 en orden, y deje correr la rebase. Luego arreglas cualquier conflicto y te aseguras de que las cosas sigan siendo correctas, luego ejecutas otro git rebase -i para colapsar las cuatro versiones en A , y así sucesivamente.

Cuando hayas terminado, parece que creaste una A perfecta la primera vez (o tal vez con a4 o alguna otra, dependiendo de los compromisos que mantengas y de cuáles abandonas y si vuelves a configurar las marcas de tiempo en las cosas) . Es posible que otras personas no quieran o necesiten ver su trabajo intermedio, aunque puede retenerlo, no combinar las confirmaciones, si eso es útil. Mientras tanto, nunca necesitas tener cosas no comprometidas que debas reabastecer, porque solo tienes confirmaciones de cosas parciales.

Ayuda a dar estos nombres de confirmación, en el texto de confirmación de una línea, que guiará su trabajo posterior de rebase:

git commit -m ''temp commit: work to enable frabulator, incomplete''

y así.


Puede usar una herramienta externa llamada git-up , que hace exactamente lo que dice para todas las sucursales. Esto también te ayudará a mantener un gráfico de historial limpio.

Lo he usado durante algunos años y funciona bastante bien, especialmente si no eres un experto en git. Si agrega la función de rebasado automático, debe saber cómo recuperarse correctamente de una rebase fallida (continuar, abortar, ...)

Instalar

Abra un shell y ejecute:

sudo gem install git-up

Configuración

Abra su archivo de configuración global ( ~/.gitconfig ), y agregue lo siguiente:

[git-up "fetch"] all = true # up all branches at once, default false prune = true # prune deleted remote branches, default false [git-up "rebase"] # recreate merges while rebasing, default: unset arguments = --preserve-merges # uncomment the following to show changed commit on rebase # log-hook = "git --no-pager log --oneline --color --decorate $1..$2"

Consulte la documentación oficial para más opciones.

Invocación

Si todo está bien configurado, simplemente ejecuta:

git up

Esto es (aproximadamente) equivalente a ejecutar lo siguiente:

git stash git fetch --all [foreach branch] git rebase --preserve-merges <branch> <remote>/<branch> git merge --ff-only <branch> [end foreach] git checkout <prev_branch> git stash pop


Respuesta de tjsingleton blogg

hacer un alias de comando de:

git stash && git pull --rebase && git stash pop

actualizar

Si está utilizando la idea, presionando con un directorio de trabajo sucio, se abrirá un cuadro de diálogo, elija volver a generar / fusionar, hará un alijo, rebase / fusionará y se abrirá automáticamente.


Todo el flujo de trabajo en un comando, incluida la recuperación:

git pull --rebase --autostash [...]


Una respuesta simple: git rebase -i --autosquash --autostash <tree-ish>

-i = interactively rebase

https://devdocs.io/git/git-rebase

Esta voluntad...

  • Auto esconder tus cambios
  • Rebase interactiva de <tree-ish>
    • Auto posiciona tus squashes y arreglos
  • Auto pop stash en el directorio de trabajo después de rebase

tree-ish puede ser un hash de confirmación o un nombre de rama o una etiqueta o cualquier identificador .