#bit

    Git implementation in MoonBit with practical compatibility extensions and a built-in local GitHub-like collaboration layer.

    Warning: This is an experimental implementation. Do not use in production. Data corruption may occur in worst case scenarios. Always keep backups of important repositories.

    #Install

    Supported platforms: Linux x64, macOS arm64/x64

    # One-line install curl -fsSL https://raw.githubusercontent.com/mizchi/bit-vcs/main/install.sh | bash # Or install via MoonBit toolchain moon install mizchi/bit

    #Subdirectory Clone

    Clone subdirectories directly from GitHub:

    # Using @user/repo/path shorthand bit clone mizchi/bit-vcs:src/vfs # Or paste GitHub browser URL bit clone https://github.com/user/repo/tree/main/packages/core # Single file download bit clone https://github.com/user/repo/blob/main/README.md

    Cloned subdirectories have their own .git directory. When placed inside another git repository, git automatically treats them as embedded repositories (like submodules) - the parent repo won't commit their contents.

    #Standard Git Commands

    bit clone https://github.com/user/repo bit checkout -b feature bit add . bit commit -m "changes" bit push origin feature

    #Local Collaboration (bit issue / bit pr)

    bit issue and bit pr give you a local GitHub-like workflow backed by repository data. Use them to track work, discuss changes, and merge branches without depending on GitHub/GitLab. When you want to share metadata across machines or teammates, sync it separately with bit relay sync.

    # Initialize PR / Issue metadata once per repository # `bit pr init` / `bit issue init` ask before creating `.git/hub/policy.toml` # and before adding `refs/notes/bit-hub` sync settings to `remote.origin.*`. bit pr init # Force prompts on/off when scripting BIT_HUB_INIT_PROMPT=1 bit issue init BIT_HUB_INIT_PROMPT=0 bit pr init # Local issues bit issue create --title "Cache invalidation bug" --body "status view stays stale" bit issue list --open # top-level issues, with sub-issue counts bit issue list --tree # parent/child tree bit issue list --all # flat list including children bit issue list --parent <issue-id> # Local pull requests bit pr create --title "Fix cache invalidation" --body "refresh status after write" \ --head feature/cache-fix --base main bit pr list --open bit pr review <pr-id> --approve --commit <commit-hex> bit pr merge <pr-id> # Optional relay sync for PR / Issue metadata bit relay sync push <remote-url> bit relay sync fetch <remote-url>

    #Compatibility

    • Hash algorithm: SHA-1 only.
    • SHA-256 repositories and --object-format=sha256 are not supported.
    • Git config: reads global aliases from ~/.gitconfig (or GIT_CONFIG_GLOBAL) only.
    • Shell aliases (prefixed with !) are not supported.

    #Implemented Commands (108)

    init add diff diff-files diff-index ls-files tag branch checkout switch commit log show reflog reset update-ref update-index status merge rebase clone push fetch pull mv notes stash rm submodule worktree config show-ref for-each-ref rev-parse symbolic-ref cherry-pick remote cat-file hash-object ls-tree write-tree commit-tree receive-pack upload-pack pack-objects index-pack format-patch describe gc clean sparse-checkout restore blame grep shell rev-list bisect diff-tree read-tree fsck am apply bundle cherry revert prune pack-refs mktree shortlog verify-pack unpack-objects maintenance range-diff show-branch repack multi-pack-index pack-redundant send-pack request-pull merge-base var stripspace ls-remote fmt-merge-msg patch-id count-objects name-rev update-server-info check-ref-format mktag interpret-trailers column merge-tree merge-file fast-import fast-export verify-tag fetch-pack credential difftool rerere mailinfo archive check-attr check-ignore show-index get-tar-commit-id verify-commit annotate

    #Git-Compat Test Results

    Validated against upstream git test suite (third_party/git/t/) via the shim layer. 908 test files in allowlist.

    TestResultNotes
    t1300-config485/485
    t1450-fsck95/95
    t3200-branch167/167
    t3206-range-diff48/48
    t3500-cherry4/4
    t3501-revert-cherry-pick21/21
    t3507-cherry-pick-conflict44/44
    t4100-apply-stat19/19all 41 apply tests pass
    t4150-am87/87all 11 am tests pass
    t4201-shortlog32/32
    t5300-pack-object52/52
    t5304-prune32/32
    t5510-fetch215/215
    t5607-clone-bundle16/16all 7 bundle tests pass
    t6020-bundle-misc37/37
    t6101-rev-parse-parents38/38
    t6300-for-each-ref427/4281 fail: SSH signature
    t6302-for-each-ref-filter62/62
    t7003-filter-branch48/48
    t7700-repack25/47see below
    t7900-maintenance72/72

    #Standalone Test Coverage

    Standalone coverage is validated with git_cmd in t/test-lib-e2e.sh, which runs bit --no-git-fallback ... (no real-git dependency in these tests). 30/30 pass.

    Current standalone integration coverage (t/t0001-*.sh to t/t0024-*.sh) includes:

    • repository lifecycle and core porcelain: init, status, add, commit, branch, checkout/switch, reset, log, tag
    • transport-style workflows in standalone mode: clone, fetch, pull, push, bundle
    • plumbing used by normal flows: hash-object, cat-file, ls-files, ls-tree, write-tree, update-ref, fsck
    • feature flows: local collaboration (pr, issue, debug, relay), ai (rebase, merge, cherry-pick, revert, commit; rebase-ai is alias), mcp, hq

    #Explicitly Unsupported In Standalone Mode

    The following are intentionally rejected with explicit standalone-mode errors (covered by t/t0005-fallback.sh and command-level checks):

    • signed commit modes (commit -S, commit --gpg-sign)
    • interactive rebase (rebase -i)
    • reftable-specific paths (clone --ref-format=reftable, update-ref on reftable repo)
    • cloning from local bundle file (clone <bundle-file>)
    • SHA-256 object-format compatibility paths (hash-object -w with compatObjectFormat=sha256, write-tree on non-sha1 repo)
    • cat-file --batch-all-objects with %(objectsize:disk)
    • unsupported option sets for index-pack and pack-objects

    #Where Git Fallback Exists

    • Main bit command dispatch in src/cmd/bit/main.mbt does not auto-delegate unknown commands to system git.
    • Git fallback/delegation is implemented in the shim layer tools/git-shim/bin/git.
      • The shim delegates to SHIM_REAL_GIT by default.
      • CI git-compat (.github/workflows/ci.yml) runs upstream git/t via this shim (SHIM_REAL_GIT, SHIM_MOON, SHIM_CMDS).

    #Unimplemented Features

    The following features are not yet implemented. Flags listed here are parsed and silently ignored or produce a warning.

    #Fundamentally Missing

    FeatureDescription
    SHA-256--object-format=sha256 repositories not supported
    Reftable--ref-format=reftable backend not supported
    Bitmap writingpack-objects --write-bitmap-index does not generate .bitmap files
    Multi-pack-index writingrepack --write-midx is a no-op
    Commit-graphNo commit-graph generation or reading
    SSH transportOnly HTTPS remotes; git@host:repo URLs not supported
    GPG signingcommit -S, tag -s, signature verification
    Interactive addadd -p / add -i delegate to real git when available
    Interactive rebaserebase -i rejected in standalone mode
    Sparse indexSparse index format not fully supported
    Custom merge drivers.gitattributes merge drivers not supported

    #Porcelain Commands - Missing Options

    CommandMissing
    add-p (patch), -i (interactive) - delegates to git
    checkout--patch, --ours, --theirs, --merge
    commit-S (GPG sign), --fixup, --squash
    diff--word-diff, --color-words
    log--graph rendering (text output only)
    mergeOctopus merge (3+ heads), custom merge strategies
    rebase-i (interactive), --root, --autosquash
    stashcreate, store (low-level plumbing)
    clean-X (remove only ignored files, needs gitignore parser)
    mv--dry-run, --verbose, --sparse

    #Plumbing Commands - Missing Options

    CommandMissing
    pack-objects--write-bitmap-index (bitmap generation), tree:N filter (N>0)
    repack--write-midx (MIDX generation), bitmap auto-creation in bare repos
    unpack-objects-r (recover), --strict
    apply--reject (rejection file generation)
    clone--filter (partial clone)
    update-ref--stdin transaction status output

    #repack Test Coverage (t7700: 25/47)

    Passing: basic -a/-d/-q/-l/-n, --keep-pack, --filter (basic), --geometric, --unpack-unreachable, --keep-unreachable, server info update, .keep file handling, incremental repack.

    Not passing:

    CategoryTestsReason
    --write-midx9MIDX generation not implemented
    --filter (advanced)5Requires test-tool find-pack
    Alternate ODB4Alternate object detection edge cases
    Bitmap writing2.bitmap file generation not implemented
    GIT_TRACE2_EVENT1git internal tracing, not applicable
    Pending objects1--path-walk + fsck output format

    #Environment Variables

    • BIT_BENCH_GIT_DIR: override .git path for bench_real (vfs benchmarks).
    • BIT_PACK_CACHE_LIMIT: max number of pack files to keep in memory (default: 2; 0 disables cache).
    • BIT_RACY_GIT: when set, rehash even if stat matches to avoid racy-git false negatives.

    #Extensions

    #Fs - Virtual Filesystem

    Mount any commit as a filesystem with lazy blob loading:

    let fs = Fs::from_commit(fs, ".git", commit_id)
    let files = fs.readdir(fs, "src")
    let content = fs.read_file(fs, "src/main.mbt")

    #Kv - Distributed KV Store

    Git-backed key-value store with Gossip protocol sync:

    let db = Kv::init(fs, fs, git_dir, node_id)
    db.set(fs, fs, "users/alice/profile", value, ts)
    db.sync_with_peer(fs, fs, peer_url)

    #PR / Issue Metadata (Hub library)

    The CLI uses the Hub library internally. Pull requests and issues are stored as Git objects:

    let hub = Hub::init(fs, fs, git_dir)
    let pr = hub.create_pr(fs, fs, "Fix bug", "...",
    source_branch, target_branch, author, ts)

    #License

    Apache-2.0

    AsyncFileSystem

    Asynchronous counterpart to FileSystem.

    AsyncHttpClient

    Asynchronous counterpart to HttpClient.

    AsyncRepoFileSystem

    Asynchronous counterpart to RepoFileSystem.

    Commit

    using @mizchi/bit_object { type Commit }

    Git commit object

    CommitInfo

    FileSystem

    GitError

    Git operation errors

    HashAlgorithm

    HashState

    HttpClient

    HttpResponse

    MockHttpClient

    ObjectId

    Object identifier (20 bytes for SHA-1, 32 bytes for SHA-256)

    ObjectStore

    ObjectType

    Git object types

    PackCompression

    Compression mode for packfile entries

    PackDeltaMode

    Delta encoding mode for packfile generation

    PackObject

    A Git object ready for packing

    RepoFileSystem

    Sha1State

    Sha256State

    TestFs

    using @mizchi/bit_io { type TestFs }

    TreeEntry

    Tree entry in a Git tree object

    checkout_commit

    checkout_commit_to_fs

    Materialize commit_id under root, producing an exact checkout: paths tracked by a prior checkout that are absent from this commit are removed. rfs must observe the same filesystem as fs (callers pass the same concrete value as both trait views).

    checkout_commit_to_fs_async

    Asynchronous counterpart to checkout_commit_to_fs.

    create_blob

    fn create_blob(content : Bytes) -> (
    ObjectId
    , Bytes)

    Create a blob object from content

    create_blob_string

    fn create_blob_string(content : String) -> (
    ObjectId
    , Bytes)

    Create a blob from string content

    create_commit

    Create a commit object

    create_object

    fn create_object(obj_type :
    ObjectType
    , content : Bytes) -> (
    ObjectId
    , Bytes)

    Create a Git object and return its ID and compressed data Format: {type} {size}\0{content} -> SHA-1 -> zlib compress

    create_tree

    Create a tree object from entries Entries must be sorted by name

    hash_array_prefix

    fn hash_array_prefix(data : Array[Byte], len : Int, hash_size? : Int) ->
    ObjectId

    Hash Array prefix (first len bytes), dispatching by hash_size.

    hash_blob

    fn hash_blob(content : Bytes) ->
    ObjectId

    Hash a blob without creating the compressed object - optimized with incremental SHA1

    hash_blob_string

    fn hash_blob_string(content : String) ->
    ObjectId

    Hash a blob from string - optimized with incremental SHA1

    hash_object_content

    fn hash_object_content(obj_type :
    ObjectType
    , content : Bytes) ->
    ObjectId

    Hash object content (without compression) - optimized with incremental SHA1

    hash_object_content_with_algo

    Hash object content using the specified algorithm.

    hash_prefix

    fn hash_prefix(data : Bytes, len : Int, hash_size? : Int) ->
    ObjectId

    Hash data prefix (first len bytes), dispatching by hash_size.

    join_path

    fn join_path(root : String, path : String) -> String

    materialize_clone_to_fs

    fn materialize_clone_to_fs(store :
    ObjectStore
    , commit_id :
    ObjectId
    , refname : String, remote_url : String, fs : &
    FileSystem
    , root : String, rfs : &
    RepoFileSystem
    ) -> Unit raise
    GitError

    materialize_clone_to_fs_async

    async fn[FS :
    AsyncFileSystem
    +
    AsyncRepoFileSystem
    ] materialize_clone_to_fs_async(store :
    ObjectStore
    , commit_id :
    ObjectId
    , refname : String, remote_url : String, fs : FS, root : String) -> Unit raise
    GitError

    Asynchronous counterpart to materialize_clone_to_fs.

    parse_commit

    serialize_commit_content

    fn serialize_commit_content(commit :
    Commit
    ) -> Bytes

    Serialize commit to raw content bytes (without git object header)

    serialize_tree

    fn serialize_tree(entries : Array[
    TreeEntry
    ]) -> Bytes

    Serialize tree entries to raw content bytes (without git object header)

    sha1

    fn sha1(data : Bytes) ->
    ObjectId

    Compute SHA-1 hash of data

    sha1_array

    fn sha1_array(data : Array[Byte]) ->
    ObjectId

    Compute SHA-1 hash of data from Array

    sha1_array_prefix

    fn sha1_array_prefix(data : Array[Byte], len : Int) ->
    ObjectId

    Compute SHA-1 hash of Array prefix (first len bytes).

    sha1_prefix

    fn sha1_prefix(data : Bytes, len : Int) ->
    ObjectId

    Compute SHA-1 hash of data prefix (first len bytes).

    sha256_array_prefix

    fn sha256_array_prefix(data : Array[Byte], len : Int) ->
    ObjectId

    sha256_prefix

    fn sha256_prefix(data : Bytes, len : Int) ->
    ObjectId

    verify_tree_entry_name

    fn verify_tree_entry_name(name : String) -> Unit raise
    GitError

    Verify a single tree-entry name is safe to materialize into a worktree path.

    Rejects: empty string, ., .., any name containing / or NUL, and .git case-insensitively (the canonical foothold for hooks, config, refs). Mirrors the subset of git's verify_path() that matters for path-traversal during checkout / clone / fetch.

    Called at the bytes→worktree boundary (walk_tree_to_fs, lib.collect_tree_files_inner). Reading the bytes via @object.parse_tree is unaffected: a repo might still contain legacy commits with names we now reject, but bit refuses to materialize them. Use git fsck --strict upstream to catch the commit; bit will not silently write into .git/ or above the worktree.

    write_git_metadata

    fn write_git_metadata(store :
    ObjectStore
    , commit_id :
    ObjectId
    , refname : String, remote_url : String, fs : &
    FileSystem
    , root : String, rfs : &
    RepoFileSystem
    ) -> Unit raise
    GitError

    write_git_metadata_async

    async fn[FS :
    AsyncFileSystem
    +
    AsyncRepoFileSystem
    ] write_git_metadata_async(store :
    ObjectStore
    , commit_id :
    ObjectId
    , refname : String, remote_url : String, fs : FS, root : String) -> Unit raise
    GitError

    Asynchronous counterpart to write_git_metadata.

    Source Files

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io