Reference snapshot · source revision 6820997f383188141ff4e40d77eb1a38db490464
kit and Git parity
This file defines what "usable like Git" means for kit. It states the scope,
the non-goals, the machine-output contract and the documented divergences.
The per-command matrix is on kit.storage/parity.
It gives each command the status parity, divergent or non-goal.
Scope
kit targets CLI behavior parity with Git. A command and flag that a person or an agent types in Git behaves the same way in kit, unless this file lists a divergence. kit keeps its own properties:
- BLAKE3 content addressing.
- A signature on every commit.
- Guards against data loss.
kit does not target on-disk or wire interoperability with Git repositories. kit objects are BLAKE3 objects. A BLAKE3 object store cannot share bytes with the SHA-1 object store of Git.
The kit git commands are the one exception. They translate objects between
the two stores. kit git export writes a deterministic Git mirror
(SPEC-GIT-BRIDGE). kit git import writes a
signed downstream fork of a Git remote
(SPEC-GIT-IMPORT). Both commands translate every
object. Neither shares bytes between the stores. Two-way sync is a non-goal.
Inherent divergences
These divergences stay while kit uses BLAKE3.
- Hash length. kit object IDs have 64 hex characters. Git object IDs have
- A Git hash never resolves in kit. A short prefix of a kit ID resolves,
for example
kit cat-file -t f9f9951d.
- A Git hash never resolves in kit. A short prefix of a kit ID resolves,
for example
- Repository directory. kit stores its state in
.kit/, not.git/. kit does not detect a repository by.git/. - Default remote name. The default remote of kit is
default, notorigin. Its tracking refs live underrefs/remotes/default/. - Remote URLs. A kit remote URL starts with
kit+<scheme>://. Plainhttps://and plain paths are errors.
Non-goals
- Submodules and subtrees.
- Hooks, including
core.hooksPath. - The full refspec grammar.
pushtakes a remote and no refspec.pushdoes not take--tagsor--delete. - Git wire protocol v2 and smart-HTTP negotiation.
git notes.- Shallow clone.
clone --depthis a usage error. .giton-disk interop and SHA-1 objects.- Shadowing the
gitbinary onPATH.
Safety divergences
kit refuses some silent data loss that Git allows. These divergences stay even when a command reaches parity on everything else.
restoreandreset --hardrefuse to discard local edits or staged content.-for--forceoverrides the guard. Git discards the edits without a warning.worktree removerefuses to delete a tree with untracked files or local changes.--forceoverrides the guard.update-ref -drefuses to delete the current branch. Git deletes it.- Repository config cannot hold the signing key.
config --local signing_keyis an error.-c signing_key=...is ignored with a warning. A cloned repository cannot redirect signing. commit --amend,resetandrebaserecord the replaced commit in a recovery log.gckeeps the commit for the grace window.
Machine-output contract
Output that tools parse is stable and has the shape of the Git output. Object IDs are the only difference. They are 64 hex characters.
status --porcelainandstatus -sprintXY <path>lines. A path with special bytes uses C-style quoting.-zprints raw paths with NUL terminators.status --porcelain=v2prints1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>for a tracked change. It prints2 ... R100for an exact rename and? <path>for an untracked path. It prints no--branchheader lines.diff --name-only -zandls-files -zprint raw paths with NUL terminators.cat-file --batchprints<id> <type> <size>, then the content. It prints<name> missingfor an unknown object.ls-files -sprints<mode> <id> <stage>\t<path>.ls-treeprints<mode> <type> <id>\t<path>.for-each-ref --formatandrev-parse --shortfollow Git.
Output channels
kit writes human summaries to stderr. kit writes data to stdout.
A clean kit status prints nothing to stdout, so a pipeline stays quiet.
Git writes some of these summaries to stdout.
The summaries have the shape of the Git summaries:
pushprintsTo <url>, then one line for each ref. It prints* [new branch],<old>..<new>,+ <old>...<new> (forced update)or! [rejected] ... (non-fast-forward). It printsEverything up-to-datewhen nothing changes.pullprintsUpdating <a>..<b>,Fast-forwardand a diffstat. It printsAlready up to date.when nothing changes.fetchprintsFrom <url>and one line for each ref. It prints nothing when nothing changes.cloneprintsCloning into '<dir>'....commitprints[<branch> <id>] <subject>, a diffstat and the file modes.mergeprintsMerge made by the 'ort' strategy.orCONFLICT (content): Merge conflict in <path>.switchandcheckoutprintSwitched to branch '<name>'orSwitched to a new branch '<name>'.reset --hardprintsHEAD is now at <id> <subject>.
kit does not print the Git object-count and delta-compression lines. kit transfers one object per pack and has no cross-branch delta graph. Those numbers would be invented.
Documented divergences
- Empty commit.
commitcreates a commit when the index equalsHEAD. Git refuses. kit has no--allow-empty. diffbase.kit diffwithout a revision comparesHEADwith the working tree. The result includes staged changes and untracked files. Git compares the index with the working tree.kit diff --stagedmatches Git.- Untracked directories.
statuslists each untracked file. Git lists the directory, for exampleu/. - Ignore files. kit reads
.gitignoreand.kitignoreat the repository root. kit does not read ignore files in subdirectories. - Conflict markers. kit labels the sides
oursandtheirs. Git usesHEADand the name of the merged branch. - Author and date.
logprints the signing identity, for exampleed25519:11de6447, and a UTC date. Git printsName <email>and a local date. logfilters.--authorand--grepmatch a substring. Git matches a regular expression.--sinceand--untilaccept@<unix>,now,today,yesterday,<N> <unit> ago,YYYY-MM-DDandYYYY-MM-DD HH:MM:SS. Git accepts more forms.taglisting.kit tagprints the tag name, the short ID and the tag kind. Git prints the names.stash. Each linked worktree has its own stash. Git shares one stash.bisect.bisectprints the next candidate and does not check it out.HEADstays on your branch. Git checks out each candidate and leavesHEADdetached.reflog.refloglists the first-parent chain of a branch. It does not record operations, and it omits commits thatcommit --amendorresetreplaced.blameoutput. The default line is<short id>\t<line>\t<text>.--porcelainfollows the Git header fields. The author fields hold the kit identity, and kit prints nopreviousline.blame --ignore-rev-precise. This option is only in kit. It follows a line by content instead of by position.- Sparse checkout.
sparse-checkout setkeeps files that are already in the working tree.sparse-checkout reapplydoes not create a file that a pattern excludes, andstatuslists that file as deleted. gc.gcprunes unreachable objects and has-n. Gitgchas no-n.config. kit accepts a fixed set of keys.user.name,user.emailandcore.*are unknown keys. An unknown key is an error.
Deferred flags
kit does not implement these flags. A command with a missing flag is
divergent on the matrix.
log -p/--stat/--decorate/--all/--graph— kit rejects each flag as an unknown argument.branch -r/-a/-u/--unset-upstream— no remote-tracking listing and no upstream setting.add -n/--dry-run— kit rejects the flag.rev-parse --verify— kit rejects the flag.rev-list --max-count— kit rejects the flag.rev-listtakes one revision and no range.show-ref <pattern>— kit rejects the pattern.fetch --prune/--tags— kit rejects each flag.pull --rebase/--no-ff— kit rejects each flag.rebase --onto— kit rejects the flag. Theedittodo action is not available either.revert -m— kit does not revert a merge commit.stash push/--include-untracked— kit rejects each form.checkout -- <path>—checkouttakes a branch or a revision. Userestorefor files.init <dir>/init -q—inittakes no argument, and it is an error in an existing repository.<rev>:<path>— kit does not resolve this form inshow,cat-fileorrev-parse.worktree move/lock/repair— kit has no such subcommand.