Created
May 30, 2025 11:06
-
-
Save alvesvaren/28b89dac25628f83e481d022c4916f6c to your computer and use it in GitHub Desktop.
Port of most oh-my-zsh git aliases to git bash for windows
This file contains hidden or 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
#!/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 <format_string>" >&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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What is this?
This is a file with most aliases from oh-my-zsh to make using git easier from the terminal.
The script is made for git bash on windows, but it might work fine in normal bash too, although there I'd just use zsh instead.
It doesn't do tab completions for most commands, but otherwise it should behave the same as in zsh
To install
source ~/.git-aliases.sh
anywhere in your~/.bashrc