Add collision resolution with automatic ID remapping

Implements --resolve-collisions flag for import command to safely handle ID
collisions during branch merges. When enabled, colliding issues are remapped
to new IDs and all text references and dependencies are automatically updated.

Also adds comprehensive tests, branch-merge example, and documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-10-12 17:13:09 -07:00
parent 42e3bb315d
commit 183ded4096
11 changed files with 2086 additions and 34 deletions

View File

@@ -0,0 +1,176 @@
# Branch Merge Workflow with Collision Resolution
This example demonstrates how to handle ID collisions when merging branches that have diverged and created issues with the same IDs.
## The Problem
When two branches work independently and both create issues, they'll often generate overlapping IDs:
```
main: bd-1, bd-2, bd-3, bd-4, bd-5
feature: bd-1, bd-2, bd-3, bd-6, bd-7 (diverged from main earlier)
```
When you try to merge `feature` into `main`, you'll have ID collisions for bd-1 through bd-3 (if the content differs).
## The Solution
bd provides automatic collision resolution that:
1. Detects collisions (same ID, different content)
2. Renumbers the incoming colliding issues
3. Updates ALL text references and dependencies automatically
## Demo Workflow
### 1. Setup - Two Diverged Branches
```bash
# Start on main branch
git checkout main
bd create "Feature A" -t feature -p 1
bd create "Bug fix B" -t bug -p 0
bd create "Task C" -t task -p 2
bd export -o .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Add main branch issues"
# Create feature branch from an earlier commit
git checkout -b feature-branch HEAD~5
# On feature branch, create overlapping issues
bd create "Different feature A" -t feature -p 2
bd create "Different bug B" -t bug -p 1
bd create "Feature D" -t feature -p 1
bd export -o .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Add feature branch issues"
```
At this point:
- `main` has: bd-1 (Feature A), bd-2 (Bug fix B), bd-3 (Task C)
- `feature-branch` has: bd-1 (Different feature A), bd-2 (Different bug B), bd-3 (Feature D)
The bd-1 and bd-2 on each branch have different content = collisions!
### 2. Merge and Detect Collisions
```bash
# Merge feature branch into main
git checkout main
git merge feature-branch
# Git will show merge conflict in .beads/issues.jsonl
# Manually resolve the conflict by keeping both versions
# (or use a merge tool)
# After resolving the git conflict, check for ID collisions
bd import -i .beads/issues.jsonl --dry-run
```
Output shows:
```
=== Collision Detection Report ===
Exact matches (idempotent): 0
New issues: 1
COLLISIONS DETECTED: 2
Colliding issues:
bd-1: Different feature A
Conflicting fields: [title, priority]
bd-2: Different bug B
Conflicting fields: [title, priority]
```
### 3. Resolve Collisions Automatically
```bash
# Let bd resolve the collisions
bd import -i .beads/issues.jsonl --resolve-collisions
```
Output shows:
```
Resolving collisions...
=== Remapping Report ===
Issues remapped: 2
Remappings (sorted by reference count):
bd-1 → bd-4 (refs: 0)
bd-2 → bd-5 (refs: 0)
All text and dependency references have been updated.
Import complete: 2 created, 0 updated, 1 dependencies added, 2 issues remapped
```
Result:
- `main` keeps: bd-1 (Feature A), bd-2 (Bug fix B), bd-3 (Task C)
- `feature-branch` issues become: bd-4 (Different feature A), bd-5 (Different bug B), bd-3 (Feature D)
### 4. Export and Commit
```bash
# Export the resolved state back to JSONL
bd export -o .beads/issues.jsonl
# Commit the merge
git add .beads/issues.jsonl
git commit -m "Merge feature-branch with collision resolution"
```
## Advanced: Cross-References
If your issues reference each other in text or dependencies, bd updates those automatically:
```bash
# On feature branch, create issues with references
bd create "Feature X" -d "Implements the core logic" -t feature -p 1
# Assume this becomes bd-10
bd create "Test for X" -d "Tests bd-10 functionality" -t task -p 2
# This references bd-10 in the description
bd dep add bd-11 bd-10 --type blocks
# Dependencies are created
# After merge with collision resolution
bd import -i .beads/issues.jsonl --resolve-collisions
# If bd-10 collided and was remapped to bd-15:
# - bd-11's description becomes: "Tests bd-15 functionality"
# - Dependency becomes: bd-11 → bd-15
```
## When to Use This
1. **Feature branches** - Long-lived branches that create issues independently
2. **Parallel development** - Multiple developers working on separate branches
3. **Stale branches** - Old branches that need to be merged but have ID conflicts
4. **Distributed teams** - Teams that work offline and sync via git
## Safety Notes
- `--resolve-collisions` preserves your existing database (current branch's issues never change IDs)
- Only the incoming colliding issues get new IDs
- Use `--dry-run` first to preview what will happen
- All text references use word-boundary matching (bd-10 won't match bd-100)
- The collision resolution is deterministic (same input = same output)
## Alternative: Manual Resolution
If you prefer manual control:
1. Don't use `--resolve-collisions`
2. Manually edit the JSONL file before import
3. Rename colliding IDs to unique values
4. Manually update any cross-references
5. Import normally
This gives you complete control but is more error-prone and time-consuming.
## See Also
- [Git Hooks Example](../git-hooks/) - Automate export/import with git hooks
- [README.md](../../README.md) - Full collision resolution documentation
- [TEXT_FORMATS.md](../../TEXT_FORMATS.md) - JSONL merge strategies

145
examples/branch-merge/demo.sh Executable file
View File

@@ -0,0 +1,145 @@
#!/bin/bash
# Demo script for branch merge collision resolution workflow
# This script simulates a branch merge with ID collisions
set -e # Exit on error
echo "=== Branch Merge Collision Resolution Demo ==="
echo ""
# Check if bd is available
if ! command -v bd &> /dev/null; then
echo "Error: bd command not found. Please install bd first."
echo "Run: go install github.com/steveyegge/beads/cmd/bd@latest"
exit 1
fi
# Create a temporary directory for the demo
DEMO_DIR=$(mktemp -d -t bd-merge-demo-XXXXXX)
echo "Demo directory: $DEMO_DIR"
cd "$DEMO_DIR"
# Initialize git repo
echo ""
echo "Step 1: Initialize git repo and bd database"
git init
git config user.name "Demo User"
git config user.email "demo@example.com"
bd init --prefix demo
# Create initial commit
echo "Initial project" > README.txt
git add README.txt .beads/
git commit -m "Initial commit"
# Create issues on main branch
echo ""
echo "Step 2: Create issues on main branch"
bd create "Implement login" -d "User authentication system" -t feature -p 1 --json
bd create "Fix memory leak" -d "Memory leak in parser" -t bug -p 0 --json
bd create "Update docs" -d "Document new API" -t task -p 2 --json
echo ""
echo "Main branch issues:"
bd list
# Export and commit
bd export -o .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Add main branch issues (bd-1, bd-2, bd-3)"
# Create feature branch from earlier point
echo ""
echo "Step 3: Create feature branch"
git checkout -b feature-branch HEAD~1
# Reimport to get clean state
bd import -i .beads/issues.jsonl
# Create overlapping issues on feature branch
echo ""
echo "Step 4: Create different issues with same IDs on feature branch"
bd create "Add dashboard" -d "Admin dashboard feature" -t feature -p 2 --json
bd create "Improve performance" -d "Optimize queries" -t task -p 1 --json
bd create "Add metrics" -d "Monitoring and metrics" -t feature -p 1 --json
echo ""
echo "Feature branch issues:"
bd list
# Export and commit
bd export -o .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Add feature branch issues (bd-1, bd-2, bd-3)"
# Merge back to main
echo ""
echo "Step 5: Merge feature branch into main"
git checkout main
# Attempt merge (will conflict)
if git merge feature-branch --no-edit; then
echo "Merge succeeded without conflicts"
else
echo "Merge conflict detected - resolving..."
# Keep both versions by accepting both sides
# In a real scenario, you'd resolve this more carefully
git checkout --ours .beads/issues.jsonl
git checkout --theirs .beads/issues.jsonl --patch || true
# For demo purposes, accept theirs
git checkout --theirs .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Merge feature-branch"
fi
# Detect collisions
echo ""
echo "Step 6: Detect ID collisions"
echo "Running: bd import -i .beads/issues.jsonl --dry-run"
echo ""
if bd import -i .beads/issues.jsonl --dry-run; then
echo "No collisions detected!"
else
echo ""
echo "Collisions detected (expected)!"
fi
# Resolve collisions
echo ""
echo "Step 7: Resolve collisions automatically"
echo "Running: bd import -i .beads/issues.jsonl --resolve-collisions"
echo ""
bd import -i .beads/issues.jsonl --resolve-collisions
# Show final state
echo ""
echo "Step 8: Final issue list after resolution"
bd list
# Show remapping details
echo ""
echo "Step 9: Show how dependencies and references are maintained"
echo "All text references like 'see bd-1' and dependencies were automatically updated!"
# Export final state
bd export -o .beads/issues.jsonl
git add .beads/issues.jsonl
git commit -m "Resolve collisions and finalize merge"
echo ""
echo "=== Demo Complete ==="
echo ""
echo "Summary:"
echo "- Created issues on main branch (bd-1, bd-2, bd-3)"
echo "- Created different issues on feature branch (also bd-1, bd-2, bd-3)"
echo "- Merged branches with Git"
echo "- Detected collisions with --dry-run"
echo "- Resolved collisions with --resolve-collisions"
echo "- Feature branch issues were renumbered to avoid conflicts"
echo ""
echo "Demo directory: $DEMO_DIR"
echo "You can explore the git history: cd $DEMO_DIR && git log --oneline"
echo ""
echo "To clean up: rm -rf $DEMO_DIR"