#!/bin/bash # Git aliases and functions compatible with Git Bash on Windows # --- Helper Functions --- # Function to compare version numbers (requires version $1 >= version $2) # Usage: is_at_least "2.8" "$git_version" is_at_least() { local required_version="$1" local current_version="$2" # Handle empty current_version if [[ -z "$current_version" ]]; then return 1 # False fi # Use sort -V for version comparison # Check if current_version is >= required_version if [[ "$(printf '%s\n' "$required_version" "$current_version" | sort -V | head -n1)" == "$required_version" ]]; then return 0 # True (or equal) else return 1 # False fi } # Get Git version git_version_string=$(git version 2>/dev/null) if [[ -n "$git_version_string" ]]; then # Extract the version number (e.g., 2.34.1 from "git version 2.34.1.windows.1") # Using awk for simplicity git_version=$(echo "$git_version_string" | awk '{print $3}') # Optional: remove suffixes like .windows.1 if needed for comparisons, though sort -V handles it often # git_version="${git_version%%.windows.*}" else git_version="" # Handle case where git isn't found or fails # echo "Warning: Could not determine git version." >&2 fi # Get the current branch name reliably git_current_branch() { local branch_name # Try symbolic-ref first, handles branches correctly branch_name=$(git symbolic-ref --short HEAD 2>/dev/null) local exit_code=$? if [[ $exit_code -ne 0 ]]; then # Fallback for detached HEAD state: show commit hash branch_name=$(git rev-parse --short HEAD 2>/dev/null) [[ -z "$branch_name" ]] && return 1 # Failed to get anything fi echo "$branch_name" return 0 } # --- Functions Current --- # Back-compatibility wrapper function current_branch() { git_current_branch } # Check for develop and similarly named branches function git_develop_branch() { command git rev-parse --git-dir &>/dev/null || return local branch for branch in dev devel develop development; do if command git show-ref -q --verify refs/heads/"$branch"; then echo "$branch" return 0 fi done echo "develop" # Default fallback name return 1 # Indicate default was used / standard names not found } # Check if main exists and use instead of master function git_main_branch() { command git rev-parse --git-dir &>/dev/null || return local ref # Expands correctly in Bash for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk,mainline,default,stable,master}; do if command git show-ref -q --verify "$ref"; then # Use basename for Bash equivalent of Zsh :t echo "$(basename "$ref")" return 0 fi done # If no main branch was found, fall back to master but return error echo "master" # Default fallback name return 1 # Indicate default was used / preferred names not found } function grename() { if [[ -z "$1" || -z "$2" ]]; then # Use function name directly in Bash echo "Usage: grename old_branch new_branch" return 1 fi # Rename branch locally git branch -m "$1" "$2" # Rename branch in origin remote # Suppress error if old branch didn't exist remotely if git push origin :"${1}" &>/dev/null; then git push --set-upstream origin "$2" else # Optionally inform user, but still try setting upstream for the new branch echo "Info: Remote branch '$1' not found or couldn't be deleted." >&2 git push --set-upstream origin "$2" fi } # --- Functions Work in Progress (WIP) --- # Similar to `gunwip` but recursive "Unwips" all recent `--wip--` commits function gunwipall() { local _commit _commit=$(git log --grep='--wip--' --invert-grep --max-count=1 --format=format:%H 2>/dev/null) local current_head current_head=$(git rev-parse HEAD 2>/dev/null) # Check if a non-WIP commit was found and it's different from HEAD if [[ -n "$_commit" && "$_commit" != "$current_head" ]]; then git reset "$_commit" || return 1 elif [[ -z "$_commit" ]]; then echo "No non-WIP commit found to reset to." >&2 return 1 fi } # Warn if the current branch is a WIP function work_in_progress() { # Use standard grep and command structure if command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- '--wip--'; then echo "WIP!!" fi } # --- Aliases --- alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' # Helper function for ggpnp _ggpnp_func() { if [[ "$#" == 0 ]]; then _ggl_func && _ggp_func # Assuming _ggl_func and _ggp_func are defined below else # Pass arguments individually using "$@" _ggl_func "$@" && _ggp_func "$@" fi } alias ggpnp='_ggpnp_func' # No direct compdef equivalent in Bash alias files alias ggpur='_ggu_func' # Use the helper function defined below alias g='git' alias ga='git add' alias gaa='git add --all' alias gapa='git add --patch' alias gau='git add --update' alias gav='git add --verbose' # Ensure deleted files are handled robustly alias gwip='git add -A && git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"' alias gam='git am' alias gama='git am --abort' alias gamc='git am --continue' alias gamscp='git am --show-current-patch' alias gams='git am --skip' alias gap='git apply' alias gapt='git apply --3way' alias gbs='git bisect' alias gbsb='git bisect bad' alias gbsg='git bisect good' alias gbsn='git bisect new' # Assuming 'new' is valid; 'start' is common alias gbso='git bisect old' # Assuming 'old' is valid; 'bad'/'good' are common alias gbsr='git bisect reset' alias gbss='git bisect start' alias gbl='git blame -w' alias gb='git branch' alias gba='git branch --all' alias gbd='git branch --delete' alias gbD='git branch --delete --force' # Helper function for gbda _gbda_func() { local main_branch develop_branch branches_to_delete main_branch=$(git_main_branch) || main_branch="master" # Fallback if function fails develop_branch=$(git_develop_branch) || develop_branch="develop" # Fallback if function fails # Escape branches for the regex local safe_main=$(printf '%s\n' "$main_branch" | sed 's/[^^]/[&]/g; s/\^/\\^/g') local safe_develop=$(printf '%s\n' "$develop_branch" | sed 's/[^^]/[&]/g; s/\^/\\^/g') # Get merged branches excluding main/develop and the current branch (*) branches_to_delete=$(git branch --no-color --merged | command grep -vE "^\*|^\s*($safe_main|$safe_develop)\s*$" | sed 's/^\s*//') # Trim whitespace if [[ -n "$branches_to_delete" ]]; then # Use xargs safely with null delimiter if possible (requires GNU xargs/findutils) # Otherwise, process line by line for safety with spaces/special chars echo "$branches_to_delete" | while IFS= read -r branch; do # Double check it's not main/develop again, just in case if [[ "$branch" != "$main_branch" && "$branch" != "$develop_branch" ]]; then git branch --delete "$branch" fi done else echo "No merged branches (excluding ${main_branch}, ${develop_branch}, and current) to delete." fi } alias gbda='_gbda_func' # Helper function for gbds (Delete Squashed) _gbds_func() { local default_branch main_branch_status default_branch=$(git_main_branch) main_branch_status=$? if [[ $main_branch_status -ne 0 ]]; then default_branch=$(git_develop_branch) if [[ $? -ne 0 ]]; then echo "Warning: Could not determine main or develop branch for comparison. Using 'master' as fallback." >&2 default_branch="master" # Or choose another default or error out fi fi if [[ -z "$default_branch" ]]; then echo "Error: Could not determine a default branch to compare against." >&2 return 1 fi git for-each-ref refs/heads/ --format='%(refname:short)' | while read branch; do # Skip the default branch itself if [[ "$branch" == "$default_branch" ]]; then continue fi local merge_base merge_base=$(git merge-base "$default_branch" "$branch" 2>/dev/null) if [[ -z "$merge_base" ]]; then # echo "Info: Cannot find merge base between $default_branch and $branch. Skipping." >&2 continue fi # Check if the branch tip is reachable from default_branch (already merged) if git merge-base --is-ancestor "$branch" "$default_branch"; then # echo "Info: Branch '$branch' seems merged into '$default_branch'. Consider 'gbda'." >&2 continue # Already merged, gbda handles this fi # Create a temporary commit to check with git cherry # This checks if the *changes* introduced by the branch relative to its merge-base # are already present in the default branch (e.g., due to squash merge or cherry-pick) local branch_tree branch_commit temp_commit branch_commit=$(git rev-parse "$branch" 2>/dev/null) branch_tree=$(git rev-parse "$branch^{tree}" 2>/dev/null) if [[ -z "$branch_commit" || -z "$branch_tree" ]]; then echo "Warning: Could not parse branch '$branch'. Skipping." >&2 continue fi # Create a commit object in memory representing the branch's state based on merge-base # The message "_" is arbitrary temp_commit=$(git commit-tree "$branch_tree" -p "$merge_base" -m "_" 2>/dev/null) if [[ -z "$temp_commit" ]]; then echo "Warning: Could not create temporary commit for branch '$branch'. Skipping." >&2 continue fi # Use git cherry to find commits in temp_commit not equivalent in default_branch # If 'git cherry' output starts with '-', it means the commit is equivalent (present) # If output starts with '+', it means the commit is not equivalent (not present) local cherry_output cherry_output=$(git cherry -v "$default_branch" "$temp_commit" 2>/dev/null) # Check if cherry output indicates the commit *is* present (starts with '-') # We check if the output is *not* empty AND *does not* start with '+' # This implies it starts with '-' or is empty (error?), meaning changes are likely present. # A safer check might be specifically for '-'. if [[ "$cherry_output" == -* ]]; then echo "Branch '$branch' changes appear to be present in '$default_branch' (squashed/cherry-picked?). Deleting with -D." git branch -D "$branch" # else # echo "Branch '$branch' has unique changes compared to '$default_branch'." fi done } alias gbds='_gbds_func' # Use standard quoting for awk alias gbgd='LANG=C git branch --no-color -vv | grep ": gone]" | cut -c 3- | awk '\''{print $1}'\'' | xargs -r git branch -d' # Added -r to xargs alias gbgD='LANG=C git branch --no-color -vv | grep ": gone]" | cut -c 3- | awk '\''{print $1}'\'' | xargs -r git branch -D' # Added -r to xargs alias gbm='git branch --move' alias gbnm='git branch --no-merged' alias gbr='git branch --remote' # Helper for ggsup _ggsup_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git branch --set-upstream-to="origin/${current_b}" else echo "Error: Could not determine current branch." >&2 return 1 fi } alias ggsup='_ggsup_func' alias gbg='LANG=C git branch -vv | grep ": gone]"' # Shows branches whose upstream is gone alias gco='git checkout' alias gcor='git checkout --recurse-submodules' alias gcb='git checkout -b' alias gcB='git checkout -B' # Helper for gcd _gcd_func() { local target_branch target_branch=$(git_develop_branch) # Gets the name, status indicates if default was used git checkout "$target_branch" } alias gcd='_gcd_func' # Helper for gcm _gcm_func() { local target_branch target_branch=$(git_main_branch) # Gets the name, status indicates if default was used git checkout "$target_branch" } alias gcm='_gcm_func' alias gcp='git cherry-pick' alias gcpa='git cherry-pick --abort' alias gcpc='git cherry-pick --continue' alias gclean='git clean --interactive -d' alias gcl='git clone --recurse-submodules' # Filter options might depend on Git version, but generally compatible alias gclf='git clone --recursive --shallow-submodules --filter=blob:none --also-filter-submodules' # Helper function for gccd (clone and cd) gccd() { local last_arg target_dir repo_url clone_dir # Store the last argument before git clone runs # Bash doesn't have a simple equivalent for Zsh's $_ behavior related to command output directories # We'll rely on the standard git clone behavior # If the last arg looks like a directory target, save it if [[ "$#" -gt 0 && ! "${@: -1}" =~ ^(git@|https?://|ssh://|ftps?://) ]]; then clone_dir="${@: -1}" fi command git clone --recurse-submodules "$@" || return $? # Now determine where git cloned it if [[ -n "$clone_dir" && -d "$clone_dir" ]]; then # If an explicit directory was given and exists now, use it target_dir="$clone_dir" else # Otherwise, infer from the last argument that was likely the URL repo_url="${@: -1}" # Simplistic assumption: last arg was URL # Derive directory name from URL: basename, remove .git suffix target_dir=$(basename "$repo_url" .git) fi # Check if the determined directory exists and cd into it if [[ -d "$target_dir" ]]; then cd "$target_dir" || { echo "Error: Failed to cd into '$target_dir'" >&2; return 1; } echo "Cloned and changed directory to '$target_dir'" else echo "Warning: Cloned repository, but could not determine target directory '$target_dir' to cd into." >&2 # Stay in the current directory fi } # No compdef equivalent alias gcam='git commit --all --message' alias gcas='git commit --all --signoff' alias gcasm='git commit --all --signoff --message' alias gcs='git commit --gpg-sign' alias gcss='git commit --gpg-sign --signoff' alias gcssm='git commit --gpg-sign --signoff --message' alias gcmsg='git commit --message' alias gcsm='git commit --signoff --message' alias gc='git commit --verbose' alias gca='git commit --verbose --all' alias gca!='git commit --verbose --all --amend' alias gcan!='git commit --verbose --all --no-edit --amend' alias gcans!='git commit --verbose --all --signoff --no-edit --amend' alias gcann!='git commit --verbose --all --date=now --no-edit --amend' # Check if --date=now works as expected alias gc!='git commit --verbose --amend' alias gcn='git commit --verbose --no-edit' # Assumes you want --no-edit always alias gcn!='git commit --verbose --no-edit --amend' alias gcf='git config --list' alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' alias gd='git diff' alias gdca='git diff --cached' alias gdcw='git diff --cached --word-diff' alias gds='git diff --staged' # Same as gdca alias gdw='git diff --word-diff' # Helper for gdv (diff with view - needs 'view' or adjust editor) _gdv_func() { # On Windows 'view' might not exist. 'less' is common in Git Bash. # Or use default $GIT_EDITOR / $EDITOR / vi local editor=${GIT_PAGER:-${GIT_EDITOR:-${EDITOR:-less}}} # Prioritize pager, then editors, fallback less git diff -w "$@" | "$editor" } alias gdv='_gdv_func' # No compdef equivalent alias gdup='git diff @{upstream}' # Helper function for gdnolock (diff exclude lock files) _gdnolock_func() { # Bash doesn't have the :(exclude) syntax directly in arguments like Zsh # Use pathspecs passed to git diff git diff "$@" -- . ":(exclude)package-lock.json" ":(exclude)*.lock" } alias gdnolock='_gdnolock_func' # No compdef equivalent alias gdt='git diff-tree --no-commit-id --name-only -r' alias gf='git fetch' # Conditional alias for gfa based on Git version if is_at_least "2.8" "$git_version"; then alias gfa='git fetch --all --tags --prune --jobs=10' else alias gfa='git fetch --all --tags --prune' fi alias gfo='git fetch origin' alias gg='git gui citool &' # Use & for background alias gga='git gui citool --amend &' # Use & for background alias ghh='git help' alias glgg='git log --graph' alias glgga='git log --graph --decorate --all' alias glgm='git log --graph --max-count=10' # Use printf for colors in log formats if needed, though Git often handles auto color # Assuming terminal supports colors, Git's %C(...) usually works in Git Bash alias glods='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset" --date=short' alias glod='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset"' alias glola='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --all' alias glols='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --stat' alias glol='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset"' alias glo='git log --oneline --decorate' alias glog='git log --oneline --decorate --graph' alias gloga='git log --oneline --decorate --graph --all' # Pretty log messages helper function _git_log_prettily() { if [[ -n "$1" ]]; then git log --pretty="$1" else # Optional: Provide default log or usage message git log --oneline --decorate --graph --max-count=20 # echo "Usage: glp " >&2 # return 1 fi } alias glp='_git_log_prettily' # No compdef equivalent alias glg='git log --stat' alias glgp='git log --stat --patch' # grep syntax is compatible alias gignored='git ls-files -v | grep "^[[:lower:]]"' alias gfg='git ls-files | grep' alias gm='git merge' alias gma='git merge --abort' alias gmc='git merge --continue' alias gms='git merge --squash' alias gmff='git merge --ff-only' # Helper for gmom _gmom_func() { local target_branch target_branch=$(git_main_branch) # Gets name, status ignored here git merge "origin/${target_branch}" } alias gmom='_gmom_func' # Helper for gmum _gmum_func() { local target_branch target_branch=$(git_main_branch) # Gets name, status ignored here git merge "upstream/${target_branch}" } alias gmum='_gmum_func' alias gmtl='git mergetool --no-prompt' alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' alias gl='git pull' alias gpr='git pull --rebase' alias gprv='git pull --rebase -v' alias gpra='git pull --rebase --autostash' alias gprav='git pull --rebase --autostash -v' # Helper function for ggu (pull --rebase current or specified) _ggu_func() { local b if [[ "$#" -eq 0 ]]; then b=$(git_current_branch) if [[ -z "$b" ]]; then echo "Error: No current branch found." >&2; return 1; fi command git pull --rebase origin "$b" elif [[ "$#" -eq 1 ]]; then command git pull --rebase origin "$1" else echo "Usage: ggu [branch_name]" >&2 return 1 fi } alias ggu='_ggu_func' # No compdef equivalent # Helper for gprom _gprom_func() { local target_branch target_branch=$(git_main_branch) git pull --rebase origin "$target_branch" } alias gprom='_gprom_func' # Helper for gpromi _gpromi_func() { local target_branch target_branch=$(git_main_branch) git pull --rebase=interactive origin "$target_branch" } alias gpromi='_gpromi_func' # Helper for gprum _gprum_func() { local target_branch target_branch=$(git_main_branch) git pull --rebase upstream "$target_branch" } alias gprum='_gprum_func' # Helper for gprumi _gprumi_func() { local target_branch target_branch=$(git_main_branch) git pull --rebase=interactive upstream "$target_branch" } alias gprumi='_gprumi_func' # Helper function for ggpull (pull current branch from origin) _ggpull_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git pull origin "$current_b" else echo "Error: Could not determine current branch." >&2 return 1 fi } alias ggpull='_ggpull_func' # Helper function for ggl (pull origin current or specified) _ggl_func() { local b if [[ "$#" -eq 0 ]]; then b=$(git_current_branch) if [[ -z "$b" ]]; then echo "Error: No current branch found." >&2; return 1; fi command git pull origin "$b" else # Pass all arguments using "$@" (handles spaces in names if they occur) command git pull origin "$@" fi } alias ggl='_ggl_func' # No compdef equivalent # Helper for gluc _gluc_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git pull upstream "$current_b" else echo "Error: Could not determine current branch." >&2 return 1 fi } alias gluc='_gluc_func' # Helper for glum _glum_func() { local target_branch target_branch=$(git_main_branch) git pull upstream "$target_branch" } alias glum='_glum_func' alias gp='git push' alias gpd='git push --dry-run' # Helper function for ggf (force push origin current or specified) _ggf_func() { local b if [[ "$#" -eq 0 ]]; then b=$(git_current_branch) if [[ -z "$b" ]]; then echo "Error: No current branch found." >&2; return 1; fi command git push --force origin "$b" elif [[ "$#" -eq 1 ]]; then command git push --force origin "$1" else echo "Usage: ggf [branch_name]" >&2 return 1 fi } alias ggf='_ggf_func' # No compdef equivalent alias gpf!='git push --force' # Conditional alias for gpf (force with lease) if is_at_least "2.30" "$git_version"; then alias gpf='git push --force-with-lease --force-if-includes' else alias gpf='git push --force-with-lease' fi # Helper function for ggfl (force-with-lease push origin current or specified) _ggfl_func() { local b push_command # Determine the correct force-with-lease command based on version if is_at_least "2.30" "$git_version"; then push_command=(git push --force-with-lease --force-if-includes origin) else push_command=(git push --force-with-lease origin) fi if [[ "$#" -eq 0 ]]; then b=$(git_current_branch) if [[ -z "$b" ]]; then echo "Error: No current branch found." >&2; return 1; fi "${push_command[@]}" "$b" elif [[ "$#" -eq 1 ]]; then "${push_command[@]}" "$1" else echo "Usage: ggfl [branch_name]" >&2 return 1 fi } alias ggfl='_ggfl_func' # No compdef equivalent # Helper function for gpsup (push set upstream) _gpsup_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git push --set-upstream origin "$current_b" else echo "Error: Could not determine current branch." >&2 return 1 fi } alias gpsup='_gpsup_func' # Helper function for gpsupf (push set upstream force-with-lease) _gpsupf_func() { local current_b push_command base_command current_b=$(git_current_branch) if [[ -z "$current_b" ]]; then echo "Error: Could not determine current branch." >&2 return 1 fi base_command=(git push --set-upstream origin "$current_b") if is_at_least "2.30" "$git_version"; then push_command=("${base_command[@]}" --force-with-lease --force-if-includes) else push_command=("${base_command[@]}" --force-with-lease) fi "${push_command[@]}" } alias gpsupf='_gpsupf_func' alias gpv='git push --verbose' alias gpoat='git push origin --all && git push origin --tags' alias gpod='git push origin --delete' # Helper function for ggpush (push current branch to origin) _ggpush_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git push origin "$current_b" else echo "Error: Could not determine current branch." >&2 return 1 fi } alias ggpush='_ggpush_func' # Helper function for ggp (push origin current or specified) _ggp_func() { local b if [[ "$#" -eq 0 ]]; then b=$(git_current_branch) if [[ -z "$b" ]]; then echo "Error: No current branch found." >&2; return 1; fi command git push origin "$b" else # Pass all arguments using "$@" command git push origin "$@" fi } alias ggp='_ggp_func' # No compdef equivalent alias gpu='git push upstream' alias grb='git rebase' alias grba='git rebase --abort' alias grbc='git rebase --continue' alias grbi='git rebase --interactive' alias grbo='git rebase --onto' alias grbs='git rebase --skip' # Helper for grbd _grbd_func() { local target_branch target_branch=$(git_develop_branch) git rebase "$target_branch" } alias grbd='_grbd_func' # Helper for grbm _grbm_func() { local target_branch target_branch=$(git_main_branch) git rebase "$target_branch" } alias grbm='_grbm_func' # Helper for grbom _grbom_func() { local target_branch target_branch=$(git_main_branch) git rebase "origin/${target_branch}" } alias grbom='_grbom_func' # Helper for grbum _grbum_func() { local target_branch target_branch=$(git_main_branch) git rebase "upstream/${target_branch}" } alias grbum='_grbum_func' alias grf='git reflog' alias gr='git remote' alias grv='git remote --verbose' alias gra='git remote add' alias grrm='git remote remove' alias grmv='git remote rename' alias grset='git remote set-url' alias grup='git remote update' alias grh='git reset' alias gru='git reset --' # Use '--' to separate paths from revisions if needed alias grhh='git reset --hard' alias grhk='git reset --keep' alias grhs='git reset --soft' alias gpristine='git reset --hard && git clean --force -dfx' alias gwipe='git reset --hard && git clean --force -df' # Slightly safer than -dfx # Helper for groh _groh_func() { local current_b current_b=$(git_current_branch) if [[ -n "$current_b" ]]; then git reset "origin/${current_b}" --hard else echo "Error: Could not determine current branch." >&2 return 1 fi } alias groh='_groh_func' alias grs='git restore' alias grss='git restore --source' alias grst='git restore --staged' alias gunwip='last_msg=$(git log -1 --pretty=%s); if [[ "$last_msg" == *"--wip--"* ]]; then git reset HEAD~1; else echo "Last commit is not a WIP commit."; fi' alias grev='git revert' alias greva='git revert --abort' alias grevc='git revert --continue' alias grm='git rm' alias grmc='git rm --cached' alias gcount='git shortlog --summary --numbered' alias gsh='git show' alias gsps='git show --pretty=short --show-signature' alias gstall='git stash --all' alias gstaa='git stash apply' alias gstc='git stash clear' alias gstd='git stash drop' alias gstl='git stash list' alias gstp='git stash pop' # Conditional alias for gsta (stash push/save) if is_at_least "2.13" "$git_version"; then alias gsta='git stash push' else alias gsta='git stash save' fi alias gsts='git stash show --patch' alias gst='git status' alias gss='git status --short' alias gsb='git status --short --branch' alias gsi='git submodule init' alias gsu='git submodule update' alias gsd='git svn dcommit' # Helper for git-svn-dcommit-push _git_svn_dcommit_push_func() { local target_branch target_branch=$(git_main_branch) # Assuming 'github' is the correct remote name for the Git repo mirror git svn dcommit && git push github "${target_branch}:svntrunk" } alias git-svn-dcommit-push='_git_svn_dcommit_push_func' alias gsr='git svn rebase' alias gsw='git switch' alias gswc='git switch --create' # Helper for gswd _gswd_func() { local target_branch target_branch=$(git_develop_branch) git switch "$target_branch" } alias gswd='_gswd_func' # Helper for gswm _gswm_func() { local target_branch target_branch=$(git_main_branch) git switch "$target_branch" } alias gswm='_gswm_func' alias gta='git tag --annotate' alias gts='git tag --sign' alias gtv='git tag | sort -V' # Assumes standard sort, Git Bash usually has GNU sort alias gignore='git update-index --assume-unchanged' alias gunignore='git update-index --no-assume-unchanged' alias gwch='git whatchanged -p --abbrev-commit --pretty=medium' alias gwt='git worktree' alias gwta='git worktree add' alias gwtls='git worktree list' alias gwtmv='git worktree move' alias gwtrm='git worktree remove' alias gstu='gsta --include-untracked' # Relies on gsta alias defined above # Helper function for gtl (list tags matching prefix) _gtl_func() { # Bash doesn't need noglob here. Ensure $1 is quoted. git tag --sort=-v:refname -n --list "${1}*" } alias gtl='_gtl_func' # Use `command` prefix and `&` for background in Bash alias gk='command gitk --all --branches &' alias gke='command gitk --all $(git log --walk-reflogs --pretty=%h) &' # --- Deprecated Alias Handling --- # Define functions for old aliases that show a warning and call the new one # ANSI color codes: Yellow=\033[0;33m, Red=\033[0;31m, Green=\033[0;32m, Reset=\033[0m deprecated_map=( "gup:gpr" "gupv:gprv" "gupa:gpra" "gupav:gprav" "gupom:_gprom_func" # Call helper func directly if new alias uses one "gupomi:_gpromi_func" # Call helper func directly ) item="" old_alias="" new_alias_cmd="" for item in "${deprecated_map[@]}"; do old_alias="${item%%:*}" # Part before : new_alias_cmd="${item#*:}" # Part after : # Use eval to dynamically create a function named $old_alias # This function prints a warning and executes the new command, passing arguments eval " ${old_alias}() { printf \"\\033[0;33m[Git Alias] Warning: '%s' is deprecated, using '%s' instead.\\033[0m\\n\" \"${old_alias}\" \"${new_alias_cmd}\" >&2 \"${new_alias_cmd}\" \"\$@\" # Execute the new command/function with original arguments } " done unset item old_alias new_alias_cmd deprecated_map # Clean up loop variables # --- Cleanup --- unset git_version_string git_version # Clean up global version variable # --- End of Script --- # To use these aliases, source this file in your ~/.bashrc or ~/.bash_profile: # source /path/to/this/script.sh