When I do:
git pull --rebase --autostash
Sometimes I get a message that there was a conflict applying the stash and I\'ll need to merge it
My script to work around this issue is non-trivial. I post it here to both help others and in the hope for comments for improvement.
Call this ~/bin/git-pull-autostash
and invoke it as git pull-autostash
:
#!/bin/bash
# Work around 0 exit if autostash doesn't apply
# https://stackoverflow.com/questions/52538050/exit-status-is-0-but-autostash-requires-manual-merging
# Work around 0 exit if no stash is created
# https://stackoverflow.com/questions/52568548/git-stash-exits-0-but-no-stash-created
set -euo pipefail
if [ -z "$(git status --porcelain --untracked-files=no)" ]; then
# Working directory and index are clean
git pull --rebase "$@"
exit 0
fi
# If we get to here, a stash is required.
exit_code_autostash_unpopped=4
exit_code_autostash_error=70 # https://unix.stackexchange.com/a/254747/143394
stash_msg="pull-autostash on $(git rev-parse --short @)"
get_stash_top() {
local top
if top=$(git rev-parse stash@\{0\} 2>/dev/null); then
echo "$top"
fi
# Null output if there is no stash
}
prev_stash_top=$(get_stash_top)
git stash push -m "$stash_msg" > /dev/null
new_stash_top=$(get_stash_top)
stash_desc="${new_stash_top:0:7}: \"$stash_msg\""
# Minimise race conditions - have trap function ready before it is required
warn_pop_required() {
local exit_code=$? # Non-zero if invoked from trap
if [[ -n ${pop_required-} ]]; then
git stash list >&2
printf '\nWARNING: autostash %s remains to be applied\n' "$stash_desc" >&2
exit "$exit_code_autostash_unpopped"
fi
exit "$exit_code"
}
trap warn_pop_required EXIT
if [[ $new_stash_top != "$prev_stash_top" ]]; then
# A stash was created
pop_required=true # flag for trap function
printf 'Created stash %s\n' "$stash_desc"
fi
pop_stash() {
local exit_code=$?
if [[ $(get_stash_top) != "$new_stash_top" ]]; then
printf 'WARNING: autostash %s is no longer at the top of the stack\n' "$stash_desc" >&2
exit "$exit_code_autostash_error"
else
git stash pop --quiet
unset pop_required
printf 'Successfully popped stash %s\n' "$stash_desc"
fi
if [[ $exit_code -ne 0 ]]; then # We were called from a signal
exit "$exit_code"
fi
}
trap pop_stash INT ERR TERM QUIT # Pop stash on termination during pull
git pull --no-autostash --rebase "$@"
trap - INT ERR TERM QUIT # Don't try to pop stash twice
pop_stash
With non-zero exit code you cannot distinguish pull
error from stash pop
error.
My advice is to avoid autostash. It seems convenient when it works but is problematic when it doesn't. And if you do things like
git stash push
git pull --rebase
git stash pop
you can create a bash script or a git alias:
git alias.pull-autostash '!git stash push && git pull --rebase && git stash pop'
Usage:
git pull-autostash