@contribnet/cn-git
v0.1.0
Published
CLI tool for ContribNet on-chain git integration
Readme
cn-git
A CLI tool that bridges local git repositories with ContribNet's on-chain version control. Developers work in normal git repos; cn-git handles bundling, IPFS pinning, and reading/writing the canonical HEAD commit from the project contract.
How it works
ContribNet stores the canonical codebase HEAD as a bytes32 on-chain (the sha256 digest of a CIDv0 IPFS address). When a contributor's work is merged (approved by reviewers), headCommit advances to their commit's CID. cn-git lets developers interact with this on-chain HEAD from the command line.
Installation
npm install -g cn-gitOr from source:
cd tooling
npm install
npm run build
npm link # makes `cn-git` available globallyOr run directly without installing:
node dist/cli.js <command>Configuration
Only two variables need to be set manually. cn-git init writes them for you.
PINATA_JWT=your_pinata_jwt # required for: push — get one free at pinata.cloud
PROJECT_ADDRESS=0x... # required for: rebase, fetch, head — set by cn-git initRPC_URL defaults to the Paseo testnet (https://eth-rpc-testnet.polkadot.io/) and does not need to be set. IPFS_GATEWAY defaults to https://ipfs.io.
PROJECT_ADDRESS is the address of the project's ERC1967Proxy (shown on the project page and printed by ProjectFactory.createProject()).
Commands
cn-git init <project-address>
Writes a .env file in the current directory with PROJECT_ADDRESS set, and prints step-by-step onboarding instructions.
cn-git init 0xAbCd...Run this once per project directory when you first start contributing to a project.
cn-git push [branch]
Bundles the specified branch (default: current HEAD), uploads the bundle to IPFS via Pinata, and prints the resulting CID. Copy this CID into the Submit Work form on the project page.
cn-git push # bundle HEAD
cn-git push main # bundle a specific branch
cn-git push --force # skip ancestry check (use if you know what you're doing)Before uploading, cn-git push checks that your branch descends from the current on-chain HEAD. If it doesn't (stale base), it warns and exits — you need to rebase first. Use --force to skip this check.
cn-git rebase
Fetches the on-chain HEAD bundle, imports it into your local repo, and rebases your current branch on top.
cn-git rebaseOn conflict: cn-git rebase exits non-zero and prints resolution instructions. Resolve conflicts with standard git rebase --continue, then run cn-git push to upload the rebased branch.
Saves progress to .cn-git-state.json on success. Skips if already up to date.
cn-git fetch
Downloads the on-chain HEAD bundle to ./cn-head.bundle without rebasing. Useful for inspecting or cloning the canonical codebase.
cn-git fetchAfter fetching:
# Clone from bundle
git clone cn-head.bundle my-project
# Or import into existing repo
git fetch cn-head.bundle
git rebase FETCH_HEADcn-git head
Prints the current on-chain HEAD commit CID.
cn-git head
# QmXyz... (or "(not initialised)" if headCommit is zero)cn-git review <task-id>
Fetches the submitted commit bundle and its parent from IPFS, then shows the commit log, a changed-files summary, and the full diff. The task ID is the bytes32 hex shown on the project page.
cn-git review 0xabc123... # full diff (piped through your pager)
cn-git review 0xabc123... --stat # changed-files summary only, no diff
cn-git review 0xabc123... --checkout # also check out the branch locally for testingExample output:
Task: 0xabc123ab… [Submitted]
Assignee: 0x1234…
Commit: QmXxx…
Parent: QmYyy…
── Commits ──────────────────────────────────────────────────
* a1b2c3d Fix wallet connection in SES environment
* e4f5g6h Add CIDv1 support to GovernancePanel
── Changed files ────────────────────────────────────────────
frontend/src/components/wallet/ConnectButton.tsx | 45 ++++++----
frontend/src/lib/utils.ts | 23 +++++++
2 files changed, 68 insertions(+), 10 deletions(-)
── Diff ─────────────────────────────────────────────────────
diff --git a/frontend/src/lib/utils.ts ...--checkout creates a local branch cn-review/<taskId-short> at the submitted commit so you can run and test the code directly. Works only inside an existing git repo. Return to your previous branch with git checkout -.
If run outside a git repo, cn-git review still works (using a temporary repo for diffing) but --checkout is unavailable.
Typical workflows
Joining a project for the first time:
# Configure this directory for the project
cn-git init 0xProjectAddress
# Add your Pinata JWT to .env
# PINATA_JWT=your_pinata_jwt_here
# Download the canonical codebase
cn-git fetch
git clone cn-head.bundle my-project
cd my-projectFirst contribution:
# Do your work, commit normally
git commit -m "implement feature X"
# Upload to IPFS
cn-git push
# → Qm... (copy this CID)
# Paste the CID into Submit Work on the project pageAfter a merge conflict (task reset to Assigned):
# Fetch and rebase onto current on-chain HEAD
cn-git rebase
# If conflicts:
# edit conflicting files
git add .
git rebase --continue
# Upload rebased branch
cn-git push
# → Qm... (new CID — paste into Resubmit on the project page)Reviewing a submission:
# Quick pass — see what changed without reading the full diff
cn-git review 0xTaskId... --stat
# Full review
cn-git review 0xTaskId...
# Check out the code to run tests locally
cn-git review 0xTaskId... --checkout
# test, run, inspect…
git checkout - # back to your branch when doneCID encoding
On-chain storage uses the raw 32-byte sha256 digest of the git bundle. cn-git converts between this bytes32 and CIDv0 (Qm...) format using base58 encoding — the same logic as bytes32ToCid / cidToBytes32 in the frontend (src/lib/utils.ts).
Local state
.cn-git-state.json is written to the working directory after a successful rebase. It tracks:
headCid— the on-chain HEAD CID at last rebaselocalHash— the local git hash at last successful rebase
This file can be committed or gitignored; it's only used to detect "already up to date" on subsequent rebases.
