Twine is a general-purpose Git collaboration server built in Rust.
This guide gets you to a working local server where you can run:
- repo API calls (
/api/repos,/api/repos/members, ...) - Smart HTTP Git operations (
ls-remote,clone,fetch,push)
- Rust toolchain (stable)
gitCLI installed- Linux/macOS shell
From repo root:
cp twine.toml.example twine.tomlEdit twine.toml:
bind_addr = "127.0.0.1:3000"
log_filter = "info"
[git]
repo_scan_path = "/tmp/twine-dev/git"
metadata_db_path = "/tmp/twine-dev/metadata/db"
metadata_reindex_interval_secs = 300
readme_cache_capacity = 128
diff_cache_capacity = 128
cache_ttl_secs = 300Create directories:
mkdir -p /tmp/twine-dev/git
mkdir -p /tmp/twine-dev/metadatamkdir -p /tmp/twine-dev/git/alicegit init --bare /tmp/twine-dev/git/alice/demoSeed with a main branch:
mkdir -p /tmp/twine-seedgit init /tmp/twine-seedgit -C /tmp/twine-seed config user.email twine@example.testgit -C /tmp/twine-seed config user.name "Twine Test"echo "# demo" > /tmp/twine-seed/README.mdgit -C /tmp/twine-seed add README.mdgit -C /tmp/twine-seed commit -m "seed"git -C /tmp/twine-seed branch -M maingit -C /tmp/twine-seed remote add origin /tmp/twine-dev/git/alice/demogit -C /tmp/twine-seed push origin HEAD:refs/heads/maingit -C /tmp/twine-dev/git/alice/demo symbolic-ref HEAD refs/heads/mainFrom repo root:
cargo runServer will listen on bind_addr from twine.toml.
Twine currently requires the repo to exist on disk and in API state.
curl -i \
-H 'x-actor-id: alice' \
-H 'content-type: application/json' \
-d '{"owner":"alice","repo":"demo"}' \
http://127.0.0.1:3000/api/reposgit -c "http.extraHeader=x-actor-id: alice" ls-remote http://127.0.0.1:3000/alice/demogit -c "http.extraHeader=x-actor-id: alice" clone http://127.0.0.1:3000/alice/demo /tmp/twine-clonegit -C /tmp/twine-clone -c "http.extraHeader=x-actor-id: alice" fetch originecho "owner push" > /tmp/twine-clone/OWNER_PUSH.mdgit -C /tmp/twine-clone add OWNER_PUSH.mdgit -C /tmp/twine-clone commit -m "owner push"git -C /tmp/twine-clone -c "http.extraHeader=x-actor-id: alice" push origin +HEAD:refs/heads/mainAdd collaborator:
curl -i \
-H 'x-actor-id: alice' \
-H 'content-type: application/json' \
-d '{"owner":"alice","repo":"demo","member_id":"bob","role":"collaborator"}' \
http://127.0.0.1:3000/api/repos/membersClone as collaborator:
git -c "http.extraHeader=x-actor-id: bob" clone http://127.0.0.1:3000/alice/demo /tmp/twine-bobAttempt push (expected to fail):
echo "blocked" > /tmp/twine-bob/BLOCKED.mdgit -C /tmp/twine-bob add BLOCKED.mdgit -C /tmp/twine-bob commit -m "blocked push"git -C /tmp/twine-bob -c "http.extraHeader=x-actor-id: bob" push origin +HEAD:refs/heads/mainYou should see a permission failure.
cargo test --workspacecargo clippy --all-targets --all-features -- -D warnings