Git comando para guardar un alijo sin modificar el árbol de trabajo?


He estado queriendo usar un comando git que guarda un alijo sin modificar mi árbol de trabajo, como una copia de seguridad ligera que está a salvo de cualquier reinicio de git o lo que sea que pueda hacer para arruinar mi índice. Básicamente el equivalente funcional de "git stash save & & git stash apply", excepto que la copia de trabajo nunca se toca, ya que esto puede hacer que ciertos editores de texto/IDE estén malhumorados.

Algo como esto se acerca a lo que quiero, pero no del todo:

git update-ref refs/stash `git stash create "Stash message"`

Esto funciona funcionalmente, pero el problema que estoy teniendo es que ningún mensaje de stash aparece en "git stash list" a pesar de que la confirmación de stash real tiene mi mensaje en ella. Teniendo en cuenta lo grande que puede llegar a ser un alijo, los mensajes de alijo son bastante importantes.

Author: Eliot, 2011-06-11

3 answers

Gracias al consejo de Charles, preparé un script bash para hacer exactamente lo que quería (me estaba topando con problemas implementando esto solo como un alias). Toma un mensaje de stash opcional al igual que git stash save. Si no se proporciona ninguno, utilizará el mensaje predeterminado generado por git stash.

#!/bin/sh
#
# git-stash-snap
# Save snapshot of working tree into the stash without modifying working tree.
# First argument (optional) is the stash message.
if [ -n "$1" ]; then
        git update-ref -m "$1" refs/stash "$(git stash create \"$1\")"
else
        HASH=`git stash create`
        MESSAGE=`git log --no-walk --pretty="tformat:%-s" "$HASH"`
        git update-ref -m "$MESSAGE" refs/stash "$HASH"
fi

Editar: Como se señala en un comentario a continuación, guardar este script como git-stash-snap en algún lugar de su ruta es suficiente para poder invocarlo escribiendo git stash-snap.

Lo bueno aquí es que incluso si sueltas un stash hecho con este método, todavía podrás ver el mensaje de stash usando git log [commit-hash] de la confirmación colgando!

Editar: desde git 2.6.0 puedes agregar --create-reflog a update-ref y luego git stash list mostrará esto incluso si git stash no se usó antes.

Editar: Git ha introducido un nuevo subcomando de stash llamado stash push así que he actualizado mi recomendación para nombrar este script de git-stash-push a git-stash-snap.

 30
Author: Eliot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 17:43:54

Necesita pasar el mensaje a update-ref, no stash create ya que stash create no recibe un mensaje (no actualiza ninguna referencia, por lo que no tiene entrada de reflog para rellenar).

git update-ref -m "Stash message" refs/stash "$(git stash create)"
 12
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-11 11:11:21

Inspirado por la solución de Eliot, extendí su guión un poco:

#!/bin/sh
#
# git-stash-push
# Push working tree onto the stash without modifying working tree.
# First argument (optional) is the stash message.
#
# If the working dir is clean, no stash will be generated/saved.
#
# Options:
#   -c "changes" mode, do not stash if there are no changes since the
#      last stash.
if [ "$1" == "-c" ]; then
        CHECK_CHANGES=1
        shift
fi


if [ -n "$1" ]; then
        MESSAGE=$1
        HASH=$( git stash create "$MESSAGE" )
else
        MESSAGE=`git log --no-walk --pretty="tformat:%-s" "HEAD"`
        MESSAGE="Based on: $MESSAGE"
        HASH=$( git stash create )
fi

if [ "$CHECK_CHANGES" ]; then
        # "check for changes" mode: only stash if there are changes
        # since the last stash

        # check if nothing has changed since last stash
        CHANGES=$( git diff stash@{0} )
        if [ -z "$CHANGES" ] ; then
                echo "Nothing changed since last stash."
                exit 0
        fi
fi

if [ -n "$HASH" ]; then
        git update-ref -m "$MESSAGE" refs/stash "$HASH"
        echo "Working directory stashed."
else
        echo "Working tree clean, nothing to do."
fi

Implementé los siguientes cambios en el script de Eliot:

  1. Cuando el directorio de trabajo está limpio, el script saldrá con gracia
  2. Cuando se usa switch -c, si no hay cambios en comparación con el último stash, el script se cerrará. Esto es útil si utiliza este script como una "máquina del tiempo", haciendo un alijo automatizado cada 10 minutos. Si nada ha cambiado, no se crea ningún alijo nuevo. Sin esto cambiar, usted podría terminar con n escondites consecutivos que son los mismos.

No es que para que el switch -c funcione correctamente, al menos debe existir un stash, de lo contrario el script lanza un error en git diff stash@{0} y no hará nada.

Utilizo este script como una "máquina del tiempo", snapshot cada 10 minutos usando el siguiente bucle bash:

 while true ; do date ; git stash-push ; sleep 600 ; done
 3
Author: andimeier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-09 12:29:49