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