Skip to content

Instantly share code, notes, and snippets.

@davivc
Created July 30, 2025 14:17
Show Gist options
  • Save davivc/8570198e1aae1844ef6d531e9a1fcf3e to your computer and use it in GitHub Desktop.
Save davivc/8570198e1aae1844ef6d531e9a1fcf3e to your computer and use it in GitHub Desktop.
Improved colored git terminal
# Complex Git prompt with Powerline fonts, enhanced colors, status indicators, and virtual environment support
force_color_prompt=yes
color_prompt=yes
# Powerline symbols (install fonts-powerline package first)
# Replace the powerline symbols section with these unicode alternatives:
POWERLINE_BRANCH="🌿" # or use "git:"
POWERLINE_SEPARATOR="β–Ά" # or use ">"
POWERLINE_RIGHT_SEPARATOR="β—€"
POWERLINE_LOCK="πŸ”’"
POWERLINE_AHEAD="⬆"
POWERLINE_BEHIND="⬇"
POWERLINE_DIVERGED="⚑"
# Enhanced git branch function with detailed status indicators
parse_git_branch() {
local branch
local status
local color
local symbols=""
# Get branch name
branch=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ -n "$branch" ]; then
# Get git status
status=$(git status --porcelain 2> /dev/null)
# Check for different types of changes and add symbols
if [ -n "$status" ]; then
echo "$status" | grep -q "^M" && symbols="${symbols}●" # Modified files
echo "$status" | grep -q "^A" && symbols="${symbols}+" # Added files
echo "$status" | grep -q "^D" && symbols="${symbols}βˆ’" # Deleted files
echo "$status" | grep -q "^R" && symbols="${symbols}β†’" # Renamed files
echo "$status" | grep -q "^??" && symbols="${symbols}?" # Untracked files
echo "$status" | grep -q "^UU" && symbols="${symbols}!" # Merge conflicts
# Determine color based on staging status
if git diff --cached --quiet 2> /dev/null; then
# Only unstaged changes - bright yellow
color="1;33"
else
# Has staged changes - bright green
color="1;32"
fi
else
# Clean working directory - bright cyan
color="1;36"
fi
# Check if we're ahead/behind remote
local remote_status=""
if git rev-parse --abbrev-ref @{upstream} >/dev/null 2>&1; then
local ahead=$(git rev-list --count @{upstream}..HEAD 2>/dev/null)
local behind=$(git rev-list --count HEAD..@{upstream} 2>/dev/null)
if [ "$ahead" -gt 0 ] && [ "$behind" -gt 0 ]; then
remote_status="${POWERLINE_DIVERGED}${ahead}/${behind}"
elif [ "$ahead" -gt 0 ]; then
remote_status="${POWERLINE_AHEAD}${ahead}"
elif [ "$behind" -gt 0 ]; then
remote_status="${POWERLINE_BEHIND}${behind}"
fi
fi
# Combine all status info
local full_status=""
if [ -n "$symbols" ]; then
full_status+=" ${symbols}"
fi
if [ -n "$remote_status" ]; then
full_status+=" ${remote_status}"
fi
if [ -n "$full_status" ]; then
echo -e "\033[${color}m${POWERLINE_BRANCH} ${branch}${full_status}\033[0m"
else
echo -e "\033[${color}m${POWERLINE_BRANCH} ${branch}\033[0m"
fi
fi
}
# Alternative simpler git function (you can switch between them)
parse_git_branch_simple() {
local branch=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ -n "$branch" ]; then
if git diff-index --quiet HEAD -- 2>/dev/null; then
# Clean - bright cyan
echo -e "\033[1;36m${POWERLINE_BRANCH}${branch}\033[0m"
else
# Dirty - bright yellow
echo -e "\033[1;33m${POWERLINE_BRANCH}${branch}\033[0m"
fi
fi
}
# Enhanced virtual environment display
parse_venv() {
local venv_display=""
if [ -n "$VIRTUAL_ENV" ]; then
local venv_name=$(basename "$VIRTUAL_ENV")
local venv_path=$(dirname "$VIRTUAL_ENV")
# Different colors and formats for different venv types
if [[ "$venv_name" == ".venv" ]]; then
# Standard .venv - bright magenta with project name
local project_name=$(basename "$venv_path")
venv_display="\033[1;35m(.venv:${project_name})\033[0m"
elif [[ "$venv_name" == "venv" ]]; then
# Standard venv - bright magenta
venv_display="\033[1;35m(venv)\033[0m"
elif [[ "$VIRTUAL_ENV" == *"conda"* ]] || [[ -n "$CONDA_DEFAULT_ENV" ]]; then
# Conda environment - bright green
local conda_env="${CONDA_DEFAULT_ENV:-$venv_name}"
venv_display="\033[1;32m(🐍 conda:${conda_env})\033[0m"
else
# Named venv - bright blue
venv_display="\033[1;34m(🐍 ${venv_name})\033[0m"
fi
elif [ -n "$CONDA_DEFAULT_ENV" ] && [ "$CONDA_DEFAULT_ENV" != "base" ]; then
# Conda environment without VIRTUAL_ENV
venv_display="\033[1;32m(🐍 conda:${CONDA_DEFAULT_ENV})\033[0m"
fi
if [ -n "$venv_display" ]; then
echo -e "$venv_display"
fi
}
# Python version display (shows current Python version)
parse_python() {
if command -v python &> /dev/null; then
local py_version=$(python --version 2>/dev/null | cut -d' ' -f2 | cut -d'.' -f1,2)
if [ -n "$py_version" ]; then
echo -e "\033[0;90m[py:${py_version}]\033[0m"
fi
fi
}
# Node.js version display (since you have nvm)
parse_node() {
if command -v node &> /dev/null; then
local node_version=$(node --version 2>/dev/null | sed 's/v//' | cut -d'.' -f1,2)
if [ -n "$node_version" ] && [ "$node_version" != "system" ]; then
echo -e "\033[0;90m[node:${node_version}]\033[0m"
fi
fi
}
# Git stash indicator
parse_git_stash() {
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
local stash_count=$(git stash list 2>/dev/null | wc -l)
if [ "$stash_count" -gt 0 ]; then
echo -e "\033[0;90m[stash:${stash_count}]\033[0m"
fi
fi
}
# Choose which git function to use (complex or simple)
GIT_FUNCTION="parse_git_branch" # Change to "parse_git_branch_simple" for simpler version
# Disable default venv prompt (we handle it ourselves)
export VIRTUAL_ENV_DISABLE_PROMPT=1
# Optional components (comment out what you don't want)
SHOW_PYTHON_VERSION=true
SHOW_NODE_VERSION=true # Set to true if you want Node version
SHOW_GIT_STASH=true
if [ "$color_prompt" = yes ]; then
# Build the prompt dynamically
prompt_parts=()
# Virtual environment
prompt_parts+=('$(parse_venv)')
# User@host:path
prompt_parts+=('\[\e[1;32m\]\u@\h\[\e[0m\]β–Ά\[\e[1;34m\]\w\[\e[0m\]')
# Git branch with status
prompt_parts+=('$('"$GIT_FUNCTION"')')
# Optional components
[ "$SHOW_PYTHON_VERSION" = true ] && prompt_parts+=('$(parse_python)')
[ "$SHOW_NODE_VERSION" = true ] && prompt_parts+=('$(parse_node)')
[ "$SHOW_GIT_STASH" = true ] && prompt_parts+=('$(parse_git_stash)')
# Final prompt symbol
prompt_parts+=('\[\e[1;37m\]❯\[\e[0m\] ')
# Join all parts with spaces
#PS1=$(IFS=' '; echo "${prompt_parts[*]}")
PS1=""
for part in "${prompt_parts[@]}"; do
PS1+="${part}"
done
else
PS1='$(parse_venv)\u@\h:\w$('"$GIT_FUNCTION"')\$ '
fi
unset color_prompt force_color_prompt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment