Build GitKraken

YESback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local Git client whose hard problems are parsing real repository state without lying about filenames or signatures, drawing a commit graph from the parent list rather than from dates, and making every destructive action recoverable by something better than hope.

estimated effort weekendthe files for this build are in the project pack

EngineThe installed git binary, called with plumbing commands and machine-readable outputRuntimeA Node process serving a React interface, bound to the loopback address onlyParsinggit status --porcelain=v2 -z and git log with a NUL-delimited custom formatGraphLanes computed from each commit's parent list over a bounded windowSafetyA recovery ref plus a command log written before every destructive action

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Everything this client does is git doing it, and porcelain v2 plus the signature placeholders need a version that has them.

    Get it Your package manager, or git-scm.com. open ↗

    Verify git --version prints the version, and git status --porcelain=v2 -z runs without error

  2. installfree

    Why Runs the local process serving the interface.

    Get it nodejs.org or your version manager. open ↗

    Verify node --version prints v22 or higher

  3. have readyfree

    Why Lane assignment, rename detection and unmerged states are the three places this build breaks, and none of them appear in a fresh repository with four commits.

    Get it Clone something real, or generate one with a script in tests/fixtures.

    Verify It contains at least one merge with two parents and one rename git detects

  4. have readyfree

    Why A filename containing a newline is the single fastest way to find out whether your status parser is correct, and it costs one shell script.

    Get it Create files with spaces, quotes, non-ASCII characters and a newline in the name.

    Verify git status --porcelain=v2 -z lists them and your parser agrees on the count

  5. decidefree

    Why Mapping the eight signature values is easy to get wrong and easy to test with a stub, but a real expired or revoked key is the only way to see the real output.

    Get it Decide between fixture commits with recorded output or generating a key you later revoke.

    Verify The test suite covers all eight values whichever route you take

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- repos(id, path, name, added_at, last_opened_at) · the list of folders you opened, and nothing about what is in them
- settings(id, graph_window, fetch_interval_seconds, confirm_destructive, always_show_command)
- recovery(id, repo_id, at, action, ref_name, head_before, argv_json, undone_at) · one row per destructive action and the ref that reverses it
- command_log(id, repo_id, at, argv_json, exit_code, duration_ms, stderr_tail) · every invocation, so a surprise is explainable rather than arguable
- Nothing about commits, branches, diffs or file contents is stored here. git is the store, and a cache of git is a second source of truth that will eventually disagree with the first.
- The repository list holds paths. A client that copies your code into its own database has quietly become a new place your code can leak from.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
GIT_BINrequired/usr/bin/gitThe binary every command goes through. Pinned so you know what you tested.
BIND_ADDRESSrequired127.0.0.1Loopback. Changing this exposes filesystem and git access to your network.
DATABASE_PATHrequired./data/client.dbRepository paths, settings, recovery rows and the command log. No code.
RECOVERY_REF_PREFIXrequiredrefs/vibe-recoveryWhere undo refs are written. Listed in the README so you can clean them up.
GRAPH_WINDOWrequired500Commits read per page. The reason a large repository opens quickly.
GIT_TERMINAL_PROMPTrequired0Set for every child process, so git never blocks waiting for a password.
COMMAND_TIMEOUT_MSrequired30000After this a command is killed and its partial output kept.

The build, in order

  1. Repository state, read honestly

    The working tree view matches what git actually reports, including for files nobody expects.

    1. Split on NUL and read the record type from the first field of each entry.

      Files src/git/status.tstests/status-weird-names.test.ts

      terminal
      git status --porcelain=v2 -z --branch --untracked-files=all
    2. A test that only uses readme.txt proves nothing about this code.

      Files tests/fixtures/make-repo.sh

    3. A git status every second on a large repository is a fan you can hear.

      Files src/git/watch.ts

    done when · tick each as it passes
    watch out
    • Parsing git status --porcelain by splitting the output on newlines breaks on a filename containing a newline, which is legal on every filesystem you will meet, and without -z git quotes unusual pathnames the way core.quotePath describes, so you also get backslash escapes you then render as literal text; the docs say plainly that there is an alternate -z format recommended for machine parsing, so use --porcelain=v2 -z and split on NUL.
  2. A graph drawn from parents, not from dates

    The commit graph is correct on a repository with merges and is bounded on one with a hundred thousand commits.

    1. One process, one parse, a known field order.

      Files src/git/log.ts

      terminal
      git log --max-count=500 -z --pretty=format:%H%x00%P%x00%D%x00%an%x00%cI%x00%s
    2. Open a lane on a first parent, close it when a commit claims it.

      Files src/graph/lanes.tstests/lanes.test.ts

    3. Octopus merges and criss-cross history are where lane code falls over.

      Files tests/fixtures/merge-history.sh

    done when · tick each as it passes
    watch out
    • Sorting the commit list by date to draw it produces a graph where a commit appears above its own parent, because author dates are whatever the committing machine said they were and a rebase or a wrong clock makes a child older than its parent; take the order git returns, which is already topological enough to draw, and treat dates as a label rather than as an ordering.
  3. Diffs and staging, including the files that break diff views

    Staging a hunk changes the index and nothing else, and a binary file never reaches the renderer.

    1. The index is the only thing a staging action is allowed to change.

      Files src/git/stage.tstests/stage-hunk.test.ts

      terminal
      git apply --cached --unidiff-zero -
    2. Decoding a forty megabyte binary as UTF-8 freezes the tab.

      Files src/diff/guard.ts

    3. A moved file shown as a delete and an add loses its history in the eye.

      Files src/git/diff.ts

    done when · tick each as it passes
    watch out
    • Applying a partially staged hunk by writing a modified copy of the file back to the working tree destroys whatever else the user had unsaved in that file and quietly changes line endings on a repository with autocrlf set; build a patch containing only the selected hunk and apply it to the index with git apply --cached, so the working tree is never touched by a staging operation.
  4. Destructive actions with a written way back

    Nothing that can lose work runs without a recovery ref and a visible command.

    1. If the ref write fails the action must not happen at all.

      Files src/safety/recovery.tstests/recovery.test.ts

      terminal
      git update-ref refs/vibe-recovery/$(date +%s) HEAD
    2. It is the only case git itself cannot recover.

      Files src/safety/stash.ts

      terminal
      git stash push --include-untracked --message
    3. The first question after any surprise is what was actually run.

      Files src/git/run.tssrc/ui/CommandPreview.tsx

    done when · tick each as it passes
    watch out
    • Treating the reflog as the undo feature means the day someone discards uncommitted changes there is nothing to recover, because those changes were never an object git knew about, and the day someone comes back a month later the reflog entry has expired under the repository's own gc settings; write your own ref for committed state, stash for uncommitted state, and never offer a destructive action that has neither.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.