Skip to content

Commit

Permalink
feat: add interactive git worktree operations
Browse files Browse the repository at this point in the history
  • Loading branch information
suft committed Nov 10, 2024
1 parent 7a40a11 commit b84a112
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
97 changes: 97 additions & 0 deletions bin/git-forgit
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $FORGIT_FZF_DEFAULT_OPTS

_forgit_warn() { printf "%b[Warn]%b %s\n" '\e[0;33m' '\e[0m' "$@" >&2; }
_forgit_info() { printf "%b[Info]%b %s\n" '\e[0;32m' '\e[0m' "$@" >&2; }
_forgit_inside_git_dir() { git rev-parse --is_inside-git-dir >/dev/null; }
_forgit_inside_work_tree() { git rev-parse --is-inside-work-tree >/dev/null; }
# tac is not available on OSX, tail -r is not available on Linux, so we use either of them
_forgit_reverse_lines() { tac 2> /dev/null || tail -r; }
Expand Down Expand Up @@ -1002,6 +1003,97 @@ _forgit_ignore_clean() {
[[ -d "$FORGIT_GI_REPO_LOCAL" ]] && rm -rf "$FORGIT_GI_REPO_LOCAL"
}

_forgit_worktree_preview() {
local sha
# trailing space in grep to avoid matching worktrees with a common path
sha=$(git worktree list | grep "$1 " | awk '{print $2}')
[[ "$sha" == "(bare)" ]] && return
_forgit_worktree_preview_git_opts=()
_forgit_parse_array _forgit_worktree_preview_git_opts "$FORGIT_WORKTREE_PREVIEW_GIT_OPTS"
# the trailing '--' ensures that this works for branches that have a name
# that is identical to a file
git log "$sha" "${_forgit_worktree_preview_git_opts[@]}" --
}

_forgit_worktree_jump() {
_forgit_inside_work_tree || _forgit_inside_git_dir || return 1
local count tree opts
count=$(git worktree list | wc -l)

[[ $count -eq 1 ]] && return 1

opts="
$FORGIT_FZF_DEFAULT_OPTS
+s +m --tiebreak=index
--preview=\"$FORGIT worktree_preview {1}\"
$FORGIT_WORKTREE_JUMP_FZF_OPTS
"

tree=$(git worktree list | awk '{print $1}' | FZF_DEFAULT_OPTS="$opts" fzf)
[[ -z "$tree" ]] && return 1
echo "$tree"
}

_forgit_git_worktree_lock() {
_forgit_worktree_lock_git_opts=()
_forgit_parse_array _forgit_worktree_lock_git_opts "$FORGIT_WORKTREE_LOCK_GIT_OPTS"
git worktree lock "${_forgit_worktree_lock_git_opts[@]}" "$@"
}

_forgit_worktree_lock() {
_forgit_inside_work_tree || _forgit_inside_git_dir || return 1
local tree opts

opts="
$FORGIT_FZF_DEFAULT_OPTS
+s -m --tiebreak=index
--preview=\"$FORGIT worktree_preview {1}\"
$FORGIT_WORKTREE_LOCK_FZF_OPTS
"

tree=$(git worktree list | awk '{print $1}' | grep -v "(bare)" | FZF_DEFAULT_OPTS="$opts" fzf)
[[ -z "$tree" ]] && return 1
_forgit_git_worktree_lock "$tree"
}

_forgit_git_worktree_remove() {
_forgit_worktree_remove_git_opts=()
_forgit_parse_array _forgit_worktree_remove_git_opts "$FORGIT_WORKTREE_REMOVE_GIT_OPTS"
git worktree remove "${_forgit_worktree_remove_git_opts[@]}" "$@"
}

_forgit_worktree_remove() {
_forgit_inside_work_tree || _forgit_inside_git_dir || return 1
local tree opts

opts="
$FORGIT_FZF_DEFAULT_OPTS
+s -m --tiebreak=index --header-lines=1
--preview=\"$FORGIT worktree_preview {1}\"
$FORGIT_WORKTREE_REMOVE_FZF_OPTS
"

tree=$(git worktree list | awk '{print $1}' | grep -v "(bare)" | FZF_DEFAULT_OPTS="$opts" fzf)
[[ -z "$tree" ]] && return 1
_forgit_git_worktree_remove "$tree"
}

_forgit_worktree_unlock() {
_forgit_inside_work_tree || _forgit_inside_git_dir || return 1
local tree opts

opts="
$FORGIT_FZF_DEFAULT_OPTS
+s -m --tiebreak=index --header-lines=1
--preview=\"$FORGIT worktree_preview {1}\"
$FORGIT_WORKTREE_UNLOCK_FZF_OPTS
"

tree=$(git worktree list | awk '{print $1}' | grep -v "(bare)" | FZF_DEFAULT_OPTS="$opts" fzf)
[[ -z "$tree" ]] && return 1
git worktree unlock "$tree"
}

public_commands=(
"add"
"blame"
Expand All @@ -1023,12 +1115,17 @@ public_commands=(
"revert_commit"
"stash_show"
"stash_push"
"worktree_jump"
"worktree_lock"
"worktree_remove"
"worktree_unlock"
)

private_commands=(
"add_preview"
"blame_preview"
"branch_preview"
"worktree_preview"
"checkout_commit_preview"
"checkout_file_preview"
"cherry_pick_from_branch_preview"
Expand Down
4 changes: 4 additions & 0 deletions conf.d/forgit.plugin.fish
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ if test -z "$FORGIT_NO_ALIASES"
abbr -a -- (string collect $forgit_revert_commit; or string collect "grc") git-forgit revert_commit
abbr -a -- (string collect $forgit_blame; or string collect "gbl") git-forgit blame
abbr -a -- (string collect $forgit_checkout_tag; or string collect "gct") git-forgit checkout_tag
abbr -a -- (string collect $forgit_worktree_jump; or string collect "gwj") 'set tree (git-forgit worktree_jump); test -n "$tree"; and cd "$tree"'
abbr -a -- (string collect $forgit_worktree_lock; or string collect "gwl") git-forgit worktree_lock
abbr -a -- (string collect $forgit_worktree_remove; or string collect "gwr") git-forgit worktree_remove
abbr -a -- (string collect $forgit_worktree_unlock; or string collect "gwu") git-forgit worktree_unlock
end
24 changes: 24 additions & 0 deletions forgit.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ forgit::ignore::clean() {
"$FORGIT" ignore_clean "$@"
}

forgit::worktree::jump() {
cd "$("$FORGIT" worktree_jump "$@")" || exit
}

forgit::worktree::lock() {
"$FORGIT" worktree_lock "$@"
}

forgit::worktree::remove() {
"$FORGIT" worktree_remove "$@"
}

forgit::worktree::unlock() {
"$FORGIT" worktree_unlock "$@"
}

# register aliases
# shellcheck disable=SC2139
if [[ -z "$FORGIT_NO_ALIASES" ]]; then
Expand All @@ -160,6 +176,10 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
export forgit_rebase="${forgit_rebase:-grb}"
export forgit_fixup="${forgit_fixup:-gfu}"
export forgit_blame="${forgit_blame:-gbl}"
export forgit_worktree_jump="${forgit_worktree_jump:-gwj}"
export forgit_worktree_lock="${forgit_worktree_lock:-gwl}"
export forgit_worktree_remove="${forgit_worktree_remove:-gwr}"
export forgit_worktree_unlock="${forgit_worktree_unlock:-gwu}"

alias "${forgit_add}"='forgit::add'
alias "${forgit_reset_head}"='forgit::reset::head'
Expand All @@ -180,5 +200,9 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then
alias "${forgit_rebase}"='forgit::rebase'
alias "${forgit_fixup}"='forgit::fixup'
alias "${forgit_blame}"='forgit::blame'
alias "${forgit_worktree_jump}"='forgit::worktree::jump'
alias "${forgit_worktree_lock}"='forgit::worktree::lock'
alias "${forgit_worktree_remove}"='forgit::worktree::remove'
alias "${forgit_worktree_unlock}"='forgit::worktree::unlock'

fi

0 comments on commit b84a112

Please sign in to comment.