node-git-server logonode-git-server

Programmatic Directories

Instead of a base directory, the first argument to new Git() can be a function that maps a repository name to a location on disk. This lets you shard repositories, namespace them per user, or resolve them from another source.

A resolver function

import { Git } from "@batchfy/node-git-server"
import path from "node:path"
 
const root = "/srv/git"
 
const repos = new Git((repo) => {
    // repo is e.g. "alice/website.git"
    return path.join(root, repo ?? "")
})

The resolver is called with the repository name and must return the directory where that repository lives (or should be created). It is called multiple times for the same repository, so it must be deterministic — always return the same path for the same input.

Note: the resolver is also called with no argument when listing repositories, so handle the undefined case by returning the root directory.

Namespacing by user

const repos = new Git((repo) => {
    // "alice/website.git" -> "/srv/git/alice/website.git"
    const [user, ...rest] = (repo ?? "").split("/")
    return path.join("/srv/git", user, rest.join("/"))
})

Async resolvers

The resolver may return a Promise<string>, which is perfect for looking the path up from a database. See Async Authentication for a full example.

const repos = new Git(async (repo) => {
    const projectId = await db.project.resolveId(repo)
    return `/srv/git/${projectId}.git`
})