#!/bin/bash # # checkout files/commits/branches using fzf # # @params # Globals # ${mydir}: current directory of the script, used for imports # ${all_files}: search all tracked files instead of just the modified files # ${branch}: checkout branch # ${selected_branch}: selected_branch to switch # ${selected_files}: selected_files to checkout to the version in HEAD # Arguments # -h: show help message # -a: search all files instead of just the modified files # -b: search branch and checkout branch # -c: search commits and checkout commits set -e mydir="${0%/*}" source "${mydir}"/../helper/set_variable.sh source "${mydir}"/../helper/get_confirmation.sh source "${mydir}"/../helper/git_data.sh function usage() { echo -e "Usage: dotbare fcheckout [-h] [-a] [-b] [-c] ...\n" echo -e "Reset/Unstage the selected staged file" echo -e "Or reset the commit to certain point\n" echo -e "optional arguments:" echo -e " -h\t\tshow this help message and exit" echo -e " -a\t\tsearch all files instead of just modified files" echo -e " -b\t\tcheckout branch" echo -e " -c\t\tcheckout single commits" } all_files="" branch="" commits="" while getopts ":habc" opt do case "$opt" in a) all_files='true' break ;; b) branch='true' break ;; c) commits='true' break ;; h) usage exit 0 ;; *) echo "Invalid option: ${OPTARG}" >&2 usage exit 1 ;; esac done if [[ -n "${branch}" ]]; then # checkout branch selected_branch=$(/usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" branch -a | \ awk '{ if ($0 ~ /\*.*\(HEAD.*/) { gsub(/\* /, "", $0) print "\033[32m" $0 "\033[0m" } else if (match($1, "\\*") != 0) { print "\033[32m" $2 "\033[0m" } else { gsub(/^[ \t]+/, "", $0) print $0 } }' | \ fzf --no-multi --header='select a branch to checkout' \ --preview="/usr/bin/git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} log --oneline --graph --color=always --decorate=short {}") [[ -z "${selected_branch}" ]] && exit 0 /usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout "${selected_branch}" exit 0 elif [[ -n "${commits}" ]]; then # checkout commits selected_commits=$(get_commit) [[ -z "${selected_commits}" ]] && exit 0 /usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout "${selected_commits}" exit 0 else # checkout files (reset file changes back to HEAD) if [[ -n "${all_files}" ]]; then selected_files=$(/usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" ls-files --full-name --directory "${DOTBARE_TREE}" | \ fzf --multi --header='select a file to checkout version in HEAD' --preview "head -50 ${DOTBARE_TREE}/{}" | \ awk -v home="${DOTBARE_TREE}" '{print home "/" $0}') else selected_files=$(/usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" diff --name-status | \ awk '{print "\033[31m" $1 " " $2}' | \ fzf --multi --header='select a file to checkout version in HEAD' \ --preview "echo {} | awk '{print \$2}' | \ xargs -I __ /usr/bin/git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} diff --color=always ${DOTBARE_TREE}/__" | \ awk -v home="${DOTBARE_TREE}" '{print home "/" $2}') fi [[ -z "${selected_files}" ]] && exit 0 while IFS= read -r line; do echo "(dryrun) dotbare checkout -- ${line}" done <<< "${selected_files}" confirm=$(get_confirmation "Confirm?") [[ "${confirm}" != 'y' ]] && exit 0 while IFS= read -r line; do /usr/bin/git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout -- "${line}" echo "${line} checkout success" done <<< "${selected_files}" fi