The parameter expansion outside of the single quotes (or inside, however you want to see it) was not quoted.
91 lines
3.0 KiB
Bash
Executable File
91 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env zsh
|
|
|
|
# Create a temporary worktree.
|
|
#
|
|
# Useful for doing quick tasks on other branches without modifying the current
|
|
# working tree. So no broken/outdated symlinks to dotfiles or unnecessary
|
|
# recompiling after switching back for example.
|
|
#
|
|
# Checks out the first argument in a worktree at a temporary directory. Then
|
|
# spawns an interactive shell inside of it.
|
|
#
|
|
# When the shell closes the worktree is tried to be removed. Until that works
|
|
# without problems (e.g. dirty), a new shell is spawned to resolve all conflicts
|
|
# (e.g. stashing).
|
|
#
|
|
# Instead of dropping in an interactive shell, the commands to execute can be
|
|
# passed via stdin. If any conflicts arise, all further shells are interactive.
|
|
# TODO: Override with flag that just `stash -u`
|
|
#
|
|
# Examples for scripted usage:
|
|
# Merge branches without leaving the current one:
|
|
# % git-checkout-worktree main <<<"git merge dev"
|
|
#
|
|
# Same for rebase (as `git rebase dev feature` switches to `feature`):
|
|
# % git-checkout-worktree feature <<<"git rebase dev"
|
|
#
|
|
#
|
|
# TODO: The git alias version seems to break with the same arguments that the
|
|
# zsh native one works with.
|
|
# TODO: Supplying a flag like --no-checkout breaks the naming of the worktree
|
|
|
|
emulate -L zsh -o err_return -o no_unset
|
|
|
|
local git_dir cwd_offset REPO_NAME WORKTREE_PATH
|
|
# Use the folder name of the main working tree to make calls from another
|
|
# temporary working tree possible
|
|
git_dir="${$(git rev-parse --git-dir):A}"
|
|
[[ $git_dir == */.git/modules/* ]] || git_dir="${git_dir%%/.git*}"
|
|
REPO_NAME="${git_dir:t}"
|
|
WORKTREE_PATH="$(mktemp -d -p "" "wtree.$REPO_NAME.${1//\//_}.XXX")"
|
|
|
|
local errc ret=0
|
|
git worktree add "$WORKTREE_PATH" "$@" || ret=$?
|
|
|
|
if (( ret )); then
|
|
rmdir "$WORKTREE_PATH"
|
|
return $ret
|
|
fi
|
|
|
|
trap '
|
|
errc=$?
|
|
<&2 printf "Exiting abnormally. Check and possibly remove \"%s\" manually.\n" "'"$WORKTREE_PATH"'"
|
|
return $errc
|
|
' INT QUIT TERM EXIT
|
|
|
|
cwd_offset="${${PWD#$(git rev-parse --show-toplevel)}#/}"
|
|
pushd -q "$WORKTREE_PATH"
|
|
until [[ -d $cwd_offset || -z $cwd_offset ]]; do
|
|
cwd_offset="${cwd_offset:h}"
|
|
done
|
|
[[ -z $cwd_offset ]] || cd "$cwd_offset"
|
|
|
|
# Discard some environment variables that were set by git when calling this
|
|
# script through an alias.
|
|
#
|
|
# Is set for submodules and will confuse git in the subshell
|
|
unset GIT_DIR
|
|
# Not sure if this can bring any issues, but better be safe
|
|
unset GIT_PREFIX
|
|
# TODO: Do we want to unset this too? Could have been set on purpose by the user
|
|
# and not git. Maybe only for the subshell via `env`?
|
|
#unset GIT_EXEC_PATH
|
|
|
|
"$SHELL" && errc=$? || errc=$?
|
|
(( !errc )) || echo "shell exited with $errc"
|
|
|
|
# Restart the shell (forcefully interactive) until the worktree is removed
|
|
until [[ ! -e "$WORKTREE_PATH" ]] || git worktree remove "$WORKTREE_PATH"; do
|
|
[[ -t 0 ]] ||
|
|
>&2 printf "Dropping into interactive shell to resolve conflicts\n"
|
|
"$SHELL" -i && errc=$? || errc=$?
|
|
(( !errc )) || echo "shell exited with $errc"
|
|
done
|
|
|
|
# Reset traps and PWD
|
|
trap '-' INT QUIT TERM EXIT
|
|
popd -q || true
|
|
|
|
git worktree prune
|
|
return $errc
|