flowchart LR
T[tree] --> Q{can this path land?}
Q -->|yes| P[commit + push]
Q -->|conflict / too big / submodule / hook reject| H[hold back]
P --> R[keep going]
H --> R
R --> F{anything still blocked?}
F -->|held some| D[remote has the rest]
F -->|nothing landed| K[park bak/pending-merge]
-
one conflicted, oversized, or submodule path parks the whole checkpoint
-
the rest of the tree sits unbacked on that machine
-
drip: push the clean subset; hold the rest; never stall the backup
-
laptop + desktop both edit
-
N local commits replay against remote -> same conflict N times
-
other machine's work never left that machine
-
agents touch many repos per session
-
add+commit+pushper repo burns time -
one blocker used to abort the whole run
-
pre-commit rejects one path (context-pollution, tilde, policy)
-
rest of the staged tree was fine
-
drip: hook reports offender via
GITTY_HOLDBACK; one retry lands the rest; hold with a specific reason
-
two hosts append different
.ndjson/.jsonllines -
git sees one slot, two lines -> conflict
-
nothing was edited; both lines should keep
| Bin | Job | When |
|---|---|---|
gitty |
drip + holdback -> commit -> push | default backup |
gittylfs |
same + LFS track | big binaries |
gittyembedded |
submodules then parent | dirty nested repos |
gittyhealth |
report only | inspect / mid-op |
gittysnap |
snap -> merge -> abort clean | solo multi-machine |
gittyplunger |
trap -> rebuild unpushed range -> hold clog | buried oversized blobs |
gittyunion |
NDJSON union driver | append ledgers |
Separate bins. Same package. Plain gitty != gittysnap.
# scoped package; same bin names
npm i -g @vd7/gittyOptional resolvers (missing file -> empty allowlist -> drip/park, no auto-resolve):
per_host:
paths:
- registry/system-resource/manifest.json
globs:
- snapshots/$(hostname)/**
semantic_union:
globs:
- "**/*.ndjson"
- "**/*.jsonl"
key_field: ts| path | do this | get this |
|---|---|---|
| A | gitty |
drip + holdback checkpoint on remote |
| B | gittysnap |
snapshot-first solo sync |
| C | gittyunion install |
NDJSON union merge driver |
| D | gitty-dispatch |
config-driven Git operation routing |
| E | gittyplunger scan |
inspect oversized blobs buried in unpushed history |
| F | gitty install-hooks |
always-on uchg 1:1 sync + optional --with mutators |
# land whatever can land; hold blockers; park only if nothing can
gitty "checkpoint" "$HOME/Documents/a/gitty"
gitty -vGITTY_PARTIAL=1 default. Park-only: GITTY_PARTIAL=0. Bulldoze: GITTY_FORCE=1.
Integration preserves configured Git clean/smudge filters. If Git's internal merge snapshot fails on a filtered worktree, gitty computes the clean merge tree from Git objects, runs merge hooks against that tree, and restores only incoming paths after proving they do not overlap local worktree changes.
Holdback reasons:
-
optional
.gitty/holdback-reasons.jsonorGITTY_HOLDBACK_CATALOG -
maps hook stderr → stable
[CODE] reason -
missing catalog → offender stderr (never mute constant)
Stale remote tip: autoheal fetch+rebase unless GITTY_NO_STALE_BASE_HEAL=1.
# both hosts on remote first; rc=2 on conflict; worktree clean
gittysnap# union + dedupe + stable-sort for .ndjson / .jsonl
gittyunion installgitty-dispatch --config /absolute/path/dispatch.json --require-match -- push origin mainConfiguration supplies policy; the binary supplies exact dispatch:
{
"dispatch": {"version": 1, "real_git": "/usr/bin/git"},
"guarded_repos": [{
"match": {"remote_urls": ["https://example.invalid/team/repo.git"]},
"dispatch": {
"mode": "redirect",
"intercept_ops": ["push"],
"passthrough_ops": ["status", "log", "diff"],
"driver_argv": ["/absolute/path/sync-driver", "{repo_root}", "{operation}"],
"authorized_ancestor": "/absolute/path/sync-driver"
}
}]
}gittyplunger scan
gittyplunger plunge --yesscan is read-only. plunge repairs only a linear local-only range, preserves
the original tip under refs/gitty/plunger/traps/, and leaves clog bytes local.
Plain gitty runs this repair automatically before push.
The driver runs when an intercepted operation has no exact canonical driver in
its process ancestry. Descendant Git calls pass through. Environment markers,
substrings, basenames, and shell evaluation never authorize a request. Rules,
driver paths, and intercepted operations remain consumer-owned configuration.
Driver paths may be absolute or start with {config_dir}/; both are
canonicalized before comparison. Use the standalone {git_args} element when a
driver needs the original Git argument vector. Git, Zsh, and jq are required.
Linux supports whitespace in driver paths; macOS ancestry verification fails
closed for such paths because ps does not expose exact argument boundaries.
Matched repositories are default-deny: every literal Git operation belongs in
either intercept_ops or passthrough_ops. Configuration and configured
executables are trusted inputs; process ancestry prevents accidental or agentic
route-around, not attacks by another process already running as the same user.
# once per clone — installs runners + always-on uchg 1:1 sync
gitty install-hooks
chflags uchg path/you/want/locked # next commit writes .gitty/file-flags.json
gitty apply-flags # reconcile now (also post-checkout / post-merge)Git does not store chflags. Pre-commit syncs tracked uchg into
.gitty/file-flags.json; checkout/pull applies that list back. Optional
--with em-dashes,health-check,… adds mutators. Full detail:
docs/file-flags (GitHub; not in the npm tarball).
| signal | meaning |
|---|---|
| partial integrate | resolved subset committed; held paths stay local |
| holdback | oversized / submodule / push-reject / hook-reject left unstaged |
[CODE] reason |
catalog match for pre-commit reject (else offender stderr line) |
| drip retry | hook emitted GITTY_HOLDBACK records; one aggregate unstage; one bounded commit retry |
| plunge | oversized blob was buried in local-only history; original tip trapped, clean range rebuilt |
| park | nothing could land; bak/pending-merge-* + remote-snapshot-* |
| merge error | original Git diagnostic; exit 2; no conflict parking |
Local branch stays put on park. Nothing lost.
Other merge or merge-commit failures stop with exit 2 rather than masquerading as parked conflicts. Any in-progress merge is left in place for manual recovery.
| problem | fix | stability | why |
|---|---|---|---|
| one unresolvable file parks whole merge | drip (GITTY_PARTIAL=1): commit resolved subset |
stable | backup as much as possible |
| oversized path blocks push | leave GITTY_PARTIAL=1 |
stable | hold back; push the rest |
| oversized blob is buried in older unpushed commits | gittyplunger scan; plain gitty auto-plunges linear ranges |
stable | trap original tip; rebuild only local-only history |
| pre-commit rejects one staged path | hook emits GITTY_HOLDBACK records; one aggregate retry holds offenders |
stable | clean subset still lands; opaque hooks halt without scan |
mute pre-commit hook rejection reason |
.gitty/holdback-reasons.json or GITTY_HOLDBACK_CATALOG |
stable | stable [CODE] + fix hint |
| remote ahead / stale-base guard | leave autoheal on; GITTY_NO_STALE_BASE_HEAL=1 to skip |
stable | fetch+rebase then retry |
| N-commit rebase replays same conflict N times | merge --ff-only then --no-ff once |
stable | one merge, one conflict set |
| per-host artifact conflicts every sync | .gitty/additive-resolvers.yaml per_host |
stable | ours on that host; --no-ff keeps both parents |
.ndjson append conflict |
semantic_union or gittyunion install |
stable | union + dedupe + stable-sort |
| fresh clone drops union driver | re-run gittyunion install |
stable | attrs alone insufficient |
want uchg restored across clones |
gitty install-hooks; chflags uchg paths; commit (pre-commit syncs inventory) |
stable | 1:1 worktree <-> .gitty/file-flags.json; apply on checkout/pull |
| nothing can land | park bak/pending-merge-* |
stable | first-class ref; nothing lost; non-fatal |
foreign-owned .git (old sudo git) |
sudo chown -R "$(whoami)" .git |
stable | fail-fast; GITTY_SKIP_PERM_CHECK=1 opt out |
npm run test:integrate (also included in npm test) requires Git, zsh, and
git-crypt. It exercises integration using disposable local repositories and
local remotes only.
| Doc | Topic |
|---|---|
docs/README |
index |
docs/commands |
all bins |
docs/gittysnap |
snapshot-first sync |
docs/gittyplunger |
buried oversized-blob repair |
docs/gittyunion |
NDJSON union driver |
docs/partial-commit |
holdback + drip |
docs/environment |
env |
docs/hooks |
repo hooks |
docs/file-flags |
uchg 1:1 sync (install-hooks) |
npm tarball = bin/ + README only. docs/ is GitHub.
