Created complete documentation suite for using beads with protected branches: 1. **docs/PROTECTED_BRANCHES.md** - Comprehensive 600+ line guide covering: - Quick start and setup - How git worktrees work - Daily workflow for agents and humans - Merging strategies (PR and direct) - Troubleshooting common issues - Platform-specific notes (GitHub, GitLab, Bitbucket) - Advanced topics (CI/CD, multi-clone sync, etc.) 2. **AGENTS.md** - Added "Protected Branch Workflow" section: - Quick reference for agents - No changes needed to agent workflows - Commands for setup and merging - Link to detailed docs 3. **README.md** - Updated with: - Protected branch support feature flag - Quick start instructions with --branch flag - Link to comprehensive guide 4. **examples/protected-branch/** - Working example with: - Step-by-step demo - Multi-clone sync workflow - GitHub Actions integration example - Directory structure explanation - Troubleshooting tips All commands verified: - bd init --branch <name> - bd config get/set sync.branch - bd sync --status - bd sync --merge Documentation is platform-agnostic and works with GitHub, GitLab, Bitbucket, or any git platform with branch protection. Closes bd-5ce8 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
659 lines
16 KiB
Markdown
659 lines
16 KiB
Markdown
# Protected Branch Workflow
|
|
|
|
This guide explains how to use beads with protected branches on platforms like GitHub, GitLab, and Bitbucket.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Quick Start](#quick-start)
|
|
- [How It Works](#how-it-works)
|
|
- [Setup](#setup)
|
|
- [Daily Workflow](#daily-workflow)
|
|
- [Merging Changes](#merging-changes)
|
|
- [Troubleshooting](#troubleshooting)
|
|
- [FAQ](#faq)
|
|
|
|
## Overview
|
|
|
|
**Problem:** GitHub and other platforms let you protect branches (like `main`) to require pull requests for all changes. This prevents beads from auto-committing issue updates directly to `main`.
|
|
|
|
**Solution:** Beads can commit to a separate branch (like `beads-metadata`) using git worktrees, while keeping your main working directory untouched. Periodically merge the metadata branch back to `main` via a pull request.
|
|
|
|
**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
|
|
|
|
## Quick Start
|
|
|
|
**1. Initialize beads with a separate sync branch:**
|
|
|
|
```bash
|
|
cd your-project
|
|
bd init --branch beads-metadata
|
|
```
|
|
|
|
This creates a `.beads/` directory and configures beads to commit to `beads-metadata` instead of `main`.
|
|
|
|
**2. Start the daemon with auto-commit:**
|
|
|
|
```bash
|
|
bd daemon start --auto-commit
|
|
```
|
|
|
|
The daemon will automatically commit issue changes to the `beads-metadata` branch.
|
|
|
|
**3. When ready, merge to main:**
|
|
|
|
```bash
|
|
# Check what's changed
|
|
bd sync --status
|
|
|
|
# Merge to main (creates a pull request or direct merge)
|
|
bd sync --merge
|
|
```
|
|
|
|
That's it! The complete workflow is described below.
|
|
|
|
## How It Works
|
|
|
|
### Git Worktrees
|
|
|
|
Beads uses [git worktrees](https://git-scm.com/docs/git-worktree) 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-metadata/ # Worktree (only .beads/ checked out)
|
|
│ └── .beads/
|
|
│ └── beads.jsonl
|
|
├── .beads/ # Your main copy
|
|
│ ├── beads.db
|
|
│ └── beads.jsonl
|
|
└── src/ # Your code (untouched)
|
|
```
|
|
|
|
**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)
|
|
|
|
### Automatic Sync
|
|
|
|
When you update an issue:
|
|
|
|
1. Issue is updated in `.beads/beads.db` (SQLite database)
|
|
2. Daemon exports to `.beads/beads.jsonl` (JSONL file)
|
|
3. JSONL is copied to worktree (`.git/beads-worktrees/beads-metadata/.beads/`)
|
|
4. Daemon commits the change in the worktree to `beads-metadata` branch
|
|
5. Main branch stays untouched (no commits on `main`)
|
|
|
|
## Setup
|
|
|
|
### Option 1: Initialize New Project
|
|
|
|
```bash
|
|
cd your-project
|
|
bd init --branch beads-metadata
|
|
```
|
|
|
|
This will:
|
|
- Create `.beads/` directory with database
|
|
- Set `sync.branch` config to `beads-metadata`
|
|
- Import any existing issues from git (if present)
|
|
- Prompt to install git hooks (recommended: say yes)
|
|
|
|
### Option 2: Migrate Existing Project
|
|
|
|
If you already have beads set up and want to switch to a separate branch:
|
|
|
|
```bash
|
|
# Set the sync branch
|
|
bd config set sync.branch beads-metadata
|
|
|
|
# Start the daemon (it will create the worktree automatically)
|
|
bd daemon start --auto-commit
|
|
```
|
|
|
|
### Daemon Configuration
|
|
|
|
For automatic commits to the sync branch:
|
|
|
|
```bash
|
|
# Start daemon with auto-commit
|
|
bd daemon start --auto-commit
|
|
|
|
# Or with auto-commit and auto-push
|
|
bd daemon start --auto-commit --auto-push
|
|
```
|
|
|
|
**Daemon modes:**
|
|
- `--auto-commit`: Commits to sync branch after each change
|
|
- `--auto-push`: Also pushes to remote after each commit
|
|
- Default interval: 5 seconds (check for changes every 5s)
|
|
|
|
**Recommended:** Use `--auto-commit` but not `--auto-push` if you want to review changes before pushing. Use `--auto-push` if you want fully hands-free sync.
|
|
|
|
### Environment Variables
|
|
|
|
You can also configure the sync branch via environment variable:
|
|
|
|
```bash
|
|
export BEADS_SYNC_BRANCH=beads-metadata
|
|
bd daemon start --auto-commit
|
|
```
|
|
|
|
This is useful for CI/CD or temporary overrides.
|
|
|
|
## Daily Workflow
|
|
|
|
### For AI Agents
|
|
|
|
AI agents work exactly the same way as before:
|
|
|
|
```bash
|
|
# Create issues
|
|
bd create "Implement user authentication" -t feature -p 1
|
|
|
|
# Update issues
|
|
bd update bd-a1b2 --status in_progress
|
|
|
|
# Close issues
|
|
bd close bd-a1b2 "Completed authentication"
|
|
```
|
|
|
|
All changes are automatically committed to the `beads-metadata` branch by the daemon. No changes are needed to agent workflows!
|
|
|
|
### For Humans
|
|
|
|
**Check status:**
|
|
|
|
```bash
|
|
# See what's changed on the sync branch
|
|
bd sync --status
|
|
```
|
|
|
|
This shows the diff between `beads-metadata` and `main` (or your current branch).
|
|
|
|
**Manual commit (if not using daemon):**
|
|
|
|
```bash
|
|
bd sync --flush-only # Export to JSONL and commit to sync branch
|
|
```
|
|
|
|
**Pull changes from remote:**
|
|
|
|
```bash
|
|
# Pull updates from other collaborators
|
|
bd sync --no-push
|
|
```
|
|
|
|
This pulls changes from the remote sync branch and imports them to your local database.
|
|
|
|
## Merging Changes
|
|
|
|
### Option 1: Via Pull Request (Recommended)
|
|
|
|
For protected branches with required reviews:
|
|
|
|
```bash
|
|
# 1. Push your sync branch
|
|
git push origin beads-metadata
|
|
|
|
# 2. Create PR on GitHub/GitLab/etc.
|
|
# - Base: main
|
|
# - Compare: beads-metadata
|
|
|
|
# 3. After PR is merged, update your local main
|
|
git checkout main
|
|
git pull
|
|
bd import # Import the merged changes
|
|
```
|
|
|
|
### Option 2: Direct Merge (If Allowed)
|
|
|
|
If you have push access to `main`:
|
|
|
|
```bash
|
|
# Check what will be merged
|
|
bd sync --merge --dry-run
|
|
|
|
# Merge sync branch to main
|
|
bd sync --merge
|
|
|
|
# This will:
|
|
# - Switch to main branch
|
|
# - Merge beads-metadata with --no-ff (creates merge commit)
|
|
# - Push to remote
|
|
# - Import merged changes to database
|
|
```
|
|
|
|
**Safety 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-ff` for clear history
|
|
|
|
### Merge Conflicts
|
|
|
|
If you encounter conflicts during merge:
|
|
|
|
```bash
|
|
# bd sync --merge will detect conflicts and show:
|
|
Error: Merge conflicts detected
|
|
Conflicting files:
|
|
.beads/beads.jsonl
|
|
|
|
To resolve:
|
|
1. Fix conflicts in .beads/beads.jsonl
|
|
2. git add .beads/beads.jsonl
|
|
3. git commit
|
|
4. bd import # Reimport to sync database
|
|
```
|
|
|
|
**Resolving JSONL conflicts:**
|
|
|
|
JSONL files are append-only and line-based, so conflicts are rare. When they occur:
|
|
|
|
1. Open `.beads/beads.jsonl` and look for conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
|
|
2. Both versions are usually valid - keep both lines
|
|
3. Remove the conflict markers
|
|
4. Save and commit
|
|
|
|
Example conflict resolution:
|
|
|
|
```jsonl
|
|
<<<<<<< HEAD
|
|
{"id":"bd-a1b2","title":"Feature A","status":"closed","updated_at":"2025-11-02T10:00:00Z"}
|
|
=======
|
|
{"id":"bd-a1b2","title":"Feature A","status":"in_progress","updated_at":"2025-11-02T09:00:00Z"}
|
|
>>>>>>> beads-metadata
|
|
```
|
|
|
|
**Resolution:** Keep the line with the newer `updated_at`:
|
|
|
|
```jsonl
|
|
{"id":"bd-a1b2","title":"Feature A","status":"closed","updated_at":"2025-11-02T10:00:00Z"}
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git add .beads/beads.jsonl
|
|
git commit -m "Resolve beads.jsonl merge conflict"
|
|
bd import # Import to database (will use latest timestamp)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### "fatal: refusing to merge unrelated histories"
|
|
|
|
This happens if you created the sync branch independently. Merge with `--allow-unrelated-histories`:
|
|
|
|
```bash
|
|
git merge beads-metadata --allow-unrelated-histories --no-ff
|
|
```
|
|
|
|
Or use `bd sync --merge` which handles this automatically.
|
|
|
|
### "worktree already exists"
|
|
|
|
If the worktree is corrupted or in a bad state:
|
|
|
|
```bash
|
|
# Remove the worktree
|
|
rm -rf .git/beads-worktrees/beads-metadata
|
|
|
|
# Prune stale worktree entries
|
|
git worktree prune
|
|
|
|
# Restart daemon (it will recreate the worktree)
|
|
bd daemon restart
|
|
```
|
|
|
|
### "branch 'beads-metadata' not found"
|
|
|
|
The sync branch doesn't exist yet. The daemon will create it on the first commit. If you want to create it manually:
|
|
|
|
```bash
|
|
git checkout -b beads-metadata
|
|
git checkout main # Switch back
|
|
```
|
|
|
|
Or just let the daemon create it automatically.
|
|
|
|
### "Cannot push to protected branch"
|
|
|
|
If the sync branch itself is protected:
|
|
|
|
1. **Option 1:** Unprotect the sync branch (it's metadata, doesn't need protection)
|
|
2. **Option 2:** Use `--auto-commit` without `--auto-push`, and push manually when ready
|
|
3. **Option 3:** Use a different branch name that's not protected
|
|
|
|
### Daemon won't start
|
|
|
|
Check daemon status and logs:
|
|
|
|
```bash
|
|
# Check status
|
|
bd daemon status
|
|
|
|
# View logs
|
|
tail -f ~/.beads/daemon.log
|
|
|
|
# Restart daemon
|
|
bd daemon restart
|
|
```
|
|
|
|
Common issues:
|
|
- Port already in use: Another daemon is running
|
|
- Permission denied: Check `.beads/` directory permissions
|
|
- Git errors: Ensure git is installed and repository is initialized
|
|
|
|
### Changes not syncing between clones
|
|
|
|
Ensure all clones are configured the same way:
|
|
|
|
```bash
|
|
# On each clone, verify:
|
|
bd config get sync.branch # Should be the same (e.g., beads-metadata)
|
|
|
|
# Pull latest changes
|
|
bd sync --no-push
|
|
|
|
# Check daemon is running
|
|
bd daemon status
|
|
```
|
|
|
|
## FAQ
|
|
|
|
### Do I need to configure anything on GitHub/GitLab?
|
|
|
|
No! This is a pure git solution that works on any platform. Just protect your `main` branch as usual.
|
|
|
|
### Can I use a different branch name?
|
|
|
|
Yes! Use any branch name you want:
|
|
|
|
```bash
|
|
bd init --branch my-custom-branch
|
|
# or
|
|
bd config set sync.branch my-custom-branch
|
|
```
|
|
|
|
### Can I change the branch name later?
|
|
|
|
Yes:
|
|
|
|
```bash
|
|
bd config set sync.branch new-branch-name
|
|
bd daemon restart
|
|
```
|
|
|
|
The old worktree will remain (no harm), and a new worktree will be created for the new branch.
|
|
|
|
### What if I want to go back to committing to main?
|
|
|
|
Unset the sync branch config:
|
|
|
|
```bash
|
|
bd config set sync.branch ""
|
|
bd daemon restart
|
|
```
|
|
|
|
Beads will go back to committing directly to your current branch.
|
|
|
|
### Does this work with multiple collaborators?
|
|
|
|
Yes! Each collaborator configures their own sync branch:
|
|
|
|
```bash
|
|
# All collaborators use the same branch
|
|
bd config set sync.branch beads-metadata
|
|
```
|
|
|
|
Everyone's changes sync via the `beads-metadata` branch. Periodically merge to `main` via PR.
|
|
|
|
### How often should I merge to main?
|
|
|
|
This depends on your workflow:
|
|
|
|
- **Daily:** If you want issue history in `main` frequently
|
|
- **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.
|
|
|
|
### Can I review changes before merging?
|
|
|
|
Yes! Use `bd sync --status` to see what's changed:
|
|
|
|
```bash
|
|
bd sync --status
|
|
# Shows diff between beads-metadata and main
|
|
```
|
|
|
|
Or create a pull request and review on GitHub/GitLab.
|
|
|
|
### What about disk space?
|
|
|
|
Worktrees are very lightweight:
|
|
- Sparse checkout means only `.beads/` is checked out
|
|
- Typically < 1 MB for the worktree
|
|
- Shared git history (no duplication)
|
|
|
|
### Can I delete the worktree?
|
|
|
|
Yes, but the daemon will recreate it. If you want to clean up permanently:
|
|
|
|
```bash
|
|
# Stop daemon
|
|
bd daemon stop
|
|
|
|
# Remove worktree
|
|
git worktree remove .git/beads-worktrees/beads-metadata
|
|
|
|
# Unset sync branch
|
|
bd config set sync.branch ""
|
|
```
|
|
|
|
### Does this work with `bd sync`?
|
|
|
|
Yes! `bd sync` works normally and includes special commands for the merge workflow:
|
|
|
|
- `bd sync --status` - Show diff between branches
|
|
- `bd sync --merge` - Merge sync branch to main
|
|
- `bd sync --merge --dry-run` - Preview merge
|
|
|
|
### Can AI agents merge automatically?
|
|
|
|
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:
|
|
|
|
```bash
|
|
# WARNING: This bypasses branch protection!
|
|
bd daemon start --auto-commit --auto-push
|
|
bd sync --merge # Run periodically (e.g., via cron)
|
|
```
|
|
|
|
### What if I forget to merge for a long time?
|
|
|
|
No problem! The sync branch accumulates all changes. When you eventually merge:
|
|
|
|
```bash
|
|
bd sync --merge
|
|
```
|
|
|
|
All accumulated changes will be merged at once. Git history will show the full timeline.
|
|
|
|
### Can I use this with GitHub Actions or CI/CD?
|
|
|
|
Yes! Example GitHub Actions workflow:
|
|
|
|
```yaml
|
|
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-metadata
|
|
bd sync --no-push
|
|
|
|
- name: Merge to main (if changes)
|
|
run: |
|
|
if bd sync --status | grep -q 'ahead'; then
|
|
bd sync --merge
|
|
git push origin main
|
|
fi
|
|
```
|
|
|
|
**Note:** Make sure the GitHub Action has write permissions to push to `main`.
|
|
|
|
## Platform-Specific Notes
|
|
|
|
### GitHub
|
|
|
|
Protected branch settings:
|
|
1. Go to Settings → Branches → Add rule
|
|
2. Branch name pattern: `main`
|
|
3. Check "Require pull request before merging"
|
|
4. Save
|
|
|
|
Create sync branch PR:
|
|
```bash
|
|
git push origin beads-metadata
|
|
gh pr create --base main --head beads-metadata --title "Update beads metadata"
|
|
```
|
|
|
|
### GitLab
|
|
|
|
Protected branch settings:
|
|
1. Settings → Repository → Protected Branches
|
|
2. Branch: `main`
|
|
3. Allowed to merge: Maintainers
|
|
4. Allowed to push: No one
|
|
|
|
Create sync branch MR:
|
|
```bash
|
|
git push origin beads-metadata
|
|
glab mr create --source-branch beads-metadata --target-branch main
|
|
```
|
|
|
|
### Bitbucket
|
|
|
|
Protected branch settings:
|
|
1. Repository settings → Branch permissions
|
|
2. Branch: `main`
|
|
3. Check "Prevent direct pushes"
|
|
|
|
Create sync branch PR:
|
|
```bash
|
|
git push origin beads-metadata
|
|
# Create PR via Bitbucket web UI
|
|
```
|
|
|
|
## Advanced Topics
|
|
|
|
### Multiple Sync Branches
|
|
|
|
You can use different sync branches for different purposes:
|
|
|
|
```bash
|
|
# Development branch
|
|
bd config set sync.branch beads-dev
|
|
|
|
# Production branch
|
|
bd config set sync.branch beads-prod
|
|
```
|
|
|
|
Switch between them as needed.
|
|
|
|
### Syncing with Upstream
|
|
|
|
If you're working on a fork:
|
|
|
|
```bash
|
|
# Add upstream
|
|
git remote add upstream https://github.com/original/repo.git
|
|
|
|
# Fetch upstream changes
|
|
git fetch upstream
|
|
|
|
# Merge upstream beads-metadata to yours
|
|
git checkout beads-metadata
|
|
git merge upstream/beads-metadata
|
|
bd import # Import merged changes
|
|
```
|
|
|
|
### Custom Worktree Location
|
|
|
|
By 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).
|
|
|
|
## Migration Guide
|
|
|
|
### From Direct Commits to Sync Branch
|
|
|
|
If you have an existing beads setup committing to `main`:
|
|
|
|
1. **Set sync branch:**
|
|
```bash
|
|
bd config set sync.branch beads-metadata
|
|
```
|
|
|
|
2. **Restart daemon:**
|
|
```bash
|
|
bd daemon restart
|
|
```
|
|
|
|
3. **Verify:**
|
|
```bash
|
|
bd config get sync.branch # Should show: beads-metadata
|
|
```
|
|
|
|
Future commits will go to `beads-metadata`. Historical commits on `main` are preserved.
|
|
|
|
### From Sync Branch to Direct Commits
|
|
|
|
If you want to stop using a sync branch:
|
|
|
|
1. **Unset sync branch:**
|
|
```bash
|
|
bd config set sync.branch ""
|
|
```
|
|
|
|
2. **Restart daemon:**
|
|
```bash
|
|
bd daemon restart
|
|
```
|
|
|
|
Future commits will go to your current branch (e.g., `main`).
|
|
|
|
---
|
|
|
|
**Need help?** Open an issue at https://github.com/steveyegge/beads/issues
|