This guide explains how to use beads with protected branches on platforms like GitHub, GitLab, and Bitbucket.
Note: This document describes a workflow that has been removed. Beads now stores data in Dolt under refs/dolt/data, separate from standard Git refs. Beads does not commit to any Git branch, so protected branch workflows are not affected.
Previous problem: GitHub and other platforms let you protect branches (like main) to require pull requests for all changes. Previously, beads committed issue data to Git branches, which conflicted with branch protection.
Current solution: Beads uses Dolt-native sync (bd dolt push / bd dolt pull). No Git branch commits are needed. The information below is retained for historical reference and for users migrating from older versions.
Benefits:
- ✅ Works with any git platform's branch protection
- ✅ Main branch stays protected
- ✅ No disruption to your primary working directory
- ✅ Backward compatible (opt-in via config)
- ✅ Minimal disk overhead (uses sparse checkout)
- ✅ Platform-agnostic solution
1. Initialize beads with a separate sync branch:
cd your-project
bd initThis creates a .beads/ directory with a Dolt database. Sync is handled via bd dolt push / bd dolt pull.
Important: After initialization, you'll see some untracked files that should be committed to your protected branch:
# Check what files were created
git status
# Commit the beads configuration to your protected branch
git add .beads/.gitignore .gitattributes
git commit -m "Initialize beads issue tracker"
git push origin main # Or create a PR if requiredFiles created by bd init:
Files that should be committed to your protected branch (main):
.beads/.gitignore- Tells git what to ignore in .beads/ directory.gitattributes- Configures merge driver for beads data
Files that are automatically gitignored (do NOT commit):
.beads/dolt/- Dolt database directory (local only).beads/dolt/sql-server.pid,sql-server.log- Dolt server runtime files
The sync branch (beads-sync) will contain:
.beads/metadata.json- Metadata about the beads installation.beads/config.yaml- Configuration template (optional)
2. Start the Dolt server:
dolt sql-serverWith git hooks installed (bd hooks install), issue changes are automatically committed to the beads-sync branch.
3. When ready, merge to main:
# Check what's changed
bd dolt show
# Merge to main
git merge beads-syncThat's it! The complete workflow is described below.
Beads uses git worktrees to maintain a lightweight checkout of your sync branch. Think of it as a mini git clone that shares the same repository history.
Directory structure:
your-project/
├── .git/ # Main git directory
│ └── beads-worktrees/
│ └── beads-sync/ # Worktree (only .beads/ checked out)
│ └── .beads/
│ └── dolt/
├── .beads/ # Your main copy
│ ├── dolt/
│ └── .gitignore
├── .gitattributes # Merge driver config (in main branch)
└── src/ # Your code (untouched)
What lives in each branch:
Main branch (protected):
.beads/.gitignore- Tells git what to ignore.gitattributes- Merge driver configuration
Sync branch (beads-sync):
.beads/metadata.json- Repository metadata.beads/config.yaml- Configuration template
Not tracked (gitignored):
.beads/dolt/- Dolt database directory (local only).beads/dolt/sql-server.*- Dolt server runtime files
Key points:
- The worktree is in
.git/beads-worktrees/(hidden from your workspace) - Only
.beads/is checked out in the worktree (sparse checkout) - Changes to issues are committed in the worktree
- Your main working directory is never affected
- Disk overhead is minimal (~few MB for the worktree)
When you update an issue:
- Issue is updated in the Dolt database (
.beads/dolt/) - Dolt automatically commits the change to its version history
- Changes are synced to remotes via
bd dolt push - Main branch stays untouched (no commits on
main)
cd your-project
bd initThis will:
- Create
.beads/directory with Dolt database - Prompt to install git hooks (recommended: say yes)
If you already have beads set up and want to switch to a separate branch:
# Set the sync branch
bd config set sync.branch beads-sync
# Start the Dolt server and install git hooks
bd dolt start
bd hooks installFor automatic commits to the sync branch, install git hooks:
bd hooks installGit hooks help maintain sync consistency. Use bd dolt push for manual sync when needed.
You can also configure the sync branch via environment variable:
export BEADS_SYNC_BRANCH=beads-syncThis is useful for CI/CD or temporary overrides.
AI agents work exactly the same way as before:
# Create issues
bd create "Implement user authentication" -t feature -p 1
# Update issues
bd update bd-a1b2 --claim
# Close issues
bd close bd-a1b2 "Completed authentication"All changes are automatically committed to the beads-sync branch via git hooks. No changes are needed to agent workflows!
Check status:
# See what's changed on the sync branch
bd dolt showThis shows the current Dolt configuration and connection status.
Manual commit:
bd dolt commit # Commit pending changesPull changes from remote:
# Pull updates from other collaborators
bd dolt pullThis pulls changes from the remote and imports them to your local database.
For protected branches with required reviews:
# 1. Push your sync branch
git push origin beads-sync
# 2. Create PR on GitHub/GitLab/etc.
# - Base: main
# - Compare: beads-sync
# 3. After PR is merged, update your local main
git checkout main
git pull
bd dolt pull # Pull latest changesIf you have push access to main:
# Sync via Dolt (no git branch merge needed)
bd dolt push
bd dolt pullSafety checks:
- ✅ Verifies you're not on the sync branch
- ✅ Checks for uncommitted changes in working tree
- ✅ Detects merge conflicts and provides resolution steps
- ✅ Uses
--no-fffor clear history
If you encounter conflicts during merge:
# git merge may detect conflicts and show:
Auto-merging .beads/...
CONFLICT (content): Merge conflict in .beads/...
To resolve:
1. Use bd vc conflicts to view conflicts
2. Resolve conflicts
3. Commit the resolutionResolving merge conflicts:
Dolt handles merge conflicts natively with cell-level merge. When concurrent changes affect the same issue field, Dolt detects the conflict and allows resolution:
# After a Dolt pull with conflicts
bd vc conflicts # View conflicts
bd vc resolve # Resolve conflictsThis happens if you created the sync branch independently. Merge with --allow-unrelated-histories:
git merge beads-sync --allow-unrelated-histories --no-ffOr merge manually with git merge beads-sync --allow-unrelated-histories --no-ff.
If the worktree is corrupted or in a bad state:
# Remove the worktree
rm -rf .git/beads-worktrees/beads-sync
# Prune stale worktree entries
git worktree prune
# Restart Dolt server (it will recreate the worktree)
bd dolt stop && bd dolt startThe sync branch doesn't exist yet. It will be created on the first commit. Create it manually:
git checkout -b beads-sync
git checkout main # Switch backIf the sync branch itself is protected:
- Option 1: Unprotect the sync branch (it's metadata, doesn't need protection)
- Option 2: Use
--auto-commitwithout--auto-push, and push manually when ready - Option 3: Use a different branch name that's not protected
Check server status and logs:
# Check status
bd dolt status
# View logs
tail -f .beads/dolt/sql-server.log
# Restart server
bd dolt stop && bd dolt startCommon issues:
- Port already in use: Another Dolt server is running
- Permission denied: Check
.beads/directory permissions - Git errors: Ensure git is installed and repository is initialized
Ensure all clones are configured the same way:
# On each clone, verify:
bd config get sync.branch # Should be the same (e.g., beads-sync)
# Pull latest changes
bd dolt pull
# Check Dolt server is running
bd dolt statusNo! This is a pure git solution that works on any platform. Just protect your main branch as usual.
Yes! Use any branch name except main or master (git worktrees cannot checkout the same branch in multiple locations):
bd dolt remote add origin <remote-url>
bd dolt pushYes:
bd config set sync.branch new-branch-name
bd dolt stop && bd dolt startThe old worktree will remain (no harm), and a new worktree will be created for the new branch.
Unset the sync branch config:
bd config set sync.branch ""
bd dolt stop && bd dolt startBeads will go back to committing directly to your current branch.
Yes! Each collaborator configures their own sync branch:
# All collaborators use the same branch
bd config set sync.branch beads-syncEveryone's changes sync via the beads-sync branch. Periodically merge to main via PR.
This depends on your workflow:
- Daily: If you want issue history in
mainfrequently - Per sprint: If you batch metadata updates
- As needed: Only when you need others to see issue updates
There's no "right" answer - choose what fits your team.
Yes! Use bd dolt show to check current status, or use git to compare branches:
git log main..beads-sync --oneline
# Shows commits on beads-sync not yet in mainOr create a pull request and review on GitHub/GitLab.
Worktrees are very lightweight:
- Sparse checkout means only
.beads/is checked out - Typically < 1 MB for the worktree
- Shared git history (no duplication)
Yes, but it may be recreated on next sync. If you want to clean up permanently:
# Stop Dolt server
bd dolt stop
# Remove worktree
git worktree remove .git/beads-worktrees/beads-sync
# Unset sync branch
bd config set sync.branch ""Yes! bd dolt push works normally. Related commands for the merge workflow:
bd dolt show- Show current Dolt configuration and connection statusgit merge beads-sync- Merge sync branch to main
Not recommended! Merging to main is a deliberate action that should be human-reviewed, especially with protected branches. Agents should create issues and update them; humans should merge to main.
However, if you want fully automated sync:
# WARNING: This bypasses branch protection!
git merge beads-sync # Run periodically (e.g., via cron)No problem! The sync branch accumulates all changes. When you eventually merge:
git checkout main
git merge beads-sync --no-ff
git pushAll accumulated changes will be merged at once. Git history will show the full timeline.
Yes! Example GitHub Actions workflow:
name: Sync Beads Metadata
on:
schedule:
- cron: '0 0 * * *' # Daily at midnight
workflow_dispatch: # Manual trigger
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Full history
- name: Install bd
run: |
curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
- name: Pull changes
run: |
git fetch origin beads-sync
bd dolt pull
- name: Merge to main (if changes)
run: |
if git log main..beads-sync --oneline | grep -q '.'; then
git merge beads-sync --no-ff -m "Merge beads-sync metadata"
git push origin main
fiNote: Make sure the GitHub Action has write permissions to push to main.
Protected branch settings:
- Go to Settings → Branches → Add rule
- Branch name pattern:
main - Check "Require pull request before merging"
- Save
Create sync branch PR:
git push origin beads-sync
gh pr create --base main --head beads-sync --title "Update beads metadata"Protected branch settings:
- Settings → Repository → Protected Branches
- Branch:
main - Allowed to merge: Maintainers
- Allowed to push: No one
Create sync branch MR:
git push origin beads-sync
glab mr create --source-branch beads-sync --target-branch mainProtected branch settings:
- Repository settings → Branch permissions
- Branch:
main - Check "Prevent direct pushes"
Create sync branch PR:
git push origin beads-sync
# Create PR via Bitbucket web UIYou can use different sync branches for different purposes:
# Development branch
bd config set sync.branch beads-dev
# Production branch
bd config set sync.branch beads-prodSwitch between them as needed.
If you're working on a fork:
# Add upstream
git remote add upstream https://github.com/original/repo.git
# Fetch upstream changes
git fetch upstream
# Merge upstream beads-sync to yours
git checkout beads-sync
git merge upstream/beads-sync
bd dolt pull # Pull merged changesBy default, worktrees are in .git/beads-worktrees/. This is hidden and automatic. If you need a custom location, you'll need to manage worktrees manually (not recommended).
If you have an existing beads setup committing to main:
-
Set sync branch:
bd config set sync.branch beads-sync -
Restart Dolt server:
bd dolt stop && bd dolt start -
Verify:
bd config get sync.branch # Should show: beads-sync
Future commits will go to beads-sync. Historical commits on main are preserved.
If you want to stop using a sync branch:
-
Unset sync branch:
bd config set sync.branch ""
-
Restart Dolt server:
bd dolt stop && bd dolt start
Future commits will go to your current branch (e.g., main).
Need help? Open an issue at https://github.com/steveyegge/beads/issues