gitty is a backup machine: commit + push as much as possible, every run.
- paths that would block remote are held back locally; everything else goes through
- built into
gittyitself (not repopre-commit/pre-pushhooks) - drip-through on additive integrate: if resolvers clear some conflict paths and not others, commit the resolved subset; hold unresolved; do not park the whole merge (
GITTY_PARTIAL=1default)
git add -A
→ scan staged paths for offenders
→ unstage offenders (held back locally)
→ git commit
→ git push -f
→ if push rejects a file → unstage it, recommit, retry| Offender | When | Reason shown |
|---|---|---|
Submodule gitlink (160000) |
Pre-commit scan | submodule (use gittyembedded) |
| File over size limit | Pre-commit scan | exceeds push size limit (N bytes) |
| Push-rejected path | After failed push | push rejected |
| Pre-commit hook reject | Elimination drip (GITTY_PARTIAL=1) |
catalog [CODE] reason or offender stderr |
Default size limit: 100 MiB (GitHub hard limit)
- Override with
GITTY_MAX_FILE_BYTES
When git commit fails under GITTY_PARTIAL=1 and more than one path is staged:
- snapshot hook stderr
- unstage each path in turn; retry commit on the remainder
- on success, hold the eliminated path with
gitty_holdback_reason - catalog (optional):
.gitty/holdback-reasons.jsonorGITTY_HOLDBACK_CATALOGrules[].matchregex vs hook stderr →[code] reason(+ optionalfix)- no catalog / no match → specific offender stderr + exit code (never mute
pre-commit hook rejection)
Canonical test: tests/holdback-reason.smoke.sh
4 files modified
- file1 is a 150 MiB blob
- file2 is a submodule pointer
- file3, file4 commit + push normally
- held-back paths stay in your working tree unstaged
🟡 - Staging changes in /path/to/repo...
🔴 - huge.bin- held back (exceeds push size limit (500 bytes))
🟡 - 1 path(s) held back; proceeding with the rest
🟡 - Committing changes...
🟡 - Force pushing to remote...
── partial: commit/push ──
🟢 - ok.txt- committed and pushed
🟢 - fine.txt- committed and pushed
🔴 - huge.bin- not pushed (exceeds push size limit (500 bytes))
🟢 - partial success- 2 pushed, 1 held back
🟢 - Partial commit/push from /path/to/repo- if a file slips past pre-scan (or the host rejects it for another size-related reason):
gittyparses push error → holds that path back → soft-resets the last commit → recommits without it → retries
Retries: GITTY_PUSH_RETRIES (default 8).
- run:
tests/partial-commit.smoke.sh
npm run test:partial
# or
tests/partial-commit.smoke.shExpects: huge.bin held back (🔴), ok.txt + fine.txt pushed (🟢), partial success dashboard
On additive_git_integrate conflict:
- run
.gitty/additive-resolvers.yamlclasses - if all conflict paths resolve → commit the merge
- if some resolve (
GITTY_PARTIAL=1) → commit the resolved subset; hold the rest; report at end of run - if none can land → park on
bak/pending-merge-*(existing behavior)
Old all-or-nothing behavior:
GITTY_PARTIAL=0 gitty "message" /path/to/repogittydoes not recurse into submodules- submodule pointer changes in parent are held back so parent push is not blocked
- use
gittyembeddedwhen you intend to commit submodule work first → then parent
gittydoes not configure Git LFS. For LFS-tracked patterns, usegittylfs
On rebase conflict with remote (additive sync / stale-base autoheal), gitty holds back conflicting paths and commits+pushes the rest when GITTY_PARTIAL=1 (default). Hard-exits only if every path conflicts or GITTY_PARTIAL=0.