Files
dotfiles/.config/zsh/autoload/git/git-checkout-worktree
Julian Prein 5deb69bbd6 git:checkout-worktree: Improve name on recursion
When calling git-checkout-worktree from inside a temporary working tree
(doesn't necessary need to be a recursive call, could be another shell
too) the name would be very long.

Fix this by using the folder name of the main working tree.
2023-04-11 23:24:52 +02:00

66 lines
2.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"
emulate -L zsh -o err_return -o no_unset
local REPO_NAME WORKTREE_PATH
# Use the folder name of the main working tree to make calls from another
# temporary working tree possible
REPO_NAME="${${${$(git rev-parse --git-dir):A}%%/.git*}:t}"
WORKTREE_PATH="$(mktemp -d -p "" "worktree.XXX.$REPO_NAME.${1//\//_}")"
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 '$WORKTREE_PATH' manually.\n"
return $errc
' INT QUIT TERM EXIT
pushd -q "$WORKTREE_PATH"
"$SHELL" && errc=$? || 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=$?
done
# Reset traps and PWD
trap '-' INT QUIT TERM EXIT
popd -q || true
git worktree prune
return $errc