Skip to content

gitai 0.4.0

Latest

Choose a tag to compare

@feder-cr feder-cr released this 23 Oct 09:16
· 30 commits to main since this release

Operators can create repositories from the CLI and the SDK. Branch names are
read exactly in every RPC, and agents can no longer write the server's own
references in any mode. Reftable housekeeping no longer fails on busy
repositories. Some error codes change; see "Upgrade".

New

  • graft repo create and SDK Repo.Create. An operator, with the
    shared token, creates a repository:
    graft repo create demo.git --initial-commit --branch feature/demo.
    The repository can be cloned straight away. The command converges: run it
    again after a failure and it does only what is missing. It never adds a
    commit to a repository that already has references, and it refuses when
    HEAD points to another branch. Agent tokens are refused. In authoritative
    mode the repository is registered with the storage core; in shadow mode the
    command prints the graft storage import step. QUICKSTART no longer needs
    git init and git push.

Security

  • Branches are read by their exact names in every operations RPC:
    UserFFBranch, UserMergeBranch, UserDeleteBranch, UserUpdateSubmodule,
    UserCherryPick, UserRevert, UserApplyPatch, UserRebaseConfirmable and the
    default branch. Before, git's revision rules let another reference answer
    for a branch, such as refs/tags/refs/heads/x or a tag named like an
    existing branch. Any client that could push a tag could use that to choose
    the commit an operation started from.

  • Start points (start_branch_name of cherry-pick and revert, the remote
    branch of a rebase) follow git, with one difference: an existing branch
    beats a tag or a refs/x of the same name. Also:

    • a full object ID is that commit;
    • refs/... is read exactly;
    • heads/, tags/ and remotes/ names follow git;
    • a reflog entry needs the reference's own reflog;
    • <rev>:path is refused.

    The local and the start-repository paths give the same answers.

  • Agents never write refs/graft/, in every mode. The reservation was
    enforced by the reference-transaction hook only in standalone mode. It is
    now an invariant of the server. SSHService/SSHUploadArchive can no longer
    be opened to agents: git's upload-archive ignores hidden references, so it
    could read refs/graft/ by name. The layers are described in
    AGENT-SECURITY.md, with end-to-end tests that push as an agent and drive
    the real hook in both modes.

Fixes

  • Reftable housekeeping on busy repositories. git pack-refs exits with
    a lock or "concurrently modified" error when a writer races it. That
    failure is harmless (git itself ignores it), but it failed the whole
    OptimizeRepository, so the commit-graph and later steps were skipped.
    It is now recorded as packed_refs=skipped, with a warning, and
    housekeeping continues; every other error stays fatal.
  • Stale reftable table locks (<table>.ref.lock, left by a killed git) are
    removed after the same grace period as tables.list.lock. Before, they
    blocked compaction forever.
  • A detached HEAD in FindDefaultBranchName (head only) is a
    FailedPrecondition, not an Internal error.

Measured, not built

STORAGE.md has two new sections, both measured and both ending in "don't
build":

  • Where the upload time goes. A file-bucket upload costs two fsyncs.
    Sharing the directory fsync would save at most 4.3 ms, and it is worse for
    large packs. The long tails in use come from the disk being shared with
    the database: put the bucket on another device.
  • Inline compaction stays. Without git's inline reftable compaction, 50
    writers are 2.6x slower and reads 4x slower.

CI

  • Tests that pass only on gotestsum's re-run are now shown as warnings on
    the run page, and their output is kept as an artifact. Before, they left
    the job green and invisible.
  • New legs run the reference-heavy packages on reftable.
  • Five timing-dependent tests now assert their property without the wall
    clock.

Upgrade

Error codes that change:

  • A contended repository lock in CreateRepository, CreateFork,
    CreateRepositoryFrom*, CreateObjectPool, ReplicateRepository and backup
    restore: Internal → FailedPrecondition "repository is already locked".
  • UserCreateBranch refused by access checks: Internal → PermissionDenied.
  • A revision passed as a branch name (main~1) now fails as not found when
    the branch is read.
  • gitaly_housekeeping_tasks_total has a new status skipped for
    packed_refs. On reftable, these events used to count as failures.

Configuration:

  • An agent_rpcs entry that names gitaly.SSHService/SSHUploadArchive now
    stops the server at startup. Remove it.

No data migration.