Skip to content

Instantly share code, notes, and snippets.

@Saafo
Last active February 19, 2024 12:30
Show Gist options
  • Save Saafo/d789f58ea84ab0caa90ddbf47da1404f to your computer and use it in GitHub Desktop.
Save Saafo/d789f58ea84ab0caa90ddbf47da1404f to your computer and use it in GitHub Desktop.
My custom git workflow
#!/usr/bin/env zsh
# Author: @Saafo
# License: MIT
# MARK: rebase workflow
function grc() {( set -e
case "$1" in -h|help|--help)
echo "grc: git fetch && git rebase origin/HEAD --autostash"
return;;
esac
readonly local REMOTE_MAIN_BRANCH=$(git rev-parse --abbrev-ref origin/HEAD)
git fetch
git rebase "$REMOTE_MAIN_BRANCH" --autostash
)}
function grr() {( set -e
case "$1" in -h|help|--help)
echo "grr: git stash && checkout main branch && fetch && pull && checkout back &&"
echo "rebase main branch && stash pop"
return;;
esac
readonly local CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
readonly local MSG_WITH_NOW="GRR Auto-Stash: $(date "+%Y-%m-%d %H:%M:%S %z")"
readonly local MAIN_BRANCH=$(git rev-parse --abbrev-ref origin/HEAD | sed 's/origin\///')
git stash -u -m "$MSG_WITH_NOW"
git checkout "$MAIN_BRANCH"
git fetch
git pull
git checkout "$CURRENT_BRANCH"
git rebase "$MAIN_BRANCH"
if [ $(git stash list | grep -c "$MSG_WITH_NOW") -gt 0 ]; then
git stash pop --index
fi
readonly local GREEN='\033[0;32m'
echo "${GREEN}GRR Succeeded!"
)}
function gcos() {( set -e
case "$1" in -h|help|--help)
echo "gcos: stash current, fetch and checkout \$1"
return;;
esac
readonly local MSG_WITH_NOW="GCOS Auto-Stash: $(date "+%Y-%m-%d %H:%M:%S %z")"
git stash -u -m "$MSG_WITH_NOW"
git fetch
git checkout "$1"
if [ $(git stash list | grep -c "$MSG_WITH_NOW") -gt 0 ]; then
git stash pop --index
fi
)}
# MARK: worktree workflow
function gwa() {
local TEMP_PATH="/tmp/gwf_gwa_target_path-$(uuidgen)"
(set -e
case "$1" in -h|help|--help)
printf "gwa: add a new git worktree\n\n"
printf "Usage:\n"
printf " gwa <target-branch> [<source-branch>]\n\n"
printf "Options:\n"
printf " <target-branch>: Using this branch as the new worktree's branch.\n"
printf " The branch can be:\n"
printf " * existed in local: will checkout the local branch.\n"
printf " * existed in remote: will checkout a local branch from the remote branch.\n"
printf " * non-existed: will create a new branch from <source-branch> (--no-track).\n"
printf " <source-branch>: Using this branch as the source branch if <target-branch> is not existed.\n"
printf " This param is optional, by default it will be origin/HEAD.\n"
printf " If specified, the branch can be exist in local or remote, but it must exist.\n"
printf "Note:\n"
printf " You can use this command from any directory of the entire git repo, \n"
printf " and by the end this command will jump to the new created worktree \n"
printf " located at <main-gitrepo>/../<main-gitrepo>-<last-part-of-target-branch-name>/\n"
return;;
esac
readonly local GREEN='\033[0;32m'
readonly local RED='\033[0;31m'
readonly local COLOR_OFF='\033[0m'
git fetch
if git rev-parse --verify --quiet "$1" > /dev/null; then
echo "${GREEN}Branch $1 already existed, skip creating branch${COLOR_OFF}"
elif git rev-parse --verify --quiet "origin/$1" > /dev/null; then
git branch "$1" "origin/$1"
echo "${GREEN}Remote branch "origin/$1" existed, forked to local${COLOR_OFF}"
else
readonly local REMOTE_MAIN_BRANCH=$(git rev-parse --abbrev-ref origin/HEAD)
local SOURCE_BRANCH="$REMOTE_MAIN_BRANCH"
if [ -n "$2" ]; then
if git rev-parse --verify --quiet "$2" > /dev/null; then
local SOURCE_BRANCH="$2"
elif git rev-parse --verify --quiet "origin/$2" > /dev/null; then
local SOURCE_BRANCH="origin/$2"
else
echo "${RED}Neither $2 nor origin/$2 existed, please specify valid source branch${COLOR_OFF}"
return 1
fi
fi
git branch "$1" --no-track "$SOURCE_BRANCH"
echo "${GREEN}Branch $1 not existed, created from $SOURCE_BRANCH${COLOR_OFF}"
fi
readonly local FEAT_NAME=$(echo $1 | rev | cut -d/ -f1 | rev)
readonly local MAIN_REPO_PATH=$(dirname $(readlink -f $(git rev-parse --git-common-dir)))
readonly local MAIN_REPO_NAME=$(basename ${MAIN_REPO_PATH})
readonly local MAIN_REPO_PARENT_PATH=$(dirname ${MAIN_REPO_PATH})
readonly local TARGET_FOLDER_PATH="${MAIN_REPO_PARENT_PATH}/${MAIN_REPO_NAME}-${FEAT_NAME}"
git worktree add ${TARGET_FOLDER_PATH} "$1"
echo "TARGET_FOLDER_PATH=${TARGET_FOLDER_PATH}" > ${TEMP_PATH}
echo "${GREEN}Create new worktree successfully at ${TARGET_FOLDER_PATH}, jumping to there"
)
if [[ -s ${TEMP_PATH} ]]; then
source ${TEMP_PATH}
if [[ -n ${TARGET_FOLDER_PATH} ]]; then
cd ${TARGET_FOLDER_PATH}
unset TARGET_FOLDER_PATH
fi
command -v trash &> /dev/null && trash ${TEMP_PATH} || rm ${TEMP_PATH}
fi
}
function gwd() {
local TEMP_PATH="/tmp/gwf_gwd_target_path-$(uuidgen)"
(set -e
case "$1" in
-h|help|--help)
echo "gwd: removing current worktree and ask whether delete current branch."
echo "Usage:"
echo " gwd [-f]"
echo "Options:"
echo " -f force delete current branch and worktree without confirming, and exit current shell."
return;;
-f|--force)
readonly local FORCE_DELETE=true;;
esac
readonly local MAIN_REPO_PATH=$(dirname $(readlink -f $(git rev-parse --git-common-dir)))
readonly local CURRENT_REPO_PATH=$(git rev-parse --show-toplevel)
readonly local CURRENT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
readonly local GREEN='\033[0;32m'
readonly local RED='\033[0;31m'
readonly local COLOR_OFF='\033[0m'
echo "${RED}will removing current worktree: ${CURRENT_REPO_PATH}"
echo "and current branch: ${CURRENT_BRANCH_NAME}${COLOR_OFF}"
function confirm() {
read -r "RESPONSE?$1 (y/n)?"
[[ ${RESPONSE:l} == "y" || -z ${RESPONSE} ]]
}
if [[ -n ${FORCE_DELETE} ]] || confirm "continue"; then
printf "\ndeleting worktree...\n"
git worktree remove ${CURRENT_REPO_PATH} || {
printf "\ngit status:\n"
git status --short
if [[ -n ${FORCE_DELETE} ]] || confirm "force delete worktree"; then
printf "\nforce deleting worktree...\n"
git worktree remove -f ${CURRENT_REPO_PATH}
else
return
fi
}
cd ${MAIN_REPO_PATH}
printf "\ndeleting branch...\n"
git branch -d ${CURRENT_BRANCH_NAME} || {
if [[ -n ${FORCE_DELETE} ]] || confirm "force delete branch ${CURRENT_BRANCH_NAME}"; then
echo "" #return a new line
git branch -D ${CURRENT_BRANCH_NAME}
fi
}
echo "MAIN_REPO_PATH=${MAIN_REPO_PATH}" >> ${TEMP_PATH}
echo "FORCE_DELETE=${FORCE_DELETE}" >> ${TEMP_PATH}
echo "${GREEN}Delete worktree successfully, jumping to main repo${COLOR_OFF}"
fi
)
if [[ -s ${TEMP_PATH} ]]; then
source ${TEMP_PATH}
command -v trash &> /dev/null && trash ${TEMP_PATH} || rm ${TEMP_PATH}
if [[ -n ${FORCE_DELETE} ]]; then
exit
fi
if [[ -n ${MAIN_REPO_PATH} ]]; then
cd ${MAIN_REPO_PATH}
fi
unset MAIN_REPO_PATH
unset FORCE_DELETE
fi
}
@Saafo
Copy link
Author

Saafo commented Apr 19, 2023

Install this script to ~/.zshrc:

curl -sLf https://gist.githubusercontent.com/Saafo/d789f58ea84ab0caa90ddbf47da1404f/raw/d195ee797d91a4fdd366f530b496aed157d79db9/.gitworkflow.zsh -o ~/.gitworkflow.zsh && echo "source ~/.gitworkflow.zsh" >> ~/.zshrc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment