git

package
v1.36.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendExclude added in v1.36.0

func AppendExclude(sitePath, pattern string) error

AppendExclude adds pattern to the site's .git/info/exclude once.

func BranchExists added in v1.21.0

func BranchExists(dir, branch string) bool

BranchExists reports whether refs/heads/<branch> resolves inside the repo at dir. Returns false when branch is empty, when dir is not a repo, or when the ref cannot be resolved.

func CopyTree added in v1.16.0

func CopyTree(src, dst string) error

CopyTree copies src to dst recursively. It first tries a reflink-aware fast path via cp, which is near-instant on btrfs, XFS with reflink=1, and APFS. Falls back to a plain recursive Go copy elsewhere. dst must not already exist.

func DeriveWorktreeAddArgs added in v1.36.0

func DeriveWorktreeAddArgs(sitePath string, args []string) []string

DeriveWorktreeAddArgs supplies the checkout path `git worktree add` requires when the user did not type one. The docs describe every form without a path (`lerd worktree add -b feat-x`), and the dashboard honours that by computing the path through WorktreeCheckoutPath, but the CLI forwarded its arguments to git untouched, so each documented form died on git's usage message.

Only the two unambiguous shapes are filled in: an explicit new branch, and a single bare existing branch. Anything else is passed through exactly as typed, because guessing which positional is a path and which is a commit-ish is how a wrapper starts checking out the wrong thing.

func EnclosingRepo added in v1.36.0

func EnclosingRepo(dir string) (string, bool)

EnclosingRepo returns the top of the work tree that tracks dir. A folder the enclosing repo ignores is not part of it, so it reports no repo.

func EnsureNestedWorktreeExclude added in v1.36.0

func EnsureNestedWorktreeExclude(sitePath string) error

EnsureNestedWorktreeExclude appends "/<base>-*/" to .git/info/exclude in sitePath (idempotent) so nested worktree dirs don't show up in git status of the parent repo. No-op when .git isn't a dir or when basename contains gitignore meta-chars we'd have to escape.

func EnsureWorktreeDeps

func EnsureWorktreeDeps(mainRepoPath, worktreePath, worktreeDomain string, secured bool, out io.Writer)

EnsureWorktreeDeps sets up a worktree checkout with the dependencies it needs:

  • vendor/ and node_modules/ are seeded from the main repo via a reflink copy (near-instant on btrfs, xfs-reflink, APFS; plain copy on ext4), then reconciled against the worktree's own lockfiles via composer install / npm ci.
  • paths listed in the main repo's .lerd.yaml worktree_include are copied across, for gitignored files the app needs to run
  • .env is copied from the main repo with APP_URL rewritten to http(s)://<worktreeDomain>

Copying (rather than symlinking) is required because PHP resolves __DIR__ through symlinks, which would make Composer's ClassLoader initialise against the main repo directory and silently load stale classes from there.

out receives composer/npm install output; pass nil for the default stdout/stderr (which is what the watcher daemon's launchd unit captures to lerd-watcher.log).

func EnsureWorktreeEnv added in v1.19.0

func EnsureWorktreeEnv(mainRepoPath, worktreePath, worktreeDomain string, secured bool)

EnsureWorktreeEnv seeds the worktree's env file from the main repo when missing (gitignored, so `git worktree add` never carries it across) and rewrites the framework's url_key to the worktree domain. The env file, its format and url_key all come from the framework definition, so every framework is seeded where it actually reads: Symfony's .env.local / DEFAULT_URI, CodeIgniter's config/.env / app.baseURL, WordPress's wp-config.php / WP_HOME, Magento's app/etc/env.php (php-array, whose base URL lives in the database so it declares no url_key and only the file is carried across for its database credentials). When the main repo's .lerd.yaml defines env_overrides, those dotenv templates are resolved and layered on top — only keys declared in env_overrides are touched, so partial overrides (e.g. SESSION_DOMAIN only) don't suppress the url_key rewrite. Idempotent and cheap; safe to call on every request.

func HasJSPackages added in v1.36.0

func HasJSPackages(projectPath string) bool

HasJSPackages reports whether projectPath has a package.json that installs anything. npm creates no node_modules for a manifest without packages, so waiting for one would never end. A manifest that does not parse counts as having packages, leaving the install to report what is wrong with it.

func Init added in v1.36.0

func Init(dir string) error

Init creates a repository at dir. It refuses when dir already sits inside a work tree, since a nested repo would silently shadow the parent one.

func InstallDependencies added in v1.16.0

func InstallDependencies(projectPath string, out io.Writer) error

InstallDependencies runs composer install and the JS package manager matching whatever lockfile the project ships so vendor/ and node_modules/ match that checkout's own lockfiles. composer goes through the lerd shim (which routes into the project's PHP-FPM container); JS tooling goes through whichever of pnpm/yarn/bun/npm is on PATH, preferring the npm shim from BinDir when the project uses npm so the fnm Node version is picked up.

Each install is skipped when the relevant install marker (vendor/composer/installed.json for composer, the package manager's own marker under node_modules for JS) is at-or-newer than the lockfile — nothing has drifted, so re-running install would just burn cycles on post-autoload-dump scripts (Laravel package:discover, Filament asset publish, etc.) for no observable change.

Errors are aggregated and returned; callers should log them rather than treat them as fatal since the worktree is still usable with the copied trees from main. out receives both stdout and stderr from composer and the JS package manager; pass nil to fall back to the watcher daemon's own stdout/stderr (which the original launchd unit captures into lerd-watcher.log).

func InstallInFlight added in v1.32.0

func InstallInFlight(worktreePath string) (bool, error)

InstallInFlight reports whether an installer currently holds worktreePath's install lock, the one signal about install progress that cannot lie. It probes with a shared non-blocking flock rather than TryLockInstall so it neither overwrites the pid the real holder recorded nor takes an exclusive lock an installer would then have to poll for.

A missing lock file means no install has ever started for the path, so it is reported as idle. The file deliberately outlives the install that created it, which is why its presence, and the pid inside it, mean nothing on their own.

func IsMainRepo

func IsMainRepo(sitePath string) bool

IsMainRepo returns true if sitePath/.git is a directory (not a file). A file means the repo itself is a worktree, not the main checkout.

func LockInstall added in v1.21.0

func LockInstall(worktreePath string, timeout time.Duration) (func(), error)

LockInstall acquires an exclusive cross-process lock guarding the composer/npm install for worktreePath, blocking until either the lock is held or timeout elapses. Returns release() which drops both the in-process and OS locks; safe to defer.

func MainBranch

func MainBranch(sitePath string) string

MainBranch returns the current branch of the main repo checkout at sitePath, or an empty string if it cannot be determined.

func NeedsInstall added in v1.21.0

func NeedsInstall(projectPath string) bool

NeedsInstall reports whether projectPath has a composer or JS install that hasn't completed. Used by the watcher's periodic rescan to recover from a UI install that crashed between `git worktree add` and the seed.

func Output added in v1.21.0

func Output(dir string, args ...string) (string, error)

Output runs `git <args>` in dir and returns its stdout as a string. If dir is empty, the command inherits the caller's working directory. Stderr is discarded; callers that need it should reach for RunCaptureStderr.

func ResetJSInstallFailures added in v1.32.0

func ResetJSInstallFailures()

ResetJSInstallFailures clears the memo. The watcher calls it at the start of each reconcile pass, so a lockfile the user has since fixed, or one whose install only failed because the registry was unreachable, is tried again.

func Run added in v1.21.0

func Run(dir string, log io.Writer, args ...string) error

Run runs `git <args>` in dir, sending stdout and stderr to log (a single writer; matches the modal-log pattern used by the worktree flows). When log is nil, output is discarded. Empty dir means inherit cwd. The returned error wraps the exec failure with the first non-flag arg so callers can surface "git worktree: exit status 1" rather than the full arg list.

func RunCaptureStderr added in v1.21.0

func RunCaptureStderr(dir string, args ...string) (string, error)

RunCaptureStderr runs `git <args>` in dir, mirroring stdout to os.Stdout and stderr to both os.Stderr and an internal buffer. The captured stderr is returned alongside any exec error so callers can detect specific git error messages (e.g. the "use --force" hint) without dropping the live stream the user is watching.

func RunNpmScript added in v1.19.0

func RunNpmScript(projectPath, script string, out io.Writer) error

RunNpmScript executes `<package-manager> run <script>` in projectPath, using the lerd npm shim for npm projects so fnm's current Node version wins and falling back to PATH for pnpm/yarn/bun. Exported for callers like `lerd worktree add` that opt into a build step interactively. out receives both stdout and stderr from the build; pass os.Stdout for CLI use or an SSE writer to surface vite/webpack failures in the dashboard modal.

func RunTTY added in v1.21.0

func RunTTY(dir string, args ...string) error

RunTTY runs `git <args>` in dir with stdout and stderr wired straight to os.Stdout and os.Stderr so the user's shell redirections (`2>/dev/null`, pipes, etc) still work. Empty dir means inherit cwd.

func SanitizeBranch

func SanitizeBranch(branch string) string

SanitizeBranch converts a branch name to a subdomain-safe slug.

func TryLockInstall added in v1.21.0

func TryLockInstall(worktreePath string) (func(), bool, error)

TryLockInstall is the non-blocking variant of LockInstall: returns (release, true) when the lock was acquired immediately, or (nil, false) when another caller holds it. err is non-nil only on filesystem failures; "already locked" is reported via the boolean.

func WorktreeCheckoutPath added in v1.36.0

func WorktreeCheckoutPath(sitePath, branch string) string

WorktreeCheckoutPath returns the directory a new worktree for branch should be checked out into: a child of the parent site, "<sitePath>/<base>-<slug>" where <base> is filepath.Base(sitePath). Bumps a numeric suffix if the default path already exists. RunWorktreeAdd also writes a `/<base>-*/` pattern into .git/info/exclude so git status doesn't show siblings. Caveat: non-git tools (composer, IDEs, find/rsync/tar) walking the parent tree DO descend into the worktree — gitignore doesn't hide it from them. Most callers don't care; flag if you do.

Types

type Status added in v1.36.0

type Status struct {
	Staged     int `json:"staged"`
	Modified   int `json:"modified"`
	Untracked  int `json:"untracked"`
	Conflicted int `json:"conflicted"`
	Ahead      int `json:"ahead"`
	Behind     int `json:"behind"`
}

Status is a checkout's working-tree state, as a shell prompt summarises it.

func ParseStatus added in v1.36.0

func ParseStatus(out string) Status

ParseStatus reads `git status --porcelain=v2 --branch` output. In a changed entry's XY field X is the index and Y the working tree, "." meaning untouched.

func ReadStatus added in v1.36.0

func ReadStatus(dir string) (Status, error)

ReadStatus runs `git status` in dir and summarises it.

type Worktree

type Worktree struct {
	Name   string // subdirectory name under .git/worktrees/
	Branch string // sanitized branch (subdomain-safe)
	Path   string // absolute path to checkout dir
	Domain string // "<sanitized-branch>.<siteDomain>"
}

Worktree represents a git worktree checkout for a registered site.

func DetectWorktrees

func DetectWorktrees(sitePath, siteDomain string) ([]Worktree, error)

DetectWorktrees returns the list of active worktrees for the given site.

func FilterReservedWorktrees added in v1.24.0

func FilterReservedWorktrees(wts []Worktree) []Worktree

FilterReservedWorktrees drops any worktree whose domain is owned by a registered group secondary (a site whose primary domain is <label>.<main>). Such a subdomain is carved out of the main's space and served by the secondary's own exact-match vhost; letting the main also emit a worktree vhost for it would collide on the same conf file and server_name. Callers pass the worktrees freshly detected for the main site; the reserved set is read from the site registry (cheap, cached).

func ServableWorktrees added in v1.24.0

func ServableWorktrees(sitePath, siteDomain string) ([]Worktree, error)

ServableWorktrees returns the worktrees that should be web-served for a site: DetectWorktrees minus any whose subdomain is reserved by a group secondary. Every path that generates a worktree vhost or certificate SAN should use this rather than DetectWorktrees, so a reserved subdomain can never collide with the secondary that owns it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL