Git Config & Setup
Git configuration: aliases, hooks, ignore patterns, and repository setup.
Config Fundamentals
# CONFIG LEVELS (lowest to highest priority)
# system: /etc/gitconfig (all users)
# global: ~/.gitconfig or ~/.config/git/config (current user)
# local: .git/config (current repo)
# worktree: .git/config.worktree (current worktree)
# VIEW CONFIG
git config --list # All settings, all levels
git config --list --show-origin # With source file
git config --list --show-scope # With scope level
git config --list --local # Repo-only settings
git config --list --global # User-only settings
# GET SPECIFIC VALUE
git config user.name # Current effective value
git config --get-all user.email # All values (if multiple)
git config --show-origin user.name # Value + which file set it
# SET VALUES
git config --global user.name "Evan Rosado"
git config --global user.email "evan@example.com"
git config --local core.autocrlf false # Repo-specific
# UNSET VALUES
git config --global --unset core.editor # Remove setting
git config --global --unset-all push.default # Remove all matching
# EDIT CONFIG DIRECTLY
git config --global --edit # Open global in editor
git config --local --edit # Open repo config in editor
# CONDITIONAL INCLUDES
# In ~/.gitconfig:
# [includeIf "gitdir:~/work/"]
# path = ~/.gitconfig-work
# [includeIf "gitdir:~/personal/"]
# path = ~/.gitconfig-personal
# Different user.email per directory tree
# USEFUL GLOBAL SETTINGS
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global fetch.prune true
git config --global diff.colorMoved zebra
git config --global rerere.enabled true # Remember conflict resolutions
git config --global core.editor "nvim"
git config --global merge.conflictstyle diff3
Aliases
# SIMPLE ALIASES
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.sw switch
# LOG ALIASES
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.recent "log --oneline -10"
# DIFF ALIASES
git config --global alias.staged "diff --staged"
git config --global alias.words "diff --word-diff"
# SHELL FUNCTION ALIASES (prefix with !)
# These run in sh, not as git subcommands
git config --global alias.acp '!f() { git add -A && git commit -m "$1" && git push; }; f'
git config --global alias.fresh '!git fetch origin && git reset --hard origin/main'
# COMPLEX ALIASES
# Show branches sorted by last commit
git config --global alias.recent-branches '!git for-each-ref --sort=-committerdate refs/heads/ --format="%(committerdate:relative) %(refname:short)"'
# Quick amend without message change
git config --global alias.amend 'commit --amend --no-edit'
# Undo last commit (keep changes staged)
git config --global alias.undo 'reset --soft HEAD~1'
# LIST ALL ALIASES
git config --get-regexp alias # Raw
git config --get-regexp alias | awk -F'[. ]' '{printf "%-20s %s\n", $2, substr($0,index($0,$3))}'
# DELETE ALIAS
git config --global --unset alias.old-alias
# ZSH FUNCTION ALTERNATIVES (from .zshrc)
# gach() { git add -A && git commit -m "$(cat)"; }
# gacp() { git add -A && git commit -m "$(cat)" && git push; }
# These are MORE flexible than git aliases for heredoc commits
Hooks
# HOOK LOCATION
# Default: .git/hooks/ (local, not tracked)
# Shared: Use core.hooksPath for team-wide hooks
# CONFIGURE HOOKS PATH
git config core.hooksPath .githooks # Use tracked .githooks/ directory
# Now hooks in .githooks/ apply to this repo
# COMMON HOOKS
# pre-commit: Runs before commit is created
# commit-msg: Runs after message entered, before commit finalized
# pre-push: Runs before push
# post-checkout: Runs after checkout/switch
# post-merge: Runs after merge
# EXAMPLE: PRE-COMMIT (lint/format check)
cat > .git/hooks/pre-commit << 'HOOK'
#!/bin/bash
# Prevent committing to main directly
branch=$(git symbolic-ref --short HEAD)
if [[ "$branch" == "main" ]]; then
echo "ERROR: Direct commits to main are not allowed"
echo "Create a feature branch first"
exit 1
fi
HOOK
chmod +x .git/hooks/pre-commit
# EXAMPLE: COMMIT-MSG (enforce conventional commits)
cat > .git/hooks/commit-msg << 'HOOK'
#!/bin/bash
msg=$(cat "$1")
pattern='^(feat|fix|docs|style|refactor|test|chore|ci|perf|build)(\(.+\))?: .+'
if ! echo "$msg" | grep -qE "$pattern"; then
echo "ERROR: Commit message must match conventional commits format"
echo "Examples: feat(auth): add OAuth support"
echo " fix: resolve null pointer in parser"
echo " docs(readme): update installation steps"
exit 1
fi
HOOK
chmod +x .git/hooks/commit-msg
# EXAMPLE: PRE-PUSH (run tests)
cat > .git/hooks/pre-push << 'HOOK'
#!/bin/bash
echo "Running tests before push..."
make test || {
echo "Tests failed! Push aborted."
exit 1
}
HOOK
chmod +x .git/hooks/pre-push
# BYPASS HOOKS (use sparingly)
git commit --no-verify -m "emergency fix"
git push --no-verify
# LIST HOOKS
ls -la .git/hooks/ # Local hooks
ls -la .githooks/ 2>/dev/null # Shared hooks directory
.gitignore Patterns
# GITIGNORE SYNTAX
# pattern → ignore matching files
# /pattern → only in repo root
# pattern/ → only directories
# !pattern → negate (unignore)
# **/pattern → any directory depth
# pattern/** → everything inside
# COMMON PATTERNS
# Build artifacts
*.o
*.pyc
__pycache__/
dist/
build/
*.egg-info/
# IDE/editor
.idea/
.vscode/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Secrets (CRITICAL)
.env
.env.*
*.pem
*.key
credentials.json
# GLOBAL GITIGNORE
git config --global core.excludesfile ~/.gitignore_global
# Put OS/editor patterns here, not in project .gitignore
# DEBUG: WHY IS FILE IGNORED?
git check-ignore -v file.txt
# Output: .gitignore:5:*.txt file.txt
# Shows which rule, which file, which line
# DEBUG: LIST ALL IGNORED FILES
git status --ignored # Basic
git ls-files --ignored --exclude-standard # All ignored files
# FORCE-ADD IGNORED FILE
git add -f secret-but-needed.conf # Override .gitignore
# STOP TRACKING (but keep file)
git rm --cached file.txt # Untrack without deleting
echo "file.txt" >> .gitignore # Prevent re-adding
# GITIGNORE NOT WORKING? (cached files)
# If file was tracked before .gitignore rule:
git rm -r --cached . # Untrack everything
git add . # Re-add (respects .gitignore)
git commit -m "chore: apply gitignore rules"
# WARNING: Large commit, every file re-staged
# TEMPLATES
# See: github.com/github/gitignore
.gitattributes
# LINE ENDINGS
# Normalize line endings in repo (LF), convert on checkout
* text=auto # Auto-detect text files
*.sh text eol=lf # Always LF for shell scripts
*.bat text eol=crlf # Always CRLF for batch files
*.adoc text eol=lf # AsciiDoc files
# BINARY FILES (don't diff, don't merge)
*.png binary
*.jpg binary
*.pdf binary
*.zip binary
# GIT LFS
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.iso filter=lfs diff=lfs merge=lfs -text
# CUSTOM DIFF DRIVERS
*.adoc diff=asciidoc # Better diffs for AsciiDoc
# MERGE STRATEGIES
# Always keep our version of lock files:
package-lock.json merge=ours
yarn.lock merge=ours
# EXPORT IGNORE (excluded from git archive)
.gitignore export-ignore
.gitattributes export-ignore
tests/ export-ignore
docs/ export-ignore
# LINGUIST (GitHub language detection)
docs/**/*.adoc linguist-documentation
vendor/** linguist-vendored
Infrastructure Config Patterns
# DOMUS-* REPO STANDARD CONFIG
# These settings are applied per-repo via .git/config
# Rebase on pull (avoid merge commits)
git config pull.rebase true
# Auto-prune on fetch
git config remote.origin.prune true
# Default push to current branch
git config push.default current
# CONVENTIONAL COMMITS ENFORCEMENT
# Most domus-* repos use this pattern:
# type(scope): description
# Types: feat, fix, docs, chore, refactor, test, ci, style
# MULTI-REMOTE CONFIG
# Standard domus-* remote setup:
git remote add origin git@github.com:EvanusModestus/repo.git
git remote add gitlab git@gitlab.com:EvanusModestus/repo.git
# SSH CONFIG INTEGRATION
# ~/.ssh/config defines Host aliases
# Vault SSH CA signs certificates for auth
# See: secrets-ops docs for vault-ssh-sign workflow
# GITIGNORE FOR DOMUS-* REPOS
# Standard ignores:
# build/ Antora build output
# node_modules/ Antora dependencies
# .env Local environment
# *.pdf Generated PDFs (some repos track these)
# VERIFY REPO CONFIG
git config --list --local --show-origin | awk -F'[=\t]' '{printf "%-30s %s\n", $2, $3}'
Config Gotchas
# WRONG: Setting user.name globally when using multiple identities
git config --global user.name "Personal Name"
# Work repos get personal identity!
# CORRECT: Use conditional includes
# ~/.gitconfig:
# [includeIf "gitdir:~/work/"]
# path = ~/.gitconfig-work
# ~/.gitconfig-work:
# [user]
# email = evan@work.com
# WRONG: Committing .gitignore changes without clearing cache
echo "secret.env" >> .gitignore
git add .gitignore && git commit -m "ignore secrets"
# secret.env is STILL tracked!
# CORRECT: Remove from index first
git rm --cached secret.env
echo "secret.env" >> .gitignore
git add .gitignore secret.env
git commit -m "chore: stop tracking secret.env"
# WRONG: Hooks not running
# Common causes:
# 1. Not executable
chmod +x .git/hooks/pre-commit
# 2. Wrong shebang
head -1 .git/hooks/pre-commit # Should be #!/bin/bash
# WRONG: Global gitignore overriding project needs
# Global: *.pdf in ~/.gitignore_global
# But domus-captures tracks PDFs!
# The global rule wins
# CORRECT: Force-add or use project .gitignore to negate
!*.pdf # In project .gitignore
# WRONG: Assuming hooks transfer with clone
git clone repo.git
# .git/hooks/ has only sample files!
# CORRECT: Use core.hooksPath for shared hooks
# In repo: .githooks/ directory (tracked)
# In config: git config core.hooksPath .githooks
# Document in README/CLAUDE.md
Quick Reference
# CONFIG
git config --list --show-origin # All settings + source
git config --global user.name "Name" # Set global
git config --local setting value # Set repo-only
git config --global --edit # Edit in editor
# ALIASES
git config --global alias.name "command" # Simple alias
git config --global alias.name '!f() { ...; }; f' # Shell function
git config --get-regexp alias # List all aliases
# HOOKS
ls .git/hooks/ # Local hooks
git config core.hooksPath .githooks # Shared hooks dir
chmod +x .git/hooks/hook-name # Make executable
# GITIGNORE
git check-ignore -v file.txt # Debug: why ignored?
git rm --cached file.txt # Stop tracking
git add -f file.txt # Force-add ignored file
# GITATTRIBUTES
* text=auto # Normalize line endings
*.png binary # Mark as binary
*.mp4 filter=lfs diff=lfs merge=lfs -text # Git LFS
See Also
-
Basics — day-to-day commands that config customizes
-
Remotes — multi-remote configuration
-
Filter-Repo — cleaning up after .gitignore failures