Volver al estado anterior a git stash – git

Pregunta:


Recientemente he descubierto que git stash pop no funciona como yo espero/deseo. git stash pop hace un merge entre el estado actual y lo que hay en el stash más reciente.

Me gustaría tener un comando o script que me devolviese al estado anterior a hacer git stash.

Es decir, hacer lo siguiente.

  1. Si el directorio de trabajo actual está sucio o si hay algo en la staging area mostrar un mensaje de error y parar.
  2. Hacer checkout del commit en que estaba en el último stash. Es decir del comit padre del último stash.
  3. git checkout la_rama_en_que_estaba_si_estaba_en_alguna
  4. git stash pop

El punto 3 es especialmente problemático porque git stash no guarda en que rama estabas. Con lo que me temo que no va a ser posible sin hacer otro script para un git stash alternativo. Con lo que acepto respuestas que no solventen este punto.

En bash lo anterior sería algo así:

#!/usr/bin/env bash
#1a directorio sucio
DIR_SUCIO=$(algunos_comandos)
if [ $DIR_SUCIO -ne 0 ]; then
  echo "El directorio actual está sucio"
  exit 1
fi
#1b staging area
STG_AREA=$(algunos_comandos)
if [ $STG_AREA -ne 0 ]; then
  echo "La área de staging no está vacía"
  exit 1
fi
#2 Obtener el commit necesario
COMMIT=$(algunos_comandos)
git checkout $COMMIT
#4 
git stash pop

Para 1a git status no sirve pues devuelve 0 tanto si el directorio está vacío como si no. Lo mismo sucede con 1b. Si no encuentro un comando apropiado voy a tener que recurrir a hacer parse de git status.
El punto 2 lo veo aún más difícil.

Preguntado por: Jose Antonio Dura Olmos

Para el primer paso uso tres comandos para comprobar :

  • Si hay cambios unstaged
  • Si hay cambios uncommited
  • Si hay cambios untracked

.

#!/usr/bin/env bash
git diff --exit-code > /dev/null 2>&1
if [ $? -ne 0 ]; then
  git status
  echo "Hay cambios unstaged" 
  exit 1
fi

git diff --cached --exit-code >/dev/null 2>&1
if [ $? -ne 0 ]; then
  git status
  echo "Hay cambios uncommited"
  exit 1
fi

untracked=$(git ls-files --others --exclude-standard --directory)
if [ a"$untracked" != a ]; then
  git status
  echo "Hay cambios untracked"
  exit 1
fi

Para el segundo paso [email protected]{0} es el último stash. Y una vez estamos ahí HEAD~1 es el commit desde el que se hizo ese stash.

git checkout [email protected]{0} >/dev/null 2>&1
if [ $? -ne 0 ]; then
  echo "No hay ningún stash para hacer pop"
  exit 1
fi

git checkout HEAD~1 >/dev/null 2>&1
if [ $? -ne 0 ]; then
  echo "Esto no debiera suceder. Fallo ir un commit atras desde el stash"
  exit 1
fi

Para el tercer paso voy a identificar las ramas que están en el commit actual como la intersección entre las que son --contains y las que son --merged. Si hay una tomo esas. Si hay 0 o más de 1 no se puede saber cual tomar. Por lo que no tomo ninguna. Me quedo sin rama.

contains=$(mktemp)
git branch --contains | grep -v "* (no branch)" | sort > $contains
merged=$(mktemp)
git branch --merged | grep -v "* (no branch)" | sort > $merged
common=$(mktemp)
comm -12 $contains $merged > $common
size=$(wc $common | sed 's/[^0-9]*([0-9]*).*/1/')
branch=$(head -1 $common)
rm $contains
rm $merged
rm $common

if [ $size -eq 1 ]; then
  git checkout $branch >/dev/null 2>&1
fi

Y ya solo queda hacer stash pop

git stash pop
if [ $? -ne 0 ]; then
  echo "git stash pop failed"
  exit 1
fi

Fuente

Tags:

Add a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *