Last active
October 10, 2024 03:16
-
-
Save Saafo/d789f58ea84ab0caa90ddbf47da1404f to your computer and use it in GitHub Desktop.
My custom git workflow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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}Local branch $1 exists, 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" exists, forking 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 exist, please specify valid source branch${COLOR_OFF}" | |
return 1 | |
fi | |
fi | |
git branch "$1" --no-track "$SOURCE_BRANCH" | |
echo "${GREEN}Branch $1 not exist, creating 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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Install this script to
~/.zshrc
: