Files
ecuthiell 766e6c17f2 fix: reject incompatible timeout in generated hooks (#5522)
Select timeout or gtimeout only after a successful GNU coreutils identity probe, validate BEADS_HOOK_TIMEOUT as positive whole seconds, and preserve the Perl and warned direct fallbacks under inherited shell options.

Keep GNU and Perl deadlines soft and backend-scoped, preserve natural status 137, regenerate every tracked hook artifact, and exercise the real process boundary through the required three-host preflight.

Fixes #5503

Agent-Signature: codex-gpt-5-unknown-reasoning on behalf of Ewen Cuthiell
2026-08-10 20:47:53 -07:00

323 lines
10 KiB
Markdown

---
title: Git Integration
description: How bd uses git for hosting and hooks, including hook installation, external hook managers, worktrees, and branch workflows.
---
How beads integrates with git.
## Overview
Beads uses git for:
- **Project hosting** - Your code repository also hosts beads configuration
- **Hooks** - Auto-sync on git operations
Data storage and sync are handled by Dolt (a version-controlled SQL database) —
see [Sync Concepts](/core-concepts/sync-concepts) for how issue data moves
between machines.
## File Structure
```
.beads/
├── config.yaml # Project config (git-tracked)
├── metadata.json # Backend metadata (git-tracked)
├── .gitignore # Written by bd init (git-tracked)
├── embeddeddolt/ # Dolt database — embedded mode, the default (gitignored)
└── dolt/ # Dolt database — server mode (gitignored)
```
`bd init` writes `.beads/.gitignore` to keep the database directory and
runtime files out of git — no manual gitignore rules are needed. Never track
the database directory (`.beads/embeddeddolt/` or `.beads/dolt/`) in git or
via Git LFS.
## Git Hooks
### Installation
`bd init` installs hooks by default (skip with `bd init --skip-hooks`). To
install or refresh them manually:
```bash
bd hooks install
```
Installed hooks are thin shims that call `bd hooks run <hook-name>`. Upgrading
`bd` automatically updates the delegated behavior inside that command; the
shim's generated shell policy remains installed content and changes only when
the hook is installed or refreshed:
| Hook | What it does |
|------|--------------|
| `pre-commit` | Runs chained hooks; when `export.auto` is enabled, exports `.beads/issues.jsonl` so it lands in the same commit |
| `post-merge` | Runs chained hooks; imports JSONL only as a legacy fallback when no Dolt remote is configured — with `sync.remote` set, `bd dolt pull` is the canonical sync |
| `pre-push` | Runs chained hooks before push |
| `post-checkout` | Runs chained hooks after branch checkout |
| `prepare-commit-msg` | Adds an `Executed-By:` agent identity trailer when an agent (`BD_ACTOR`) makes the commit |
The shims use section markers to coexist with existing hooks — content
outside the markers is preserved across installs and upgrades. Install
variants:
```bash
bd hooks install --beads # Install to .beads/hooks/ (recommended for the Dolt backend)
bd hooks install --shared # Install to .beads-hooks/ (versioned, shareable with the team)
bd hooks install --chain # Run existing hooks before bd hooks
```
Hook installation is worktree-aware: `bd` resolves the shared git directory,
so installing from a linked worktree works.
### Status
```bash
bd hooks list
```
### Uninstall
```bash
bd hooks uninstall
```
### External Hook Managers
bd detects these external git hook managers and checks whether their config
calls `bd hooks run`:
- [lefthook](https://lefthook.dev/) — YAML/TOML/JSON config
- [husky](https://typicode.github.io/husky/) — `.husky/` directory scripts
- [pre-commit](https://pre-commit.com/) — `.pre-commit-config.yaml`
- [prek](https://prek.j178.dev/) — Rust-based pre-commit alternative (same config)
- [hk](https://hk.jdx.dev/) — fast hook manager using Pkl config
- [overcommit](https://github.com/sds/overcommit) — Ruby-based (detection only)
- yorkie — detection only
- [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) — lightweight JS (detection only)
`bd doctor` reports whether a detected manager is integrated with bd, and
`bd doctor --fix` reinstalls the hooks with `--chain` so the manager's
existing hooks keep running.
For config-driven managers, add bd steps directly. Example `hk.pkl`:
```pkl
hooks {
["pre-commit"] {
steps {
["bd-pre-commit"] {
check = "bd hooks run pre-commit"
}
}
}
["post-merge"] {
steps {
["bd-post-merge"] {
check = "bd hooks run post-merge"
}
}
}
["pre-push"] {
steps {
["bd-pre-push"] {
check = "bd hooks run pre-push \"$@\""
}
}
}
}
```
### Hook Timeout
The hook shim applies a soft deadline to `bd hooks run` when a compatible
helper is available. It
uses `timeout` or `gtimeout` only after a successful GNU coreutils identity
probe, avoiding the incompatible `timeout.exe` that native Windows can place
on `PATH`. GNU timeout sends `TERM` at the configured deadline. On POSIX hosts,
the Perl fallback uses `SIGALRM` on the direct `bd` process at the deadline.
Git for Windows Perl does not guarantee that alarm across `exec`, so GNU
coreutils is the preferred deadline backend there.
The default deadline is **300 seconds** (5 minutes), which accommodates chained
pre-commit pipelines (eslint, prettier, TypeScript compilation). Override it
with the `BEADS_HOOK_TIMEOUT` environment variable:
```bash
# Set a longer timeout (in seconds)
export BEADS_HOOK_TIMEOUT=600 # 10 minutes
# Or set it per-invocation
BEADS_HOOK_TIMEOUT=600 git commit -m "..."
```
The value must be a positive whole number of seconds. Invalid values and zero
produce a warning and use the 300-second default. These are soft process
deadlines, not process-tree containment: TERM-resistant work or descendants
can outlive them. If neither GNU timeout nor Perl is available, the hook warns
and runs directly without a deadline; that last-resort path can hang until the
hook itself returns.
After upgrading from a release whose generated hooks used a name-only timeout
check, run `bd hooks install` once to refresh already-installed canonical hook
sections. Automatic generated-policy adoption is tracked separately.
When the timeout is reached, beads prints a warning and lets the git
operation proceed — the commit or push is not blocked.
## Conflict Resolution
Dolt handles merge conflicts at the database level using its built-in
merge capabilities. When conflicts arise during sync, Dolt identifies
conflicting rows and allows resolution through SQL.
```bash
# Check for and fix conflicts
bd doctor --fix
```
## Protected Branches
Dolt stores data under `refs/dolt/data`, separate from Git refs. This means
beads data does not conflict with protected Git branches, and no separate
`beads-sync` branch or protected-branch exception is needed. On new projects
with a Git `origin`, `bd init` configures that origin as the Dolt remote
automatically.
See [Protected Branches](/reference/protected-branches) for the full
workflow, including legacy `beads-sync` cleanup.
## Git Worktrees
Beads works in Git worktrees without extra setup. Linked worktrees discover the
repository's `.beads` workspace and sync issue data through Dolt:
```bash
# In a linked worktree
bd create "Task"
bd list
bd dolt pull
bd dolt push
```
All worktrees share the repository's `.beads` workspace: discovery follows
`BEADS_DIR` if set, then the main repository's `.beads`, preventing database
duplication across worktrees. Use `bd where` as the authoritative check for
which workspace is active — a local `./.beads` may legitimately be absent in
a worktree. Embedded mode (the default) serves one writer at a time; for
concurrent writers across worktrees, use server mode. See
[Git Worktrees](/reference/worktrees) for the full guide.
Older beads versions documented a `sync.branch` workflow that created hidden
Git worktrees. That workflow has been removed; current sync uses Dolt remotes.
## Branch Workflows
### Feature Branch
```bash
git checkout -b feature-x
bd create "Feature X" -t feature
# Work...
bd dolt push
git push
```
### Fork Workflow
```bash
# In fork
bd init --contributor # Interactive wizard
# Work in separate planning repo...
bd dolt push
```
The contributor wizard keeps issue data in a separate planning repository,
leaving the upstream repo without any `.beads/`. Best for open source
contributors, solo developers, and private task tracking on public repos.
`bd init` auto-detects forks and offers to configure `.git/info/exclude`
(`--setup-exclude`) so beads files stay local. Set the role without prompting
via `--role contributor` or `--role maintainer` (the default in
non-interactive mode).
### Team Workflow
```bash
bd init --team
# All team members share the Dolt database
bd dolt pull # Pull latest changes from Dolt remote
bd dolt push # Push your changes to Dolt remote
```
Best for teams on protected branches and review-before-merge policies. See
[Multi-Repo Migration](/multi-agent/multi-repo-migration) for multi-repo
patterns.
### Duplicate Detection
After merging branches:
```bash
bd duplicates --auto-merge
```
## Branchless Workflows (Jujutsu / jj)
Beads works with branchless VCS tools like
[Jujutsu (jj)](https://martinvonz.github.io/jj/). Since beads data is stored
in Dolt (not git branches), there is no dependency on the "current branch"
concept.
### What Works Without Hooks
All core beads functionality works without git hooks:
| Feature | Hooks Required? | Notes |
|---------|----------------|-------|
| `bd create`, `bd update`, `bd close` | No | Core CRUD uses Dolt directly |
| `bd ready`, `bd list`, `bd show` | No | Read-only queries |
| `bd dolt push` / `bd dolt pull` | No | Dolt-native sync, independent of git |
| `bd onboard`, `bd doctor` | No | Diagnostics and onboarding |
| Agent identity trailers | Yes | `prepare-commit-msg` hook adds `Executed-By:` to commits |
| Hook chaining | Yes | Preserves existing pre-commit, post-merge hooks |
To skip hooks entirely during init:
```bash
bd init --skip-hooks
```
### What Works Without AGENTS.md
The AGENTS.md file generated by `bd init` provides AI agent instructions. If
you manage your own agent instructions or don't want beads to modify tracked
files:
```bash
bd init --skip-agents # Skip AGENTS.md and Claude/Codex setup generation
bd init --stealth # Full invisible mode (also skips hooks + agents)
```
### Jujutsu Setup
**Colocated repos** (`jj git init --colocate`): Git hooks work normally.
Beads installs simplified hooks (`pre-commit` and `post-merge` only, no
staging logic).
**Pure jj repos** (no git): Since jj doesn't have native hooks yet, set up
push aliases:
```toml
# ~/.config/jj/config.toml
[aliases]
push = ["util", "exec", "--", "sh", "-c", "bd dolt commit && bd dolt push && jj git push \"$@\"", ""]
```
Then use `jj push` instead of `jj git push`.
## Best Practices
1. **Install hooks** - `bd hooks install`
2. **Push regularly** - `bd dolt push` at session end
3. **Pull before work** - `bd dolt pull` to get latest issues
4. **Use normal Git worktrees** - no sync branch is required