| name | Stack Sync |
| description | Manages and syncs stacked feature branches automatically. Use when the user mentions branch stacking, stacked branches, dependent branches, or asks to sync a branch stack, rebase a stack, or update dependent branches. |
Stack Sync
This skill manages stacked feature branches - a workflow where multiple branches are built on top of each other (e.g., main -> feature-1 -> feature-2 -> feature-3). When any branch in the stack is updated, all dependent branches are automatically rebased to stay in sync.
Quick Start
When the user asks about branch stacking:
- Detect the current branch stack structure
- Visualize the stack dependencies
- Sync branches in the correct order
- Handle conflicts at each level
- Update remote branches safely
Core Concepts
What is branch stacking?
Branch stacking is when you create multiple feature branches that depend on each other:
main (production code)
└─> feature/auth-foundation (PR #1)
└─> feature/auth-ui (PR #2)
└─> feature/auth-tests (PR #3)
Benefits:
- Break large features into reviewable PRs
- Get early feedback on foundation work
- Work on dependent features in parallel
- Merge incrementally without blocking
Challenges:
- When feature/auth-foundation changes, feature/auth-ui needs rebasing
- When feature/auth-ui rebases, feature/auth-tests needs rebasing
- Changes propagate up the stack
Instructions
Step 1: Detect the branch stack
Determine the current branch and its position in the stack:
# Get current branch
CURRENT_BRANCH=$(git branch --show-current)
# Get the parent branch (what this branch is based on)
# This checks the merge-base with various candidates
git merge-base $CURRENT_BRANCH main
git merge-base $CURRENT_BRANCH origin/main
# List all local branches
git branch --format="%(refname:short)"
# For each branch, check what it's based on
# by comparing merge bases
Detection strategy:
For each local branch, determine its parent by:
- Check if branch name follows a pattern (e.g., feature/auth-1, feature/auth-2)
- Find the nearest branch that this branch diverges from
- Use merge-base to find common ancestors
- Build a dependency tree
Step 2: Visualize the stack
Show the user the current stack structure:
# Show branch relationships with graph
git log --graph --oneline --all --decorate --simplify-by-decoration
# Show commits per branch
for branch in $(git branch --format="%(refname:short)"); do
echo "=== $branch ==="
git log main..$branch --oneline --no-merges | head -5
done
Present in clear format:
Branch Stack:
main (base)
├─> feature/auth-foundation (3 commits)
│ └─> feature/auth-ui (2 commits)
│ └─> feature/auth-tests (4 commits) ← YOU ARE HERE
└─> feature/logging (5 commits)
Step 3: Determine sync strategy
Ask the user what they want to do:
Common operations:
Sync current branch with its parent
- Rebase current branch on top of its parent
- Update dependents of current branch
Sync entire stack with main
- Update bottom branch from main
- Propagate changes up the entire stack
Sync after a branch was updated
- When a parent branch changes, sync all dependents
Restack after merge
- When a branch is merged to main, update the stack
Step 4: Execute the sync
Option A: Sync current branch with parent
# Identify parent branch
PARENT_BRANCH="feature/auth-ui" # detected in step 1
CURRENT_BRANCH=$(git branch --show-current)
# Ensure clean working directory
if [[ -n $(git status -s) ]]; then
echo "Working directory has uncommitted changes"
# Ask user to commit or stash
exit 1
fi
# Fetch latest
git fetch origin
# Rebase current on parent
git rebase $PARENT_BRANCH
# If conflicts occur, handle them (see conflict handling section)
# Update remote if branch was previously pushed
git push --force-with-lease
Option B: Sync entire stack from main
# Define the stack order (from bottom to top)
STACK_BRANCHES=("feature/auth-foundation" "feature/auth-ui" "feature/auth-tests")
# Start from bottom of stack
git checkout ${STACK_BRANCHES[0]}
# Update from main
git fetch origin
git rebase origin/main
# If successful, push
git push --force-with-lease
# Move up the stack
for i in "${!STACK_BRANCHES[@]}"; do
if [ $i -eq 0 ]; then continue; fi
CURRENT="${STACK_BRANCHES[$i]}"
PARENT="${STACK_BRANCHES[$i-1]}"
echo "Syncing $CURRENT on top of $PARENT"
git checkout "$CURRENT"
git rebase "$PARENT"
if [ $? -ne 0 ]; then
echo "Conflict in $CURRENT - needs manual resolution"
# Provide conflict resolution guidance
exit 1
fi
git push --force-with-lease
done
echo "Stack sync complete!"
Option C: Sync dependents of a branch
When a branch in the middle of the stack changes:
UPDATED_BRANCH="feature/auth-ui"
# Find all branches that depend on this branch
DEPENDENTS=()
for branch in $(git branch --format="%(refname:short)"); do
# Check if branch is based on UPDATED_BRANCH
MERGE_BASE=$(git merge-base $branch $UPDATED_BRANCH)
UPDATED_COMMIT=$(git rev-parse $UPDATED_BRANCH)
if [ "$MERGE_BASE" = "$UPDATED_COMMIT" ] && [ "$branch" != "$UPDATED_BRANCH" ]; then
DEPENDENTS+=("$branch")
fi
done
# Rebase each dependent
for dependent in "${DEPENDENTS[@]}"; do
echo "Rebasing $dependent on $UPDATED_BRANCH"
git checkout "$dependent"
git rebase "$UPDATED_BRANCH"
git push --force-with-lease
done
Step 5: Handle conflicts
When conflicts occur during rebase:
# Show conflicted files
git status
# Show the conflict in detail
git diff
Provide guidance:
"Conflict detected in branch [branch-name] while rebasing on [parent-branch].
Conflicted files:
- [file1]
- [file2]
Options:
Resolve manually:
- Edit the conflicted files
- Run: git add [file]
- Run: git rebase --continue
- I'll continue syncing remaining branches
Abort this branch:
- Run: git rebase --abort
- I'll skip this branch and continue with others
Abort entire sync:
- Run: git rebase --abort
- We'll stop the sync process
Which would you like to do?"
Step 6: Verify the sync
After syncing, verify the stack is healthy:
# For each branch in stack, show status
for branch in "${STACK_BRANCHES[@]}"; do
git checkout "$branch"
echo "=== $branch ==="
# Show if ahead/behind remote
git status -sb
# Show recent commits
git log --oneline -3
# Show if needs force push
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u} 2>/dev/null)
if [ "$LOCAL" != "$REMOTE" ]; then
echo "⚠️ Branch diverged from remote - needs force push"
fi
done
Advanced Features
Auto-detect stack from branch names
If branches follow naming conventions:
# Pattern: feature/name-1, feature/name-2, feature/name-3
# Or: username/feature-part1, username/feature-part2
# Extract base name and sort by suffix
git branch | grep 'feature/auth' | sort
Store stack metadata
Create a .stack file to explicitly define relationships:
# .stack file in repository
stacks:
auth-stack:
base: main
branches:
- feature/auth-foundation
- feature/auth-ui
- feature/auth-tests
logging-stack:
base: main
branches:
- feature/logging-core
- feature/logging-ui
Read and use this file:
# Check if .stack file exists
if [ -f .stack ]; then
# Parse YAML and use defined stacks
# This requires yq or python
cat .stack
fi
Interactive stack management
Provide interactive menu:
Current Stack:
1. feature/auth-foundation (needs sync with main)
2. feature/auth-ui (synced)
3. feature/auth-tests (synced) ← current
Options:
[a] Sync entire stack from main
[b] Sync current branch with parent
[c] Sync dependents of current branch
[d] Show stack status
[e] Restack after merge
[q] Quit
Choose an option:
Handle merged branches
When a branch is merged to main:
# Detect if a branch in stack was merged
BOTTOM_BRANCH="feature/auth-foundation"
# Check if commits from bottom branch are in main
git merge-base --is-ancestor $BOTTOM_BRANCH origin/main
if [ $? -eq 0 ]; then
echo "$BOTTOM_BRANCH has been merged to main!"
# Remove from stack
# Rebase next branch directly on main
NEXT_BRANCH="feature/auth-ui"
git checkout $NEXT_BRANCH
git rebase origin/main
# Delete merged branch
git branch -d $BOTTOM_BRANCH
fi
Common Workflows
Workflow 1: Starting a new stack
# Create foundation branch
git checkout main
git checkout -b feature/auth-foundation
# ... make changes ...
git commit -m "Add auth foundation"
# Create dependent branch
git checkout -b feature/auth-ui
# ... make changes ...
git commit -m "Add auth UI"
# Create another dependent
git checkout -b feature/auth-tests
# ... make changes ...
git commit -m "Add auth tests"
# Push all branches
git push -u origin feature/auth-foundation
git push -u origin feature/auth-ui
git push -u origin feature/auth-tests
Workflow 2: Main was updated
# Main has new commits, need to update entire stack
git fetch origin
# Use Stack Sync skill
# It will:
# 1. Rebase feature/auth-foundation on origin/main
# 2. Rebase feature/auth-ui on feature/auth-foundation
# 3. Rebase feature/auth-tests on feature/auth-ui
# 4. Force push all branches
Workflow 3: Bottom branch got feedback
# Made changes to feature/auth-foundation based on PR review
git checkout feature/auth-foundation
# ... make changes ...
git commit -m "Address PR feedback"
# Use Stack Sync skill to update dependents
# It will:
# 1. Rebase feature/auth-ui on updated feature/auth-foundation
# 2. Rebase feature/auth-tests on updated feature/auth-ui
# 3. Force push dependent branches
Workflow 4: Bottom branch merged
# feature/auth-foundation merged to main
git checkout main
git pull
# Use Stack Sync skill for restack
# It will:
# 1. Detect feature/auth-foundation is in main
# 2. Rebase feature/auth-ui on main (instead of merged branch)
# 3. Rebase feature/auth-tests on feature/auth-ui
# 4. Delete local feature/auth-foundation
# 5. Update stack structure
Safety Measures
Always use --force-with-lease
Never use git push --force. Always use:
git push --force-with-lease
This prevents overwriting changes pushed by others.
Verify before force push
Before force pushing:
# Show what will be pushed
git log origin/$BRANCH..$BRANCH --oneline
# Confirm with user
echo "About to force push $BRANCH. This will overwrite remote with:"
git log origin/$BRANCH..$BRANCH --oneline
echo "Continue? (y/n)"
Create backup branches
Before major sync operations:
# Create backup branches
for branch in "${STACK_BRANCHES[@]}"; do
git branch backup/$branch $branch
done
echo "Created backup branches: backup/feature/*"
echo "If something goes wrong: git checkout backup/feature/branch-name"
Check remote state
Before rebasing:
# Fetch latest
git fetch origin
# Check if remote has new commits
LOCAL=$(git rev-parse $BRANCH)
REMOTE=$(git rev-parse origin/$BRANCH)
if [ "$LOCAL" != "$REMOTE" ]; then
echo "⚠️ Remote has changes. Pull first or proceed with caution."
fi
Troubleshooting
Problem: Lost track of stack structure
Solution:
# Rebuild stack understanding
git log --graph --oneline --all
# Check each branch's divergence point
for branch in $(git branch --format="%(refname:short)"); do
echo "$branch:"
git merge-base --fork-point main $branch
done
Problem: Conflict in middle of stack
Solution:
- Resolve the conflict in that branch
- Continue rebasing that branch:
git rebase --continue - Then sync all branches above it in the stack
Problem: Force push rejected
Solution:
# Check why
git fetch origin
git log HEAD..origin/$BRANCH
# If remote has commits you don't have, you'll lose them
# Pull and re-rebase, or coordinate with team
Problem: Branch based on wrong parent
Solution:
# Rebase onto correct parent
git rebase --onto correct-parent wrong-parent current-branch
# Example: branch is on feature-2 but should be on feature-1
git rebase --onto feature-1 feature-2 current-branch
Best Practices
- Keep stacks small - 3-4 branches max per stack
- Sync regularly - Before starting each day's work
- One stack at a time - Don't interleave multiple stacks
- Clear naming - Use consistent prefixes (feature/auth-1, feature/auth-2)
- Document dependencies - Use .stack file or branch descriptions
- Communicate with team - Let them know about your stacks
- Fast-forward when possible - Merge bottom branches quickly
- Backup before major syncs - Create backup/* branches
Integration with other tools
gh CLI (GitHub CLI)
# Create PRs for stack
gh pr create --base main --head feature/auth-foundation --title "Auth Foundation"
gh pr create --base feature/auth-foundation --head feature/auth-ui --title "Auth UI"
gh pr create --base feature/auth-ui --head feature/auth-tests --title "Auth Tests"
# View stack PRs
gh pr list --author @me
git-stack / git-branchstack tools
If using external tools:
# git-stack (if installed)
git stack sync
# graphite (if installed)
gt stack sync
Output Format
When running stack sync, provide clear progress:
🔍 Detecting branch stack...
Found stack:
main
└─> feature/auth-foundation (3 commits, last: 2 hours ago)
└─> feature/auth-ui (2 commits, last: 1 hour ago)
└─> feature/auth-tests (4 commits, last: 30 min ago) ← CURRENT
📥 Fetching latest from origin...
🔄 Syncing stack from bottom to top:
[1/3] feature/auth-foundation on origin/main
✓ Rebased successfully (3 commits)
✓ Pushed to origin (forced)
[2/3] feature/auth-ui on feature/auth-foundation
✓ Rebased successfully (2 commits)
✓ Pushed to origin (forced)
[3/3] feature/auth-tests on feature/auth-ui
✓ Rebased successfully (4 commits)
✓ Pushed to origin (forced)
✅ Stack sync complete!
Summary:
- 3 branches updated
- 0 conflicts
- All branches pushed to remote
- Stack is healthy
Current status:
feature/auth-foundation: ✓ synced with main
feature/auth-ui: ✓ synced with feature/auth-foundation
feature/auth-tests: ✓ synced with feature/auth-ui ← YOU ARE HERE
Quick Reference
Common commands the user might request:
- "Sync my branch stack" → Detect and sync entire stack
- "Update stack with main" → Rebase bottom branch on main, propagate up
- "Rebase dependents" → Update all branches that depend on current
- "Show my stack" → Visualize the branch stack structure
- "Fix my stack" → Detect issues and repair the stack
- "Restack after merge" → Update stack after bottom branch merged
Important Notes
- Stack syncing requires force pushing - always warn the user
- Conflicts are common - be prepared to handle them at each level
- Keep the user informed of progress at each step
- Always verify working directory is clean before starting
- Create backups before complex operations
- Document the stack structure for team awareness