Skip to content
vdutts7Public

About

git add, commit, and push in one command from any dir, for any repo

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Repository files navigation

gitty icon

gitty

diligent backup machine

land everything that can land, every run

GitHub npm



Path You get Verdict
git
  • git commit all-or-nothing
  • one conflict / huge file / submodule
  • whole checkpoint dies
  • remote unchanged
❌

stalls the backup
rebase
  • pull --rebase
  • same conflict N times
  • dirty tree mid-flight
  • other host still stranded
❌

sync theater
gitty
  • gitty drip
  • push the clean subset
  • hold blockers locally (size / submodule / hook)
  • park only if nothing can land
✅

backup continues
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]
Loading

Issue

❌ All-or-nothing stall

  • 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

❌ Dual-machine strand

  • laptop + desktop both edit

  • N local commits replay against remote -> same conflict N times

  • other machine's work never left that machine

❌ Checkpoint friction

  • agents touch many repos per session

  • add + commit + push per repo burns time

  • one blocker used to abort the whole run

❌ Hook-block stalls the clean subset

  • 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

❌ Append ledger false conflicts

  • two hosts append different .ndjson / .jsonl lines

  • git sees one slot, two lines -> conflict

  • nothing was edited; both lines should keep


Options

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.


Setup

# scoped package; same bin names
npm i -g @vd7/gitty

Optional 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

Usage

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

Path A · gitty

# land whatever can land; hold blockers; park only if nothing can
gitty "checkpoint" "$HOME/Documents/a/gitty"
gitty -v

GITTY_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.json or GITTY_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.

Path B · gittysnap

# both hosts on remote first; rc=2 on conflict; worktree clean
gittysnap

Path C · gittyunion

# union + dedupe + stable-sort for .ndjson / .jsonl
gittyunion install

Path D · gitty-dispatch

gitty-dispatch --config /absolute/path/dispatch.json --require-match -- push origin main

Configuration 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"
    }
  }]
}

Path E · gittyplunger

gittyplunger scan
gittyplunger plunge --yes

scan 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.

Path F · gitty install-hooks / file-flags

# 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).

Output

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.

Gotchas

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

Regression tests

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.

Docs

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.

Contact

vd7.io   /vdutts7

About

git add, commit, and push in one command from any dir, for any repo

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages