Fix: Implement proper branch lifecycle management
Resolved 💬 4 comments Opened Nov 5, 2025 by sl-factory[bot] Closed Jan 9, 2026
Summary
Implement proper branch lifecycle management: create unique branches per ticket, cleanup after merge, ensure clean state between tickets.
Problem (Bug #6 from #167)
Ticket #1 created feature/ticket-1-project-structure, PR #17 merged.
Ticket #2 started without creating new branch, continued working on feature/ticket-1-project-structure, created PR #18 on the same branch.
Impact:
- Branch pollution (multiple PRs on same branch)
- Merge conflicts between tickets
- Hard to track which commit belongs to which ticket
- Can't work on tickets in parallel
Root Cause
Two problems:
- Orchestrator doesn't clean up after PR merge
- After merging PR, repository stays on feature branch
- No checkout to main
- No branch deletion
- Developer doesn't create new branch per ticket
- Developer starts working without checking current branch
- Continues on whatever branch is checked out
- No validation that branch is unique to this ticket
Solution
Fix 1: Orchestrator branch cleanup
Location: src/factory/orchestration/ticket_executor.py after merge_pr_and_close_ticket()
def execute_ticket(self, ticket_id: int, sprint: Sprint) -> tuple[TicketExecutionResult, Sprint]:
# ... existing code ...
if review_outcome == "APPROVED":
# Merge PR and close ticket
self.github.merge_pr_and_close_ticket(
ticket_id,
pr_number,
metrics=metrics,
)
# NEW: Clean up branch after merge
try:
# Get branch name from PR
pr = self.github.get_pull_request(pr_number)
branch_name = pr.head.ref
# Switch back to main and pull latest
subprocess.run(
["git", "checkout", "main"],
cwd=self.project_path,
check=True,
capture_output=True,
)
subprocess.run(
["git", "pull"],
cwd=self.project_path,
check=True,
capture_output=True,
)
# Delete feature branch locally
subprocess.run(
["git", "branch", "-d", branch_name],
cwd=self.project_path,
check=False, # Don't fail if branch doesn't exist
capture_output=True,
)
logger.info(f"Cleaned up branch {branch_name}")
except Exception as e:
logger.warning(f"Branch cleanup failed: {e}")
# Don't fail ticket execution for cleanup issues
Fix 2: Developer must create unique branch
Location: src/factory/prompts/developer.md
Add to Developer instructions:
## Branch Management (CRITICAL)
**ALWAYS create a new branch at the start of each ticket:**
1. Check current branch: Use `run_command("git branch --show-current")`
2. If not on 'main', checkout main first: `run_command("git checkout main && git pull")`
3. Create unique branch: `create_branch(f"feature/ticket-{ticket_id}-{slug}")`
- Use ticket ID in branch name
- Use short slug from ticket title
- Example: `feature/ticket-42-add-authentication`
**NEVER reuse existing feature branches.**
If you find yourself on a feature branch from another ticket, STOP and checkout main first.
Location: src/factory/agents/developer.py in implement_ticket()
Add validation:
def implement_ticket(self, project_path: str, ticket_id: int, stream: bool = True) -> AgentResponse:
# Check current branch before starting
result = subprocess.run(
["git", "branch", "--show-current"],
cwd=project_path,
capture_output=True,
text=True,
)
current_branch = result.stdout.strip()
# Warn if not on main (agent should switch)
if current_branch != "main":
logger.warning(
f"Starting ticket #{ticket_id} on branch '{current_branch}' (expected 'main'). "
f"Developer should checkout main and create new branch."
)
# ... rest of implementation ...
Test Plan
- Unit test for branch cleanup:
- Mock successful PR merge
- Verify
git checkout maincalled - Verify
git pullcalled - Verify
git branch -d <branch>called
- E2E test:
- Execute two tickets sequentially
- After Ticket #1 merge, verify on 'main' branch
- Verify Ticket #2 creates NEW branch (not reusing Ticket #1's)
- Verify both PRs on different branches
- Validation test:
- Start ticket while on feature branch
- Verify warning logged
- Verify Developer switches to main and creates new branch
Acceptance Criteria
- [ ] Orchestrator cleans up branch after PR merge
- [ ] Orchestrator switches to main and pulls latest
- [ ] Developer prompt includes branch management instructions
- [ ] Developer checks current branch before starting
- [ ] Warning logged if starting on wrong branch
- [ ] Unit tests for branch cleanup
- [ ] E2E test: two tickets use different branches
- [ ] Documentation: Branch lifecycle
Related Issues
- Fixes Bug #6 in #167
- Prerequisite for parallel ticket execution (#173)
Priority
High - Prevents branch pollution and merge conflicts.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗