Skip to content

Instantly share code, notes, and snippets.

@subpath
Last active December 22, 2025 09:47
Show Gist options
  • Select an option

  • Save subpath/da4ba30a1319512dc9ab3e3db8f1d043 to your computer and use it in GitHub Desktop.

Select an option

Save subpath/da4ba30a1319512dc9ab3e3db8f1d043 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to check if we're in a git repository
check_git_repo() {
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${RED}Error: Not a git repository${NC}" >&2
exit 1
fi
}
# Function to get the exclude file path
get_exclude_file() {
local git_dir
git_dir=$(git rev-parse --git-dir)
echo "${git_dir}/info/exclude"
}
# Helper function to display file with bat or cat
display_with_bat() {
local file="$1"
if command -v bat &> /dev/null; then
bat "$file"
else
cat "$file"
fi
}
# Function to add a pattern to local exclude
add_pattern() {
local pattern="$1"
if [ -z "$pattern" ]; then
echo -e "${RED}Error: No pattern specified${NC}" >&2
echo "Usage: gex add <file-or-folder>" >&2
exit 1
fi
local exclude_file
exclude_file=$(get_exclude_file)
# Create the info directory if it doesn't exist
mkdir -p "$(dirname "$exclude_file")"
# Check if pattern already exists
if [ -f "$exclude_file" ] && grep -Fxq "$pattern" "$exclude_file"; then
echo -e "${YELLOW}Pattern '$pattern' already exists in local exclude${NC}"
return 0
fi
# Add the pattern
echo "$pattern" >> "$exclude_file"
echo -e "${GREEN}Added '$pattern' to local git exclude${NC}"
}
# Function to remove a pattern from local exclude
remove_pattern() {
local pattern="$1"
if [ -z "$pattern" ]; then
echo -e "${RED}Error: No pattern specified${NC}" >&2
echo "Usage: gex remove <pattern>" >&2
exit 1
fi
local exclude_file
exclude_file=$(get_exclude_file)
if [ ! -f "$exclude_file" ]; then
echo -e "${RED}Error: Exclude file doesn't exist${NC}" >&2
exit 1
fi
# Check if pattern exists and remove it
if ! grep -Fxq "$pattern" "$exclude_file"; then
echo -e "${YELLOW}Pattern '$pattern' not found in local exclude${NC}"
return 1
fi
# Remove the pattern (grep -v is simpler and more reliable than sed for literal strings)
grep -Fxv "$pattern" "$exclude_file" > "${exclude_file}.tmp" && mv "${exclude_file}.tmp" "$exclude_file"
echo -e "${GREEN}Removed '$pattern' from local git exclude${NC}"
}
# Function to show/edit the exclude file
show_exclude() {
local exclude_file
exclude_file=$(get_exclude_file)
local editor="${EDITOR:-code}"
# Create the file if it doesn't exist
if [ ! -f "$exclude_file" ]; then
mkdir -p "$(dirname "$exclude_file")"
touch "$exclude_file"
echo -e "${GREEN}Created new exclude file${NC}"
fi
"$editor" "$exclude_file"
}
# Function to display current exclude patterns
cat_exclude() {
local exclude_file
exclude_file=$(get_exclude_file)
if [ ! -f "$exclude_file" ]; then
echo -e "${YELLOW}No local exclude file found${NC}"
return 0
fi
display_with_bat "$exclude_file"
}
# Function to install gex to user's bin directory
install_gex() {
local script_path
script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
local install_dir="$HOME/.local/bin"
local install_path="$install_dir/gex"
# Create install directory if it doesn't exist
if [ ! -d "$install_dir" ]; then
mkdir -p "$install_dir"
echo -e "${GREEN}Created directory: $install_dir${NC}"
fi
# Copy the script
if [ "$script_path" = "$install_path" ]; then
echo -e "${YELLOW}Already installed at $install_path${NC}"
else
cp "$script_path" "$install_path"
chmod +x "$install_path"
echo -e "${GREEN}Installed gex to $install_path${NC}"
fi
# Detect shell config file
local shell_config=""
if [ -n "${ZSH_VERSION:-}" ] || [ -f "$HOME/.zshrc" ]; then
shell_config="$HOME/.zshrc"
elif [ -n "${BASH_VERSION:-}" ] || [ -f "$HOME/.bashrc" ]; then
shell_config="$HOME/.bashrc"
elif [ -f "$HOME/.bash_profile" ]; then
shell_config="$HOME/.bash_profile"
fi
# Check if install_dir is in PATH
if [[ ":$PATH:" != *":$install_dir:"* ]]; then
echo -e "${YELLOW}$install_dir is not in your PATH${NC}"
if [ -n "$shell_config" ]; then
# Check if PATH export already exists in shell config
if grep -q "export PATH=\"\$HOME/.local/bin:\$PATH\"" "$shell_config" 2>/dev/null || \
grep -q "export PATH=\"\$PATH:\$HOME/.local/bin\"" "$shell_config" 2>/dev/null; then
echo -e "${GREEN}PATH already configured in $shell_config${NC}"
else
# Add to PATH in shell config
echo "" >> "$shell_config"
echo "# Added by gex installer" >> "$shell_config"
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$shell_config"
echo -e "${GREEN}Added $install_dir to PATH in $shell_config${NC}"
echo -e "${YELLOW}Run 'source $shell_config' or restart your terminal to use gex${NC}"
fi
else
echo -e "${YELLOW}Could not detect shell config file${NC}"
echo "Add this line to your shell config manually:"
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
fi
else
echo -e "${GREEN}$install_dir is already in your PATH${NC}"
fi
echo ""
echo -e "${GREEN}Installation complete!${NC}"
echo "You can now use 'gex' from anywhere in your terminal."
echo "Try: gex help"
}
# Main command handler
main() {
local command="${1:-}"
shift || true
case "$command" in
add)
check_git_repo
add_pattern "$@"
;;
remove)
check_git_repo
remove_pattern "$@"
;;
show|open|edit)
check_git_repo
show_exclude
;;
cat|view)
check_git_repo
cat_exclude
;;
install)
install_gex
;;
help|--help|-h|"")
echo "gex - Git Local Exclude Manager"
echo ""
echo "Usage:"
echo " gex add <pattern> Add a pattern to .git/info/exclude"
echo " gex remove <pattern> Remove a pattern from .git/info/exclude"
echo " gex cat Display .git/info/exclude contents"
echo " gex show Open .git/info/exclude in \$EDITOR (default: code)"
echo " gex install Install gex to ~/.local/bin and add to PATH"
echo ""
echo "Examples:"
echo " gex install"
echo " gex add node_modules"
echo " gex add \"*.log\""
echo " gex remove node_modules"
echo " gex cat"
echo " gex show"
;;
*)
echo -e "${RED}Error: Unknown command '$command'${NC}" >&2
echo "Run 'gex help' for usage information" >&2
exit 1
;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment