# @references:
#    https://git-scm.com/docs/git-config
#    https://dzone.com/articles/how-to-use-gitconfigs-includeif
#    https://specifications.freedesktop.org/basedir-spec/latest/
#
# Identity (user.name / user.email / signingkey) is set by `infra setup git`
# and `infra setup gpg` — never bake real name/email/key ids into this file.
#
# Keep this file at ~/.gitconfig so `git config --global` keeps writing here.
# Companion files use XDG: ~/.config/git/{ignore,message,mailmap,attributes}.
#
[init]
    defaultBranch = main
#   templatedir = ~/.infra/templates/git/templates/

[user]
    # name / email are set by `infra setup git` from setup.user_name / user_email
    # (do not put placeholders here — they look "set" and block updates).
    # signingkey = ABCDEFGH12345678

# Per-tree identity overrides (create the sidecar files yourself):
#   ~/.gitconfig-work     → work email / signing key
#   ~/.gitconfig-personal → personal email / signing key
[includeIf "gitdir/i:~/projects/work/"]
    path = ~/.gitconfig-work
[includeIf "gitdir/i:~/projects/personal/"]
    path = ~/.gitconfig-personal

[commit]
    template = ~/.config/git/message
    # gpgsign is set by `infra setup gpg` when a signing key exists (do not force false).

# Global mailmap (repo-root .mailmap still wins when present). See git/mailmap.
[mailmap]
    file = ~/.config/git/mailmap

# OpenPGP (GnuPG) signing — not SSH signing (gpg.format=ssh expects a key path).
[gpg]
    format = openpgp
# Prefer whatever `gpg` is on PATH (Intel Homebrew, Apple Silicon, or Linux).
#   program = gpg

[core]
    editor = vim
    autocrlf = input
    ignorecase = false
    # Official default is already ~/.config/git/ignore; set explicitly for clarity.
    excludesfile = ~/.config/git/ignore
    attributesfile = ~/.config/git/attributes
    # git-delta (installed via os_setup). Falls back if missing: unset pager.
    pager = delta
    # hooksPath = ~/.infra/templates/git/hooks/

[interactive]
    diffFilter = delta --color-only

[delta]
    navigate = true
    line-numbers = true
    side-by-side = false
    hyperlinks = true

[alias]
    # General
    st = status
    co = checkout
    com = "! f() { git checkout main 2>/dev/null || git checkout master; }; f"
    cob = !git branch -a | fzf | xargs git checkout
    br = branch
    brc = branch --show-current
    brd = "!f() { git checkout main 2>/dev/null || git checkout master; git branch -d @{-1}; }; f"
    cp = cherry-pick
    ci = commit
    pu = push
    poh = push -u origin HEAD
    # Fetch/pull: only current branch + main/master (not every remote tip).
    # Plain `git pull` / `git fetch` still use remote.*.fetch (often refs/heads/*).
    pf = "!f() { b=$(git branch --show-current) || exit 1; r=${1:-origin}; git fetch \"$r\" \"$b\" main 2>/dev/null || git fetch \"$r\" \"$b\" master; }; f"
    pl = "!f() { b=$(git branch --show-current) || exit 1; r=$(git config --get branch.\"$b\".remote 2>/dev/null || echo origin); git pf \"$r\" && git pull --rebase --autostash \"$r\" \"$b\"; }; f"
    # Annotated-style lightweight tag: <branch>-<shortsha>-<YYYYMMDDHHMMSS>
    # e.g. main-d48c535-20260826224032  (slashes in branch names → '-')
    tg = "!f() { b=$(git branch --show-current) || exit 1; [ -n \"$b\" ] || exit 1; b=$(printf '%s' \"$b\" | tr '/' '-'); h=$(git rev-parse --short HEAD); t=$(date +%Y%m%d%H%M%S); tag=\"${b}-${h}-${t}\"; git tag \"$tag\" && printf '%s\\n' \"$tag\"; }; f"
    # Delete a local tag (and remote origin tag when present): git tgd <tag>
    tgd = "!f() { tag=$1; [ -n \"$tag\" ] || { printf 'usage: git tgd <tag>\\n' >&2; exit 1; }; git tag -d \"$tag\" || exit 1; git push origin \":refs/tags/$tag\" 2>/dev/null || true; }; f"
    bl = blame

    # Logging
    lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
    last = log -1 HEAD
    lgf = !sh -c \"git log -m -1 --name-only --pretty=format:\" -

    # Diff
    di = diff
    df = diff
    dc = diff --cached
    d3 = diff --color --diff-algorithm=histogram --word-diff=color --ignore-all-space
    d3c = diff --cached --color --diff-algorithm=histogram --word-diff=color --ignore-all-space
    dim = "!sh -c 'git diff $(git branch -a | sed -n -E -e \"/remotes.origin.ma(in|ster)$/s@remotes/origin/@@p\") HEAD --name-only'"

    # Submodule (each module: current branch + main/master only)
    sbi = submodule init
    sbu = submodule update
    sbp = "!git submodule foreach 'b=$(git branch --show-current); r=$(git config --get branch.\"$b\".remote 2>/dev/null || echo origin); git fetch \"$r\" \"$b\" main 2>/dev/null || git fetch \"$r\" \"$b\" master; git pull --rebase --autostash \"$r\" \"$b\"'"
    sbc = "!f() { git submodule foreach 'git checkout main 2>/dev/null || git checkout master'; }; f"

    # Fork / PR helpers
    prq = !sh -c \"git fetch upstream refs/pull/$1/head:pr-$1 && git checkout pr-$1\" -
    dpr = !sh -c \"git branch | grep pr- | xargs git branch -D\" -
    # Prefer hooks on; use --no-verify only when you intentionally own the bypass.
    sync = "!f() { git com && git pl && git push origin HEAD; }; f"

    # Clean up
    done = "!f() { git com && git pl && git branch --merged | grep -v '*' | xargs -n 1 git branch -d; }; f"

[pull]
    rebase = true

[push]
    default = simple
    autoSetupRemote = true

[fetch]
    prune = true
    # Avoid implying fetch of every configured remote (`git fetch --all`).
    all = false

[rebase]
    autoStash = true

[rerere]
    enabled = true

[branch]
    sort = -committerdate

[tag]
    sort = version:refname

[protocol]
    version = 2

[diff]
    algorithm = histogram

[merge]
    tool = vimdiff
    conflictstyle = zdiff3

[color]
    ui = auto

[filter "lfs"]
    clean = git-lfs clean -- %f
    smudge = git-lfs smudge -- %f
    process = git-lfs filter-process
    # false: repos without LFS still work; `git lfs install` wires filters when needed.
    required = false
