Skip to content

v3.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 08 Sep 23:55

Release overview

ngit v3 is its biggest release yet. With CI, private repositories, software
releases, and plenty more, ngit, powered by GRASP, is quickly becoming a fully
fledged development solution. It launches in tandem with ngit-grasp v3,
GitWorkshop v4, and the new ngit-ci 0.1 as one coordinated release across the
ngit family of tools. These are the changes that define the release. Read the
full launch story
to see how all four releases fit
together; the detailed entries below record every feature, compatibility
change, and fix.

  • CI is here: One of the biggest gaps holding projects back from ngit is
    now closed. Discover maintainer-selected coordinators, request, trigger, and
    stop runs, follow workflows down to individual job logs and trust evidence,
    and optionally require a trusted CI result before merging.
  • Private repositories without surrendering identity: Clone, fetch, push,
    and collaborate on GRASP-08 private repositories using scoped Nostr and Git
    authentication. The repository remains a signed Nostr identity instead of
    becoming an account owned by its server. Basic Buzz support extends clone,
    pull-request, and lifecycle-status workflows to Buzz repositories.
  • Maintainers and repository authority: Introduce an explicit lead,
    role history, and non-maintainer moderators, with clearer invitations,
    handovers, departures, roster changes, and historical authorization. These
    substantial improvements are backwards compatible for existing repositories
    and confirmed maintainer relationships. The one narrow breaking change is
    that an invited maintainer has no Git-state authority until they accept. That
    pending-invitation boundary is the SemVer reason for the v3 major version
    bump.
  • Pull requests that fit real projects: Target non-default branches, build
    inferred or explicit pull-request stacks, check out contributor branches on
    demand, record issue-resolution provenance, and merge with stronger safety
    checks.
  • Software releases without the platform: Think GitHub Releases without
    GitHub, made resilient through Blossom replication. Publish signed NIP-82
    applications, releases, and assets with Zapstore-compatible metadata, then
    update ngit itself from its verified releases.

Additional ngit highlights

  • Credential protection: Move nsec and bunker credentials out of Git
    config by default and into the OS credential store, with an ngit-specific,
    user-only file as fallback. This reflects a changed threat model: coding
    agents and other tools now routinely read Git config, making inadvertent
    disclosure much more likely.
  • Nsite and container publishing: Publish nsites and OCI container images
    through Nostr and Blossom.
  • Accounts and automation: Add portable local and remote signer selection,
    deliberate credential export, global JSON output and repository selection,
    plus a versioned agent skill installer and upgrader.
  • Repository addresses: Resolve path-scoped NIP-AD mappings from memorable
    bare domains, with NIP-65 relay discovery when the repository announcement is
    not already cached.
  • Everyday Git compatibility: Support guarded force pushes with
    --force-with-lease, raw object IDs in refspecs, no-op pushes, Git-managed
    tracking refs, and installed remote helpers for additional server protocols.
  • Safer upgrades and recovery: Update from exact signed NIP-82 releases,
    preserve staged, unstaged, and untracked work through merges, and provide an
    actionable merge recipe when synchronized refs have diverged.
  • Private-network access: Connect opportunistically to .onion relays and
    clone URLs through Tor, and optionally trust host-installed certificate
    authorities for private or development infrastructure.

Added

  • Bare-domain nostr:// repository URLs can resolve path-scoped NIP-AD
    mappings, including protocol and SSH-key prefixes. NIP-AD mappings and the
    existing hint-less nostr://<npub>/<identifier> form now bootstrap missing
    repository announcements through the author's NIP-65 write relays.
  • ngit release publish can derive its version and source commit from one
    exact Git tag, so tagged CI builds need no positional arguments. Schema-1
    manifests accept Zapstore-compatible local APK release_source; ngit
    extracts package/version, SDK, certificate, and ABI metadata from the stable
    Blossom snapshot and rejects conflicts with declarative assertions.
  • Schema-1 release manifests can declare Zapstore-style application metadata.
    Tracked local icons and screenshots publish through Blossom, while existing
    HTTP(S) image URLs remain direct references and are never downloaded.
  • Add ngit update, ngit update --check, and exact-version selection backed
    by ngit's signed repository state and trusted NIP-82 release assets. Only
    receipted standalone Unix installations are replaced automatically; Nix,
    Cargo, and unreceipted installations receive non-mutating guidance. The
    canonical website installer template now shares this update path.
  • Release manifests can set release_notes: CHANGELOG.md to publish the
    matching Keep a Changelog version section. Missing, duplicate, and empty
    sections fail rather than falling back to the complete changelog.
  • Add ngit nsite publish <DIRECTORY> for publishing an already-built static
    site as a root or named NIP-5A manifest. The command snapshots files
    deterministically, confirms every unique blob on every selected Blossom
    server with batched BUD-11 authorization, then signs and publishes the
    manifest with local or remote signers. Blossom servers may be supplied
    explicitly, read with site metadata, fallback routing, and relay hints from
    nsyte's .nsite/config.json, or discovered from the account's kind-10063
    server list.
  • Add ngit container publish <OCI_LAYOUT> for publishing verified OCI image
    layouts through Blossom and repository-bound Nostr kind-30624 state. The
    command uploads every reachable blob, preserves existing remote tags by
    default, publishes through repository relays, and supports NIP-42 and
    structured CI output.
  • Private repositories via GRASP-08: discover private repositories through
    encrypted kind-10318 relay lists, then clone, fetch, push, and collaborate
    using NIP-42 relay authentication and repository-scoped NIP-98 Git HTTP
    credentials. Private repository events stay on repository relays instead of
    leaking through indexers, fallback relays, or account relay fanout. Copied
    repository URLs can also be classified as private from GRASP-08 NIP-11
    metadata before discovery begins.
  • Basic Buzz support: clone Buzz repositories, view pull requests and their
    lifecycle status, and push new or updated pull requests and status changes
    through authenticated Buzz relay and Git transport. Normal branch and tag
    pushes are not supported, and Buzz pull-request comments cannot be viewed or
    published because Buzz uses kind 1 while ngit uses NIP-22 kind 1111.
  • Stored accounts can be selected for one ngit command with global
    --signer <npub|alias|profile-name>, or for one Git command with
    git -c nostr.signer=<account>, without changing the configured login.
    ngit account login <account> reactivates retained credentials and
    --alias adds a portable signer name. An explicit selector that is missing,
    invalid, or ambiguous fails closed.
  • Add portable one-shot and export paths for both signer types:
    --nsec-file reads a local key, while interoperable --nbunksec and
    --nbunksec-file reuse an established NIP-46 session. Secret-file targets
    must be small regular files and, on Unix, use mode 0400 or 0600.
    ngit account export-keys returns the selected account's npub plus nsec
    for a local signer or nbunksec for a remote signer.
  • --json is now a global option for all ngit commands. Machine-readable
    results are written to stdout only after command completion, diagnostics and
    progress stay on stderr, and mutating commands return useful event IDs and
    metadata. JSON output cannot be combined with interactive mode.
  • Pull requests can target a non-default branch with git push -o target-branch=<branch> or ngit send --target-branch <branch>. Root PR events expose the target as an indexed b tag, and listing, viewing, updating, merging, and applied-status detection honor the immutable target; omitting the option retains default-branch behavior. ngit merge resolves an explicit target against the latest Nostr repository state, fetching the target commit without mutating tracking refs, so a stale local clone cannot merge onto old target history.
  • Pull requests automatically select the unique most-advanced tip of the author's other open or draft PRs when it is in the new proposal's history and ahead of the target branch. Existing children follow later authorized parent updates after they are rebased, while stale children and ambiguous unrelated parents fail closed. git push -o base=<commit|branch|event> and ngit send --base <commit|branch|event> override inference for that publication; PR roots select their latest authorized update, specific PR-update events select their historical commit, and unique event-ID prefixes are accepted. Repeat an explicit historical base on later child updates to keep that deliberate pin instead of following the open parent lineage.
  • Issue-resolution status events now identify the triggering commit and, when
    attribution is unambiguous, the proposal and merge commit that caused the
    status change.
  • Add a multi-stage Containerfile for building a minimal Alpine-based ngit image, plus a CI smoke test that builds the image and runs ngit --version.
  • Add an opt-in native-tls-roots build feature that trusts certificate authorities installed on the host alongside WebPKI roots, enabling WSS connections to relays and GRASP servers using private, corporate, or development CAs.
  • ngit repo --json now exposes selected_maintainer, confirmed_maintainers, invited_maintainers, lead_maintainer, and the directional maintainer_edges alongside the backward-compatible full maintainers set.
  • Add ngit skill install, upgrade, and status commands plus local and global reminder opt-outs for repository-managed coding-agent guidance. Installs add a slim versioned SKILL.md and eight on-demand reference/*.md guides to both Codex and Claude discovery paths, including static-site publication with ngit nsite, and append a compact pointer only to existing AGENTS.md or CLAUDE.md files that do not already mention ngit. Installs and upgrades preserve supported symlinks, protect modified or newer copies unless forced, and create distinct guidance-only commits; non-maintainers are advised to push the commit as a pull request, while ngit init leaves installation as an explicit suggested follow-up.
  • Expand --repo-relay-only to all ngit commands that publish nostr events.
  • Git server clone URLs can use installed git-remote-<scheme> helpers for listing, fetching, and pushing. Installing a helper is treated as consent for signed repository announcements to invoke it, subject to Git's protocol policy; recursive nostr, internal fd, and GRASP-reserved ws/wss schemes are not delegated.
  • Global --repo <REMOTE|NADDR|NOSTR-URL> argument selects the target repository for repo-scoped operations (send, issue, pr, repo, sync, and every other command that resolves a repository coordinate). Available at any command position (ngit --repo upstream issue create, ngit issue --repo upstream create, ngit issue create --repo upstream). Value is first matched against configured remote names, then parsed as an naddr, then as a nostr:// URL.
  • Repo-coordinate resolution now prints a target repository: <naddr> (source: ...) diagnostic when publishing repo-scoped events, so an incorrect target is visible before the event is signed.
  • Opportunistic Tor support for .onion relays and clone URLs. ngit uses an available SOCKS5 proxy from NGIT_TOR_PROXY or probes the common system Tor and Tor Browser ports (127.0.0.1:9050 and 127.0.0.1:9150). Unavailable onion entries fail immediately so they do not delay clearnet alternatives. See docs/onion.md.

Changed

  • The bundled coding-agent skill is rewritten around the guides published at
    https://ngit.dev. SKILL.md keeps the rules agents get wrong and points each
    task slice at its bundled reference, the matching guide, and
    ngit <command> --help; the reference files drop material the guides cover
    better, describe capabilities instead of choosing workflow policy, and gain a
    rule to preserve choices the user or repository already made. The skill now
    states that it documents ngit v3 and how to install or update an older host,
    merges reference/repo-settings.md into reference/repositories.md, and
    corrects the setup-ngit action tag (v3), the issue auto-resolution
    keywords, and the canonical ngit pr merge behaviour.
  • ngit skill install and upgrade delete reference files that a later ngit
    no longer bundles, resolving the same canonical symlinks as bundled files,
    and stage the deletion in the guidance commit. A lingering retired file is
    reconciled even when the skill version is already current.
  • The top-level ngit merge command is now a compatibility alias for the
    canonical ngit pr merge command. Both spellings create the same local
    no-ff merge on the PR's declared target (or repository default), share
    conflict handling and options, and refuse closed or already-applied PRs
    before changing Git state. Preparing the local merge no longer requires a
    maintainer identity; the later Git push enforces repository authority and
    publishes the Nostr applied status. Ungated JSON keeps the PR id, entity,
    and action (merged or conflicted) while omitting the unrequested CI
    projection and unpublished event.
  • JSON command-result envelopes now use top-level command_status: "ok" | "error" instead of the ambiguous status field or ok boolean. Nested
    fields continue to describe domain results, so a successful ci status
    query can pair command_status: "ok" with ci.conclusion: "failure".
    Release, nsite, and container publication envelopes advance to format
    version 2 for this breaking schema change.
  • ngit merge now accepts --require-ci-trust, matching ngit pr merge.
  • Repository hosting flags now distinguish grasp-derived infrastructure from
    deliberate additions. ngit init uses --additional-relay and
    --additional-clone; ngit repo edit replaces whole-list
    --grasp-server, --relay, --clone, and --hashtag flags with repeatable
    --add-* and --remove-* actions. Repository identifiers can no longer be
    changed through repo edit because doing so creates a new coordinate.
  • GRASP service URLs may include a non-root base path. Repository announcements, nostr:// relay hints, Git push/fetch, and explicit GRASP-06 PR endpoints preserve the configured path.
  • ngit account whoami now inventories every usable stored account from local, global, and system Git config, credentials.json, and the OS credential store; groups identities by npub; lists distinct local-key and remote-signer connections with their npub/alias selectors and connection-specific scope badges; and prints shared guidance for one-shot ngit or Git use, local/global activation, alias creation, and removing a local override. ngit account list is a visible alias, while ngit account login <account> adds a concise activation form alongside the existing --signer spelling. A non-secret account index makes newly stored OS-keyring identities discoverable without relying on platform-specific keyring enumeration.
  • Logged-in accounts answer NIP-42 authentication challenges from repository
    relays, and from the account's inbox or outbox relays while publishing, but
    decline challenges from unrelated relays such as indexers and fallbacks.
  • Now that ngit-grasp repository-relay synchronization has matured, repository state and collaboration events are fetched exclusively from relays declared by the repository. This makes repository relays the authoritative collaboration view and allows grasp servers to provide moderation in the future without filtered events being restored from user relays. URL hints, fallback relays, and announcement indexers are limited to repository announcements; user relays are limited to profile metadata, relay lists, and user GRASP lists. Publishing still fans out to relevant user relays unless --repo-relay-only or nostr.repo-relay-only is set.
  • Open and draft PRs from other users are no longer downloaded as branches by
    default. ngit pr checkout opts an individual PR back in with its familiar
    shorthand-suffixed branch name and keeps later fetch, pull, and push tracking
    intact. The new default applies to fresh and existing clones; existing clones
    keep previously downloaded tracking refs until git fetch --prune. Set
    nostr.auto-pr-branches=true explicitly to restore automatic downloading.
  • Global event caching now falls back to an in-memory cache when persistent storage is unavailable, allowing ngit to operate in restricted or sandboxed environments. Set NGIT_CACHE_DIR to select a writable persistent cache directory; repository caches remain strict and require the Git common directory to be writable.
  • Upgrade NostrDevKit dependencies from the 0.45.0-alpha.2 prerelease series to the stable 0.45.0 release.
  • Align maintainer terminology with gitworkshop: every pubkey in the directional maintainer graph has maintainer rights, while "invited" identifies an unreciprocated relationship rather than reduced authority. Reciprocal graph membership confirms co-maintainers, and a unique highest-listed confirmed maintainer is shown as a coordination-only lead. ngit repo describes whom each confirmed maintainer lists and, when informative, who invited an unconfirmed maintainer. Acceptance defaults now reciprocate the sole confirmed maintainer or unique lead, retaining the selected maintainer only for ambiguous non-interactive cases.
  • Accepting co-maintainership (ngit repo accept, and the auto-accept that runs during push and status commands) no longer rewrites nostr.repo or the origin remote to point at the accepter's own coordinate. The coordinate a repository resolves from is the root of trust; re-rooting it on your own announcement — which always lists you as a maintainer — would make it impossible to observe the inviter removing you later. Resolution stays on the inviter's coordinate, so a removal surfaces naturally (for example as a refused push); only ngit repo edit / ngit init change the resolved coordinate deliberately. When origin is not a nostr:// remote, ngit repo accept now prints how to add a nostr remote for the inviter's coordinate instead of claiming pushes will work.
  • ngit account login and ngit account create now store local keys and typed remote-signer records in the OS credential store, falling back to a user-only file store in ngit's data directory when no OS store is available. With credential-backed storage, Git config keeps only public account-selection and alias metadata. Plaintext values in Git config remain supported indefinitely and are never rewritten by reads; run ngit account login to move an existing plaintext login into a credential store. The nostr.secret-storage Git config item, NGIT_SECRET_STORAGE env var, or --secret-storage flag on ngit account login / create selects auto (OS store then file store), file, or git-config (plaintext, the previous behaviour); when a secret cannot be stored, login fails with guidance instead of silently saving plaintext. ngit account logout keeps the stored secret — the store may hold the only copy of the key — and prints the ngit account forget-keys <entry> command that removes it; ngit account logout --forget does both in one step. Generated keys are no longer printed by ngit account create; use ngit account export-keys when the secret needs to be revealed deliberately. See docs/credential-storage.md.
  • Repository-coordinate resolution now follows a documented priority: (1) explicit --repo, (2) git config nostr.repo, (3) current branch's tracked upstream if a nostr:// remote, (4) origin if a nostr:// remote, (5) sole remaining distinct nostr coordinate. When multiple distinct coordinates remain and none of the earlier rules match, ngit errors by default and prints how to disambiguate, instead of silently picking one at HashMap-iteration random. Interactive selection is offered only when -i is explicitly requested and uses deterministic (name-sorted) ordering.
  • ngit init first-time use now recreates the existing origin as a remote named after the git server's domain (e.g. github for github.com; deeper hosts drop the public suffix and dash-join the rest, like git-fiatjaf for git.fiatjaf.com; name collisions get a numeric suffix) instead of discarding its URL entirely when origin is repointed at the nostr URL. Branch upstreams and existing tracking refs are untouched.
  • ngit init now pushes git data and publishes the repository state in-process instead of spawning git push / ngit sync subprocesses. The state is cached and broadcast only after a Git server accepts the data and a relay accepts the event. A failure while pushing or establishing the state is a real error that reports that the announcement was already published and names the follow-up command (git push -u origin <branch> or ngit sync), instead of being downgraded to a warning.
  • Repeat ngit init on a repository that already has a state event republishes it as a fresh event (identical refs, new event id) through the same acceptance-gated flow as a push, so relays and git servers newly added to the announcement receive the repository state immediately instead of only on the next git push. Establishing the state during init now requires at least one reachable git server.
  • ngit init on a repository with a pre-existing reachable origin now records refs/remotes/origin/* remote-tracking refs for the branches covered by the published state, so ahead/behind reporting against the repointed nostr origin is correct before the first push.
  • The remote helper no longer creates, updates or deletes refs/remotes/<remote>/* tracking refs itself: git's own transport layer performs those updates for every ref the helper reports ok, mapping the destination through remote.<name>.fetch. The helper's only remaining local ref bookkeeping is deleting legacy tag tracking refs written by old ngit versions. Two behaviours deliberately change to match vanilla git semantics: a remote whose remote.<name>.fetch refspec has been narrowed no longer receives tracking refs for pushed branches outside that refspec, and git push <nostr-url> with no configured remote now completes without the helper's previous bookkeeping error, writing no tracking refs.

Removed

  • Remove the former ngit pr merge --squash option so the canonical command
    and its top-level alias expose one identical no-ff merge interface. Use Git's
    manual squash workflow when a single-parent result is desired.

Fixed

  • Invalid repository self-defer role records are now author-scoped health
    problems instead of repository-wide failures. A strictly later signed
    self-role restores current authority without rewriting the malformed
    history; otherwise only that signer is gated and can explicitly repair the
    record with ngit repo edit --repair-self-defer or accept a fresh role. A
    numeric repair now merges a same-role successor into one multi-interval
    record so the signed replacement does not retain a duplicate-role conflict.
  • Unparseable repository role records, including records with non-hex
    subjects, no longer abort repository parsing or read as a signed departure.
    They remain byte-for-byte on the source announcement but never grant
    authority or enter copied history. An author whose own role records are
    exclusively malformed is blocked —
    excluded from authority as an author-scoped health problem that gates only
    that signer's announcement edits (no automated repair exists yet) — while
    the repository stays readable through the selected coordinate instead of
    suggesting a follow-lead redirect that cannot resolve. A valid numeric
    departure still departs, and still redirects, even beside malformed tags.
  • The nostr:// Git remote helper now accepts raw commit object IDs on the
    source side of push refspecs, matching Git's normal behavior for commands
    such as git push origin <oid>:refs/heads/recovery. Branch and lightweight
    tag destinations are recorded in repository state without requiring a
    temporary local ref.
  • Blossom presence checks and upload responses now treat a server's MIME type
    as representation metadata rather than blob identity. Content-addressed bytes
    can be reused by files with different media types, so an existing empty blob
    labelled inode/x-empty no longer blocks publication of an empty CSS file;
    hash, size, and descriptor URL validation remain strict.
  • ngit update now recognizes signed prerelease events whose NIP-82 channel
    matches the first SemVer prerelease identifier (rc.7 uses rc, beta.2
    uses beta) for both automatic and exact-version updates, while continuing
    to accept backward-compatible main-channel events. Stable releases remain
    restricted to main, and pending-release warnings now use the correct
    singular or plural verb.
  • Remote-signer login no longer overwrites a different NIP-46 connection for
    the same npub before failing to persist Git config. A bare npub retains its
    default signer, while --alias <name> stores and selects additional signer
    sessions independently for login, push, and account export-keys.
    Credential-store alias values remain raw npubs so older ngit versions can
    continue reading them. If only one session remains and it was stored for an
    alias, either the npub or alias can still select it; multiple sessions with
    no default require an alias.
  • ngit account export-keys --secret prints only the selected account's nsec
    or nbunksec, providing a direct human-readable export without a JSON wrapper
    or interactive menu.
  • ngit repo edit now refreshes the maintainer's current announcement from
    every NIP-65 write relay before deriving a replacement. A cold cache can no
    longer let a stale indexer announcement make a targeted --add-* edit drop
    existing grasp servers, relays, clone URLs, hashtags, or membership data;
    incomplete account-relay reads fail before anything is signed or published.
  • ngit merge now preserves staged, unstaged, and untracked changes across
    the merge commit and branch switch, including the staged/unstaged boundary.
    If those changes conflict with the merged target, ngit rolls the merge back
    and restores the original branch and worktree. Linked worktrees are
    supported when the command runs from the worktree that owns the target
    branch; if another worktree owns it, ngit refuses before changing either
    worktree or the shared target ref.
  • ngit init --defaults no longer drops grasp hosting when --additional-clone
    or --additional-relay is supplied. Additional infrastructure supplements the
    account's preferred grasp servers (or ngit's defaults) instead of silently
    replacing them, so the announcement keeps its grasp-derived clone URLs and
    relays. Publishing without any grasp server is now stated explicitly with an
    empty value, --grasp-server "", which also requires an additional relay and
    clone URL of its own. Republishing an announcement that genuinely declares no
    grasp servers no longer grafts the defaults onto it.
  • ngit init and ngit repo edit refuse to publish a repository announcement
    whose relay or clone field would be empty, naming --grasp-server,
    --additional-relay and --additional-clone as the ways to supply the
    missing half. The check runs on the resolved announcement before anything is
    signed, so it covers every flag shape and repository configuration, including
    a metadata-only edit of an announcement that already lacks hosting — which
    previously republished the unusable announcement and then failed while
    pushing git data with no git server to connect to.
  • Prevent TLS client initialization from panicking after Reqwest 0.13 selected
    AWS-LC alongside rust-nostr's Ring provider. Reqwest remains
    provider-neutral while ngit explicitly installs Ring before constructing
    either its application or library HTTP clients.
  • Repository-conditioned global signer identities, aliases, and secret-storage
    policies selected through Git includeIf gitdir conditions are now
    resolved in repository context. Conditional signers work for
    ngit account whoami and ordinary signed commands, while
    nostr.secret-storage and legacy nostr.credential-store settings control
    login storage and plaintext hints.
  • ngit now honours GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM and GIT_CONFIG_NOSYSTEM when resolving Git config scopes outside the repository. libgit2 does not apply these to the config ngit opens, so a login stored, read or removed with --global (or any global-scope read, such as the secret-storage policy) previously went to ~/.gitconfig regardless of the redirect, silently overwriting the real global login of anyone who sandboxes ngit with the documented variables.
  • Keep --json output parseable by sending relay-fetch summaries such as no updates and updates: ... to stderr instead of stdout.
  • git push --force-with-lease now works with nostr:// remotes: matching leases authorize guarded non-fast-forward updates, while stale leases reject the push before a conflicting repository state can be published.
  • git push of a pr/ branch alongside branch or tag changes now reports the proposal ref as failed when no git server accepts the pushed git data, matching the branch/tag refs. Proposal events are broadcast to the repository and user relays only after a git server accepts the pushed data; previously the helper told git ok and recorded a refs/remotes/<remote>/pr/<branch> tracking ref in that total-failure case even though the proposal events were never broadcast.
  • git push to a nostr remote now treats a git server that already has every requested change as a successful push target, so no-op pushes (re-pushing a tag that is already present, deleting an already-deleted branch) succeed instead of erroring, including under nostr.nostate. Git data is no longer pushed to a GRASP server whose paired relay did not accept the staged state event, and the locally cached repository state is only updated after a git server accepted the pushed data and a relay accepted the state event, so a failed or interrupted push leaves the previous state authoritative instead of caching an unpublished replacement.
  • Git pushes that encounter libgit2's internal protocol assertion now retry
    through the system Git transport, allowing affected SSH servers such as
    tangled.org to accept the same push.
  • Make ahead/behind commit walks topology-complete so merged side-branch commits with equal timestamps are not skipped, restoring every issue-resolution status generated from a multi-merge push.
  • Fast successive repository and proposal updates now order reliably despite Nostr's whole-second timestamps. Repository state, announcements, and statuses use bounded nonce grinding with a timestamp fallback; GRASP now honors the lower-event-ID tie-break for same-second state replacements. Patch revisions and pull-request upgrades or updates remain strictly ordered by timestamp.
  • ngit init first-time use no longer fails to publish git data for existing origin refs that were never downloaded locally (e.g. tags after a --no-tags or single-branch clone): the missing objects are now fetched from the origin by ref name before the repository state is signed, and refs whose objects still cannot be obtained are excluded from the state event instead of being advertised as oids no git server holds.
  • Fix silent mis-targeting of repo-scoped events (ngit send, ngit issue create, ngit pr *, ngit repo, etc.) when a repository had multiple nostr:// remotes with disagreeing coordinates. Previously the resolver iterated a HashMap and picked the first key it saw, ignored nostr.repo, and printed no diagnostic; the effect was that PRs and issues could be published against the wrong repository coordinate without warning. See the documented priority under "Changed".
  • ngit merge run with no argument on a bare pr/<name> branch now falls back to matching the branch's tip commit against the published tips of open and draft PRs when the logged-in-author mapping finds zero or several candidates. A maintainer merging a contributor's PR from a hand-made bare branch, and a logged-out user merging their own, now resolve the PR instead of erroring; when several open PRs share both the branch name and the tip commit, merge still asks for an explicit event-id.