#!/usr/bin/env lowfat-filter
# git-compact — compact git output for LLM contexts
# env: $sub $level $exit $args
# ── shared helpers ────────────────────────────────────────────────
define strip-trailers:
drop /^[[:space:]]*(Signed-off-by|Co-authored-by|Change-Id|Reviewed-by|Acked-by|Tested-by|Reported-by|Cc):/
define abbrev-hash:
shell: sed -E 's/^commit ([0-9a-f]{12})[0-9a-f]{28}/commit \1/'
# State machine: drop pre-hunk metadata (--- +++ index mode), drop
# unchanged context, strip @@ function-context tail when ultra.
define compact-diff(limit):
shell: |
awk -v lim=$1 -v lvl=$level '
BEGIN { in_hunk=0; n=0 }
n>=lim { exit }
/^diff / { in_hunk=0; print; n++; next }
/^@@ / { in_hunk=1
if (lvl=="ultra" && match($0,/ @@/))
print substr($0,1,RSTART+2)
else print
n++; next }
lvl=="ultra" { next }
in_hunk && /^[+-]/ { print; n++ }
'
# ── status ────────────────────────────────────────────────────────
# File entries: long-format indents them with a tab; short/porcelain (`-s`)
# prefixes two status-code columns. At full/lite we also keep the section
# headers ("On branch", "Changes …", "Untracked …", "## branch" for porcelain)
# since they carry staged-vs-unstaged context; ultra strips them down to
# file entries only.
status:
match level:
ultra:
keep /^(\t|[ MADRCU?!]{2} )/
head 15
or "git status: clean"
lite:
keep /^(\t|[ MADRCU?!]{2} |## |On branch|Changes|Untracked)/
head 60
or "git status: clean"
else:
keep /^(\t|[ MADRCU?!]{2} |## |On branch|Changes|Untracked)/
head 30
or "git status: clean"
# ── diff ──────────────────────────────────────────────────────────
diff:
if exit failed:
raw
elif level ultra:
compact-diff 30
or-shell: awk 'NF' | head -50
elif level lite:
compact-diff 400
or-shell: awk 'NF' | head -50
else:
compact-diff 200
or-shell: awk 'NF' | head -50
# ── log ───────────────────────────────────────────────────────────
log:
match level:
ultra:
keep /^(commit | )/
strip-trailers
abbrev-hash
head 10
lite:
strip-trailers
abbrev-hash
head 50
else:
strip-trailers
abbrev-hash
head 25
# ── show ──────────────────────────────────────────────────────────
# Lite is permissive — preserve full context (incl. unchanged lines); only
# strip trailers + abbreviate the hash, and drop pre-hunk index/mode meta
# which always duplicates the path already on `diff --git`.
define drop-index-meta:
drop /^(index [0-9a-f]+\.\.[0-9a-f]+( [0-7]+)?|new file mode |deleted file mode |old mode |new mode |similarity index |dissimilarity index |rename from |rename to |copy from |copy to |---|\+\+\+) /
show:
match level:
ultra:
keep /^(commit |Author:|Date:| |diff --git)/
strip-trailers
abbrev-hash
head 20
lite:
strip-trailers
abbrev-hash
drop-index-meta
head 200
else:
# split at first `diff `, run separate chains on each half
split /^diff /
pre:
keep /^(commit |Merge:|Author:|Date:| )/
strip-trailers
abbrev-hash
post:
compact-diff 100
head 100
# ── default ───────────────────────────────────────────────────────
*:
head 30