# https://github.com/Tenemo/aliases.sh
#
# Default location on Windows: C:\Program Files\Git\etc\profile.d\aliases.sh
# Default location on MacOS: ~/.zshrc
# After updating, run `source ~/.zshrc` (Mac) or restart terminal (Windows) to apply.
# It's aliases all the way down.
unalias aliases 2>/dev/null
aliases() {
if [ "$(uname)" = "Darwin" ]; then
local SRC="$HOME/.zshrc"
if [ -f "$SRC" ]; then
grep '^[[:space:]]*alias ' "$SRC" | sed 's/^[[:space:]]*alias[[:space:]]*//'
else
alias | sed 's/^alias //' | sort
fi
else
local SRC="/c/Program Files/Git/etc/profile.d/aliases.sh"
if [ -f "$SRC" ]; then
grep '^[[:space:]]*alias ' "$SRC" | sed 's/^[[:space:]]*alias[[:space:]]*//'
else
alias | sed 's/^alias //' | sort
fi
fi
}
if [ "$(uname)" = "Darwin" ]; then
alias ls='ls -F -G'
else
alias ls='ls -F --color=auto --show-control-chars'
fi
alias ll='ls -l'
# For working with LLMs
concat() {
local DIRECTORY_TO_SEARCH="${1:-./}"
local OUTPUT_FILE="temp.txt"
local TMP_FINAL="${OUTPUT_FILE}.final.tmp"
local TMP_TREE="${OUTPUT_FILE}.tree.tmp"
local TMP_EXCL_DIRS="${OUTPUT_FILE}.excluded_dirs.tmp"
local TMP_EXCL_FILES="${OUTPUT_FILE}.excluded_files.tmp"
local TMP_CONTENTS="${OUTPUT_FILE}.contents.tmp"
if [ ! -d "$DIRECTORY_TO_SEARCH" ]; then
echo "concat: directory not found: $DIRECTORY_TO_SEARCH" >&2
return 2
fi
# ── Exclude these directories completely (existence only; DO NOT scan inside) ──
local EXCLUDED_DIRECTORIES=(
"node_modules" ".git" "dist" ".husky" "fonts" "target" "benches" ".github"
"coverage" ".pio" ".vscode" ".idea" "__pycache__"
".venv" "venv" "build" "bin" "obj" ".gradle" ".terraform" ".m2" ".cache"
)
# ── Exclude specific filenames (outside excluded dirs) ──
local EXCLUDED_FILES=(
"package-lock.json" "yarn.lock" "LICENSE" ".gitignore"
"c_cpp_properties.json" "launch.json" "settings.json" "Cargo.lock"
)
# ── Exclude extensions (outside excluded dirs) ──
local EXCLUDED_FILE_EXTENSIONS=(
"jpg" "jpeg" "png" "ico" "webp" "svg" "gif" "mp4" "pdf"
"exe" "dll" "bin" "zip" "tar" "gz" "iso"
)
# Skip files larger than this (0 disables); size check uses stat (metadata), not reading the file
local MAX_BYTES=$((2 * 1024 * 1024)) # 2 MiB
# Internal files created by this function (do not include in tree/excluded lists/contents)
# Note: only skipped when they are at repo root (REL == name).
local INTERNAL_ROOT_FILES=(
"$OUTPUT_FILE"
"$TMP_FINAL" "$TMP_TREE" "$TMP_EXCL_DIRS" "$TMP_EXCL_FILES" "$TMP_CONTENTS"
"${OUTPUT_FILE}.tmp" "${OUTPUT_FILE}.excluded" "${OUTPUT_FILE}.tmp.tmp"
)
# ── Fast membership sets ──
declare -A EXCL_DIR_SET
declare -A EXCL_FILE_SET
declare -A EXCL_EXT_SET
declare -A INTERNAL_ROOT_SET
local d f e
for d in "${EXCLUDED_DIRECTORIES[@]}"; do EXCL_DIR_SET["$d"]=1; done
for f in "${EXCLUDED_FILES[@]}"; do EXCL_FILE_SET["$f"]=1; done
for e in "${EXCLUDED_FILE_EXTENSIONS[@]}"; do EXCL_EXT_SET["$e"]=1; done
for f in "${INTERNAL_ROOT_FILES[@]}"; do INTERNAL_ROOT_SET["$f"]=1; done
# ── Helpers ──
_file_size_bytes() {
# echo size in bytes, metadata-only when possible
local fp="$1" s=""
if s=$(stat -c %s -- "$fp" 2>/dev/null); then printf '%s' "$s"; return 0; fi
if s=$(stat -f %z -- "$fp" 2>/dev/null); then printf '%s' "$s"; return 0; fi
wc -c < "$fp" 2>/dev/null
}
_indent_for_rel() {
# prints indentation for a relative path based on depth
local rel="$1"
local slashes="${rel//[^\/]/}"
local depth="${#slashes}"
local nspaces=$((2 * (depth + 1)))
printf '%*s' "$nspaces" ""
}
# ── Init temps ──
: > "$TMP_TREE" || return 1
: > "$TMP_EXCL_DIRS" || return 1
: > "$TMP_EXCL_FILES" || return 1
: > "$TMP_CONTENTS" || return 1
# Root line for tree
echo "// ." >> "$TMP_TREE"
# ── Build a single find command that:
# - prints excluded dirs, then prunes them (so we never see their children)
# - prints everything else (dirs + files)
local FIND_CMD=()
FIND_CMD+=(find .)
# \( -type d \( -name A -o -name B ... \) -print0 -prune \) -o -print0
FIND_CMD+=( \( -type d \( )
local first=1
for d in "${EXCLUDED_DIRECTORIES[@]}"; do
if [ $first -eq 1 ]; then
FIND_CMD+=(-name "$d")
first=0
else
FIND_CMD+=(-o -name "$d")
fi
done
FIND_CMD+=( \) -print0 -prune \) -o -print0 )
# ── Single traversal (never walks inside excluded dirs due to -prune) ──
local included_count=0
local excluded_file_count=0
local pruned_dir_count=0
while IFS= read -r -d '' ITEM; do
# Normalize relative path (strip leading ./)
local REL="${ITEM#./}"
[ -z "$REL" ] && continue # skip "."
# Skip internal files only if they are at root (REL matches exactly)
if [[ ${INTERNAL_ROOT_SET["$REL"]+x} ]]; then
continue
fi
local FULLPATH="$DIRECTORY_TO_SEARCH/$REL"
local INDENT; INDENT="$(_indent_for_rel "$REL")"
local BASENAME="${REL##*/}"
# Directory entry
if [ -d "$FULLPATH" ]; then
if [[ ${EXCL_DIR_SET["$BASENAME"]+x} ]]; then
# Excluded directory: note existence, do not scan children (already pruned by find)
echo "// ${INDENT}${BASENAME}/ [excluded-dir]" >> "$TMP_TREE"
echo "$REL" >> "$TMP_EXCL_DIRS"
pruned_dir_count=$((pruned_dir_count + 1))
else
echo "// ${INDENT}${BASENAME}/" >> "$TMP_TREE"
fi
continue
fi
# File entry
if [ -f "$FULLPATH" ]; then
# Determine extension (lowercase)
local EXT=""
if [[ "$BASENAME" == *.* ]]; then
EXT="${BASENAME##*.}"
EXT="${EXT,,}"
fi
local EXT_TAG
if [ -n "$EXT" ]; then EXT_TAG=".$EXT"; else EXT_TAG="(noext)"; fi
# Classify exclusion/inclusion (outside excluded dirs only, by construction)
local REASON=""
# excluded by exact filename
if [[ ${EXCL_FILE_SET["$BASENAME"]+x} ]]; then
REASON="name"
# excluded by extension
elif [ -n "$EXT" ] && [[ ${EXCL_EXT_SET["$EXT"]+x} ]]; then
REASON="ext"
# unreadable
elif [ ! -r "$FULLPATH" ]; then
REASON="unreadable"
# size cap (metadata)
elif [ "$MAX_BYTES" -gt 0 ]; then
local SIZE; SIZE="$(_file_size_bytes "$FULLPATH")" || SIZE=0
if [ -n "$SIZE" ] && [ "$SIZE" -gt "$MAX_BYTES" ] 2>/dev/null; then
REASON="size"
fi
fi
# binary detection (only if not excluded yet)
if [ -z "$REASON" ] && [ -s "$FULLPATH" ]; then
# Fast binary sniff: grep reads minimally for empty pattern, and -I rejects binary
if ! LC_ALL=C grep -Iq '' -- "$FULLPATH"; then
REASON="binary"
fi
fi
if [ -n "$REASON" ]; then
# Excluded file: record it, include only as a name in tree
echo "// ${INDENT}${BASENAME} [excluded]" >> "$TMP_TREE"
printf '%s\t%s\t%s\n' "$EXT_TAG" "$REL" "$REASON" >> "$TMP_EXCL_FILES"
excluded_file_count=$((excluded_file_count + 1))
continue
fi
# Included file
echo "// ${INDENT}${BASENAME}" >> "$TMP_TREE"
printf '\n// Contents of: "%s"\n' "$REL" >> "$TMP_CONTENTS"
cat -- "$FULLPATH" >> "$TMP_CONTENTS"
included_count=$((included_count + 1))
fi
done < <(cd "$DIRECTORY_TO_SEARCH" && "${FIND_CMD[@]}")
# ── Build final output (ALL in temp.txt) ──
: > "$TMP_FINAL" || return 1
{
echo "// concatenate snapshot"
echo "// root: $DIRECTORY_TO_SEARCH"
echo "//"
echo "// Included files (contents copied): $included_count"
echo "// Excluded files (names only): $excluded_file_count"
echo "// Excluded directories (pruned): $pruned_dir_count"
echo "// Max file size for inclusion: $MAX_BYTES bytes (0 disables)"
echo "//"
echo "// NOTE: Excluded directories are listed but NOT traversed; no child entries are present."
echo
echo "// === FILE TREE (PRUNED) ==="
cat "$TMP_TREE"
echo
echo "// === EXCLUDED DIRECTORIES (EXISTENCE ONLY; NOT SCANNED) ==="
if [ -s "$TMP_EXCL_DIRS" ]; then
sort -u "$TMP_EXCL_DIRS" | sed 's#^#// - #; s#$#/#'
else
echo "// (none)"
fi
echo
echo "// === EXCLUDED FILES (NAMES ONLY; OUTSIDE PRUNED DIRS) ==="
echo "// Grouped by extension."
if [ -s "$TMP_EXCL_FILES" ]; then
# Sort by extension then path, group by extension; output ONLY paths (no reasons)
sort -t
#039;\t' -k1,1 -k2,2 "$TMP_EXCL_FILES" \
| awk -F'\t' '
BEGIN { cur="" }
{
ext=$1; path=$2;
if (ext != cur) {
if (cur != "") print "//"
cur = ext
print "// " cur ":"
}
print "// " path
}'
else
echo "// (none)"
fi
echo
echo "// === INCLUDED FILE CONTENTS ==="
cat "$TMP_CONTENTS"
} >> "$TMP_FINAL"
mv -f "$TMP_FINAL" "$OUTPUT_FILE" || return 1
# cleanup
rm -f "$TMP_TREE" "$TMP_EXCL_DIRS" "$TMP_EXCL_FILES" "$TMP_CONTENTS"
# Optional: keep terminal quiet; comment this out if you truly want zero output
local OUTPUT_SIZE_BYTES OUTPUT_SIZE_KB OUTPUT_LINES
OUTPUT_SIZE_BYTES="$(_file_size_bytes "$OUTPUT_FILE" 2>/dev/null)" || OUTPUT_SIZE_BYTES="?"
OUTPUT_LINES="$(wc -l < "$OUTPUT_FILE" 2>/dev/null | tr -d '[:space:]')" || OUTPUT_LINES="?"
[ -n "$OUTPUT_SIZE_BYTES" ] || OUTPUT_SIZE_BYTES="?"
[ -n "$OUTPUT_LINES" ] || OUTPUT_LINES="?"
if [ "$OUTPUT_SIZE_BYTES" = "?" ]; then
OUTPUT_SIZE_KB="?"
else
OUTPUT_SIZE_KB="$(awk "BEGIN { printf \"%.2f\", $OUTPUT_SIZE_BYTES / 1024 }")"
fi
echo "Wrote $OUTPUT_FILE: ${OUTPUT_SIZE_KB} KB, ${OUTPUT_LINES} lines" >&2
}
alias i='npm install'
unalias s 2>/dev/null
s() {
npm start
local STATUS=$?
if [ "$STATUS" -eq 130 ]; then
return 130
fi
if [ "$STATUS" -ne 0 ]; then
npm run dev
return $?
fi
return 0
}
alias r='npm run'
alias b='npm run build'
alias d='npm run deploy'
alias bs='npm run build:skip'
alias t='npm test'
alias u='npm test -- -u'
alias od='npm outdated'
alias up='npm update'
alias un='npm uninstall'
alias cu='ncu --packageFile package.json'
alias cuu='ncu --packageFile package.json -u && rm -rf package-lock.json node_modules && npm install'
alias cxuu='ncu --packageFile package.json -u -x "history" && rm -rf package-lock.json node_modules && npm install'
alias cruu='ncu --packageFile package.json -u -x react,react-dom && rm -rf package-lock.json node_modules && npm install'
alias global='npm list -g --depth 0'
alias globaloutdated='npm outdated -g --depth=0'
alias nuke_modules='rm -rf node_modules package-lock.json && npm install'
alias nuke_modules_nolock='rm -rf node_modules && npm install'
alias nuke_clean='rm -rf node_modules && npm ci' # Safer, uses lockfile exactly
alias gla='git config -l | grep alias | cut -c 7-'
alias gcl='git clone'
alias ga='git add'
alias gs='git status'
alias gcp='git cherry-pick'
alias gco='git checkout'
alias gcob='git checkout -b'
alias gcoo='git fetch && git checkout'
alias gdev='git checkout development && git pull origin development'
alias gstaging='git checkout staging && git pull origin staging'
alias gmaster='git checkout master && git pull origin master'
alias gmain='git checkout main && git pull origin main'
alias gc='git commit'
alias gamend='git commit --amend --no-edit'
alias gaamend='git add . && git commit --amend --no-edit'
gcm() {
[ $# -gt 0 ] || { echo "Usage: gcm <commit message>" >&2; return 2; }
git commit -m "$*"
}
gac() {
[ $# -gt 0 ] || { echo "Usage: gac <commit message>" >&2; return 2; }
git add . && git commit -m "$*"
}
gacgo() {
[ $# -gt 0 ] || { echo "Usage: gacgo <commit message>" >&2; return 2; }
git add . && git commit -m "$*" --no-verify
}
gogo() {
[ $# -gt 0 ] || { echo "Usage: gogo <commit message>" >&2; return 2; }
git add . && git commit -m "$*" && git push origin
}
gogogo() {
# WARNING: This skips pre-commit hooks. Use with caution.
[ $# -gt 0 ] || { echo "Usage: gogogo <commit message>" >&2; return 2; }
git add . && git commit -m "$*" --no-verify && git push origin --no-verify
}
listall() {
find . \
-not -path "./node_modules/*" \
-not -path "./.git/*" \
-not -path "./.husky/*" \
-type f -print | sed 's|^\./||'
}
alias gbr='git branch'
alias gbrd='git branch -d'
alias gdlc='git diff --cached HEAD^ -- ":(exclude)package-lock.json"'
gdc() {
if [ -n "$1" ]; then
git diff "$1" --cached -- ":(exclude)package-lock.json"
else
git diff --cached -- ":(exclude)package-lock.json"
fi
}
gdiff() {
if [ -n "$1" ]; then
git diff "$1" --word-diff -- ":(exclude)package-lock.json"
else
git diff --word-diff -- ":(exclude)package-lock.json"
fi
}
gdiffloc() {
if [ -n "$1" ]; then
git diff --shortstat "$1" -- ":(exclude)package-lock.json"
else
git diff --shortstat -- ":(exclude)package-lock.json"
fi
}
alias gplo='git pull origin'
alias gplod='git pull origin development'
alias gplos='git pull origin staging'
alias gplom='git pull origin master'
alias gplomain='git pull origin main'
unalias gploh 2>/dev/null
gploh() {
local BRANCH
BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
if [ -z "$BRANCH" ] || [ "$BRANCH" = "HEAD" ]; then
echo "gploh: not on a branch (detached HEAD). Use: git pull <remote> <branch>" >&2
return 2
fi
git pull origin "$BRANCH"
}
alias gpo='git push origin'
alias gforce='git push origin --force-with-lease'
alias gpod='git push origin development'
alias gpos='git push origin staging'
alias gpom='git push origin master'
alias gpomain='git push origin main'
alias gpoh='git push origin HEAD'
alias gr='git reset'
alias gr1='git reset HEAD^'
alias gr2='git reset HEAD^^'
alias grh='git reset --hard'
alias grh1='git reset HEAD^ --hard'
alias grh2='git reset HEAD^^ --hard'
alias gunstage='git reset --soft HEAD^'
alias gst='git stash'
alias gsl='git stash list'
alias gsa='git stash apply'
alias gss='git stash push'
alias ggr='git log --graph --full-history --all --color --pretty=tformat:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s%x20%x1b[33m(%an)%x1b[0m"'
alias gls='git log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate'
alias gll='git log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --numstat'
alias gld='git log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --date=relative'
alias glds='git log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --date=short'
unalias gdl 2>/dev/null
gdl() {
if git config --get alias.ll >/dev/null 2>&1; then
git ll -1
else
git log -1
fi
}
alias gprune='git remote update origin --prune'
if [ "$(uname)" != "Darwin" ]; then
case "$TERM" in
xterm*)
# The following programs are known to require a Win32 Console
# for interactive usage, therefore let's launch them through winpty
# when run inside `mintty`.
for name in node ipython php php5 psql python2.7 python python3
do
case "$(type -p "$name".exe 2>/dev/null)" in
''|/usr/bin/*) continue;;
esac
alias $name="winpty $name.exe"
done
;;
esac
fi