Skip to content

Instantly share code, notes, and snippets.

@morisono
Last active July 7, 2025 23:37
Show Gist options
  • Save morisono/21b0c66bac2cae7669921cdf7eb6379d to your computer and use it in GitHub Desktop.
Save morisono/21b0c66bac2cae7669921cdf7eb6379d to your computer and use it in GitHub Desktop.
BBManager - Yet Another Git-branch manager as single shell script

BBManager - Git Branch Manager

BBManager is an interactive branch management tool that provide a comprehensive, beautiful interface for managing Git branches using gum for terminal UI components.

Pf73k4b0.mp4

Features

  • Beautiful Interactive Interface with gum-powered terminal UI
  • Smart Branch Selection with local/remote branch toggle
  • Create New Branches following git-flow conventions
  • Merge Branches with proper target selection and safety checks
  • Delete Branches with comprehensive safety confirmations
  • Configuration Management for customizing behavior
  • Repository Status overview with rich formatting
  • Extends branch-manager.sh functionality

Installation Requirements

BBManager requires both gum to be installed. If it is not present, the script will offer to install it automatically.

For gum installation, see: https://github.com/charmbracelet/gum#installation

For learning the core, see: https://github.com/charmbracelet/gum/blob/main/examples/git-branch-manager.sh

Usage

Interactive Mode (Default)

Launch the beautiful interactive interface:

./bbmanager
# or
./bbmanager branch-select

The interface provides:

  • 🔀 Select/Switch Branch - Choose from local/remote branches with detailed info
  • 🆕 Create New Branch - Guided branch creation with type selection
  • 🔄 Merge Branch - Smart merging with target branch detection
  • 🗑️ Delete Branch - Safe deletion with confirmation prompts
  • ⚙️ Configuration - Customize settings and preferences
  • 📊 Repository Status - Comprehensive repository overview
  • ❓ Help - Interactive help and documentation

Command Line Interface

# Quick access commands
./bbmanager new               # Create new branch
./bbmanager st                # Show status
./bbmanager merge             # Merge current branch
./bbmanager delete            # Delete branch
./bbmanager conf              # Configuration

# Using gum with full command names
./bbmanager branch-create     # Create new branch
./bbmanager branch-status     # Show repository status
./bbmanager branch-merge      # Merge current branch
./bbmanager branch-delete     # Delete branch
./bbmanager branch-config     # Configuration

Options

  • --debug: Enable debug mode with detailed logging
  • --no-color: Disable colored output for compatibility
  • --config-file <FILE>: Use custom configuration file
  • --check-gum: Check if gum is installed

Interactive Mode Interface

The main interface uses a beautiful menu-driven approach:

 ┌──────────────────────────────────┐
 │                                  │
 │  BBManager - Git Branch Manager  │
 │                                  │
 └──────────────────────────────────┘

Select a branch to start or resume a git session:

Current: feature/456-test-feature
Status: ✅ Ready
Controls: ↑↓ Navigate | Enter Select | Hotkeys: N-New M-Merge D-Delete C-Config Q-Quit

Choose an action:
> 🔀 Select/Switch Branch
  🆕 Create New Branch
  🔄 Merge Branch
  🗑️ Delete Branch
  ⚙️ Configuration
  📊 Repository Status
  ❓ Help
  🚪 Exit

Navigation

  • ↑↓ Arrow Keys: Navigate menu options
  • Enter: Select highlighted option
  • ESC: Cancel current operation

Branch Selection Features

  • Local Branches: All available local branches with commit info
  • Remote Branches: Toggle to show remote branches with 🌐 prefix
  • Branch Information: Last commit, upstream status, relative time
  • Smart Checkout: Automatic local branch creation from remote branches

Status Indicators

  • Working: Operation in progress
  • Pending: Waiting for user input
  • Ready: System ready
  • Failed: Operation failed
  • 🎉 Complete: Operation successful
  • ℹ️ Information: Informational message
  • ⚠️ Attention: Warning or important notice

Branch Types Supported

BBManager supports all branch types from brancher.sh:

  • feature: New functionality (requires issue number)
  • bugfix: Non-urgent bug fixes (requires issue number)
  • hotfix: Critical fixes applied immediately (requires issue number)
  • release: Stabilize and prepare new version (requires version)
  • experiment: Spike or proof-of-concept work
  • docs: Documentation changes only
  • chore: Routine tasks (dependencies, tooling)
  • ci: CI/CD pipeline and config updates
  • refactor: Code restructuring without behavior change
  • perf: Performance optimizations
  • test: Add or improve automated tests

Configuration

BBManager stores configuration in ~/.bbmanager.conf and allows customization of:

  • Base branch mappings
  • Default branch types
  • Aliases and shortcuts
  • Color schemes

Examples

Creating a Feature Branch

./bbmanager new
# Interactive selection of branch type
# Select: feature
# Issue: 123
# Description: user authentication
# Result: feature/123-user-authentication

Interactive Branch Selection

./bbmanager
# Beautiful menu interface appears
# Use arrow keys to navigate
# Select "🔀 Select/Switch Branch"
# Choose from available branches with rich information

Quick Status Check

./bbmanager st
# Shows:
# - Git working tree status
# - Current branch information
# - Upstream tracking status
# - Recent branches with timestamps

Smart Branch Merging

./bbmanager merge
# Automatically suggests appropriate target branch
# - feature/* → develop
# - hotfix/* → main
# - release/* → main
# Provides confirmation and safety checks

Integration with Existing Workflow

BBManager seamlessly extends both branch-manager.sh and brancher.sh functionality:

  • Full git-flow support: All branch types from brancher.sh
  • Enhanced safety: Comprehensive confirmation prompts
  • Beautiful UI: Gum-powered terminal interface
  • Smart defaults: Intelligent target branch detection
  • gum integration: Powerful command-line interface with aliases

All existing brancher commands continue to work while adding the interactive layer and enhanced user experience.

Troubleshooting

gum Not Found

./bbmanager check-gum

gum Not Found

Install gum from: https://github.com/charmbracelet/gum#installation

Color Display Issues

./bbmanager --no-color

Debug Mode

./bbmanager --debug branch-status

Demo

Run the demo to see all features:

./bbmanager-demo.sh
#!/bin/bash
# BBManager Demo Script
# Demonstrates the capabilities of bbmanager.sh
echo "🎉 BBManager Demo"
echo "=================="
echo
echo "This demo will showcase the bbmanager.sh functionality:"
echo
# Get the script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "1. Checking gum installation..."
"$SCRIPT_DIR/bbmanager.sh" --check-gum
echo
echo "2. Showing repository status..."
"$SCRIPT_DIR/bbmanager.sh" status
echo
echo "3. Displaying help information..."
"$SCRIPT_DIR/bbmanager.sh" help
echo
echo "4. To run the interactive interface, use:"
echo " bbmanager.sh"
echo
echo "5. Available commands:"
echo " bbmanager.sh select # Select/switch branches"
echo " bbmanager.sh create # Create new branch"
echo " bbmanager.sh merge # Merge branches"
echo " bbmanager.sh delete # Delete branches"
echo " bbmanager.sh config # Configuration"
echo " bbmanager.sh status # Repository status"
echo " bbmanager.sh help # Show help"
echo
echo "� Demo completed! Try running the interactive mode:"
echo " cd $(pwd)"
echo " bbmanager.sh"
#!/bin/bash
# BBManager - Git Branch Manager
# An interactive branch management tool that extends branch-manager.sh functionality
# Uses gum for beautiful terminal UI and gum for CLI argument parsing
#
# @meta dotenv
# @option --config-file <FILE> Path to custom configuration file
# @flag --debug Enable debug mode
# @flag --no-color Disable colored output
# @flag --check-gum Check if gum is installed
# @arg action Choice of action [select|create|merge|delete|config|status|help]
# Integrated brancher.sh functionality - no external dependencies needed
# Configuration
readonly BB_CONFIG_FILE="${BB_CONFIG_FILE:-$HOME/.bbmanager.conf}"
readonly BB_TEMP_DIR="/tmp/bbmanager-$$"
readonly BB_LOCK_FILE="/tmp/bbmanager.lock"
# Gum configuration
readonly GIT_COLOR="#f14e32"
readonly BB_HEADER_COLOR="#0080ff"
readonly BB_SUCCESS_COLOR="#00ff80"
readonly BB_WARNING_COLOR="#ffff00"
readonly BB_ERROR_COLOR="#ff4040"
# Branch type configurations (from brancher.sh)
declare -A BRANCH_TYPES=(
["main"]="protected"
["develop"]="integration"
["feature"]="supporting"
["bugfix"]="supporting"
["hotfix"]="supporting"
["release"]="supporting"
["experiment"]="supporting"
["docs"]="supporting"
["chore"]="maintenance"
["ci"]="maintenance"
["refactor"]="maintenance"
["perf"]="maintenance"
["test"]="supporting"
)
declare -A BRANCH_DESCRIPTIONS=(
["main"]="Production-ready code; only merge commits from release/hotfix"
["develop"]="Integration branch for completed features awaiting release"
["feature"]="New functionality; 1:1 with Issue or ticket"
["bugfix"]="Non-urgent bug fixes targeting next release"
["hotfix"]="Critical fixes applied immediately to production"
["release"]="Stabilize and prepare a new version"
["experiment"]="Spike or proof-of-concept work"
["docs"]="Documentation changes only"
["chore"]="Routine tasks (dependencies, tooling)"
["ci"]="CI/CD pipeline and config updates"
["refactor"]="Code restructuring without behavior change"
["perf"]="Performance optimizations"
["test"]="Add or improve automated tests"
)
declare -A BASE_BRANCHES=(
["feature"]="develop"
["bugfix"]="develop"
["hotfix"]="main"
["release"]="develop"
["experiment"]="develop"
["docs"]="develop"
["chore"]="develop"
["ci"]="develop"
["refactor"]="develop"
["perf"]="develop"
["test"]="develop"
)
# Configuration constants from brancher.sh
readonly MAX_BRANCH_LENGTH=50
readonly ALLOWED_PATTERN="^[a-z0-9._/-]+$"
readonly SEPARATOR="-"
# Color codes for output (legacy from brancher.sh)
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly NC='\033[0m' # No Color
# Status indicators
declare -A STATUS_ICONS=(
["BUSY"]=""
["WAITING"]=""
["IDLE"]=""
["ERROR"]=""
["SUCCESS"]="🎉"
["INFO"]="ℹ️"
["WARNING"]="⚠️"
)
declare -A STATUS_LABELS=(
["BUSY"]="Working"
["WAITING"]="Pending"
["IDLE"]="Ready"
["ERROR"]="Failed"
["SUCCESS"]="Complete"
["INFO"]="Information"
["WARNING"]="Attention"
)
# Legacy brancher.sh utility functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
[[ "${DEBUG:-}" == "1" ]] && echo -e "${CYAN}[DEBUG]${NC} $1"
}
# Core validation functions (from brancher.sh)
validate_git_repo() {
if ! git rev-parse --git-dir > /dev/null 2>&1; then
bb_error "Not in a git repository"
return 1
fi
}
validate_branch_type() {
local branch_type="$1"
if [[ -z "${BRANCH_TYPES[$branch_type]:-}" ]]; then
bb_error "Invalid branch type: $branch_type"
bb_info "Supported types: ${!BRANCH_TYPES[*]}"
return 1
fi
}
validate_branch_name() {
local branch_name="$1"
# Check length
if [[ ${#branch_name} -gt $MAX_BRANCH_LENGTH ]]; then
bb_error "Branch name too long (${#branch_name} > $MAX_BRANCH_LENGTH): $branch_name"
return 1
fi
# Check pattern
if [[ ! "$branch_name" =~ $ALLOWED_PATTERN ]]; then
bb_error "Invalid characters in branch name. Only lowercase letters, numbers, dots, underscores, and hyphens allowed: $branch_name"
return 1
fi
}
sanitize_input() {
local input="$1"
# Convert to lowercase, replace spaces and underscores with hyphens
echo "$input" | tr '[:upper:]' '[:lower:]' | tr ' _' '--' | sed 's/--*/-/g' | sed 's/^-\|-$//g'
}
check_branch_exists() {
local branch_name="$1"
git rev-parse --verify --quiet "$branch_name" > /dev/null 2>&1
}
ensure_base_branch() {
local base_branch="$1"
local current_branch
current_branch=$(git branch --show-current)
# Check if base branch exists, fall back to main if it doesn't
if ! git rev-parse --verify --quiet "$base_branch" > /dev/null 2>&1; then
bb_warning "Base branch '$base_branch' doesn't exist, falling back to 'main'"
base_branch="main"
fi
if [[ "$current_branch" != "$base_branch" ]]; then
bb_info "Switching to base branch: $base_branch"
if ! git checkout "$base_branch" 2>/dev/null; then
bb_error "Failed to checkout base branch: $base_branch"
return 1
fi
bb_info "Pulling latest changes from $base_branch"
if ! git pull origin "$base_branch" 2>/dev/null; then
bb_warning "Failed to pull latest changes. Continuing with local state."
fi
fi
}
# Core branching functions (from brancher.sh)
create_standard_branch() {
local branch_type="$1"
local issue_number="$2"
local description="$3"
local branch_name
local base_branch="${BASE_BRANCHES[$branch_type]:-develop}"
# Construct branch name based on type
if [[ "$branch_type" == "release" ]]; then
# For releases, issue_number is actually the version
branch_name="${branch_type}/${issue_number}"
elif [[ "$branch_type" == "experiment" ]] || [[ "$branch_type" == "docs" ]] || [[ "$branch_type" == "chore" ]] || [[ "$branch_type" == "ci" ]] || [[ "$branch_type" == "refactor" ]] || [[ "$branch_type" == "perf" ]] || [[ "$branch_type" == "test" ]]; then
# These types don't require issue numbers
if [[ -n "$issue_number" && -n "$description" ]]; then
branch_name="${branch_type}/$(sanitize_input "$issue_number-$description")"
elif [[ -n "$issue_number" ]]; then
branch_name="${branch_type}/$(sanitize_input "$issue_number")"
else
bb_error "Description required for $branch_type branches"
return 1
fi
else
# Standard types with issue numbers
if [[ -z "$issue_number" ]]; then
bb_error "Issue number required for $branch_type branches"
return 1
fi
if [[ -n "$description" ]]; then
branch_name="${branch_type}/${issue_number}-$(sanitize_input "$description")"
else
branch_name="${branch_type}/${issue_number}"
fi
fi
# Validate branch name
validate_branch_name "$branch_name" || return 1
# Check if branch already exists
if check_branch_exists "$branch_name"; then
bb_error "Branch already exists: $branch_name"
return 1
fi
# Ensure we're on the correct base branch
ensure_base_branch "$base_branch" || return 1
# Create and checkout the new branch
bb_info "Creating branch: $branch_name (from $base_branch)"
if git checkout -b "$branch_name"; then
bb_success "Successfully created and checked out: $branch_name"
bb_info "Branch type: ${BRANCH_TYPES[$branch_type]}"
bb_info "Description: ${BRANCH_DESCRIPTIONS[$branch_type]}"
return 0
else
bb_error "Failed to create branch: $branch_name"
return 1
fi
}
create_feature_branch_legacy() {
# Legacy feature branch creation with date-indexed naming
local main_branch="main"
local prefix="feature"
local datetime=$(date +%Y-%m-%d)
local username=$(echo "$USER" | tr '[:upper:]' '[:lower:]')
local additional_path=$(echo "$*" | tr ' ' '-')
local index=1
local new_branch
# Construct the branch path prefix with optional additional path
local branch_path="${prefix}/${username}"
[[ -n "$additional_path" ]] && branch_path="${branch_path}/${additional_path}"
branch_path="${branch_path}/${datetime}"
# Switch to main branch and pull latest changes if not on main
if [[ "$(git branch --show-current)" != "$main_branch" ]]; then
bb_info "Switching to ${main_branch} and pulling latest changes..."
git checkout $main_branch
git pull
fi
# Find the next available branch index for datetime
while git rev-parse --verify --quiet "${branch_path}/${index}"; do
index=$((index + 1))
done
# Create and switch to the new branch
new_branch="${branch_path}/${index}"
bb_info "Creating and checking out ${new_branch}..."
git checkout -b $new_branch
}
# List branches function from brancher.sh
list_branches() {
bb_info "Current branches organized by type:"
echo
for type in "${!BRANCH_TYPES[@]}"; do
local branches
branches=$(git branch -a | grep -E "^\s*[*]?\s*(remotes/origin/)?${type}/" | sed 's/^\s*[*]?\s*//' | sed 's/remotes\/origin\///' | sort -u)
if [[ -n "$branches" ]]; then
echo -e "${CYAN}$type branches:${NC}"
echo "$branches" | sed 's/^/ /'
echo
fi
done
}
# Global state
declare -g CURRENT_BRANCH=""
declare -g BRANCH_STATUS="IDLE"
declare -g ALL_BRANCHES=()
declare -g SHOW_REMOTE=false
# Utility functions using gum for beautiful output
bb_header() {
gum style \
--border normal \
--margin "1" \
--padding "1 2" \
--border-foreground "$BB_HEADER_COLOR" \
--bold \
--foreground "$BB_HEADER_COLOR" \
"BBManager - Git Branch Manager"
}
bb_info() {
local message="$1"
gum style --foreground "$BB_HEADER_COLOR" "ℹ️ $message"
}
bb_success() {
local message="$1"
gum style --foreground "$BB_SUCCESS_COLOR" "🎉 $message"
}
bb_warning() {
local message="$1"
gum style --foreground "$BB_WARNING_COLOR" "⚠️ $message"
}
bb_error() {
local message="$1"
gum style --foreground "$BB_ERROR_COLOR" "$message"
}
bb_confirm() {
local prompt="$1"
local default="${2:-No}"
gum confirm "$prompt" --default="$default"
}
bb_input() {
local prompt="$1"
local placeholder="${2:-}"
if [[ -n "$placeholder" ]]; then
gum input --placeholder "$placeholder" --prompt "$prompt "
else
gum input --prompt "$prompt "
fi
}
bb_choose() {
local prompt="$1"
shift
gum choose --selected.foreground="$GIT_COLOR" "$@" --header "$prompt"
}
bb_status_line() {
local current_branch
current_branch=$(git branch --show-current 2>/dev/null || echo "No repository")
local status_display="${STATUS_ICONS[$BRANCH_STATUS]} ${STATUS_LABELS[$BRANCH_STATUS]}"
gum join --vertical \
"$(gum style --foreground "$BB_HEADER_COLOR" "Current: $current_branch")" \
"$(gum style --foreground "#888888" "Status: $status_display")" \
"$(gum style --foreground "#888888" "Controls: ↑↓ Navigate | Enter Select")"
}
# Branch management functions using gum interface
get_all_branches() {
local include_remote="${1:-false}"
local branches=()
# Get local branches
while IFS= read -r branch; do
branch=$(echo "$branch" | sed 's/^[* ] //' | sed 's/^remotes\/origin\///')
[[ "$branch" =~ ^(HEAD|main|master|develop)$ ]] && continue
branches+=("$branch")
done < <(git branch 2>/dev/null)
# Get remote branches if requested
if [[ "$include_remote" == "true" ]]; then
while IFS= read -r branch; do
branch=$(echo "$branch" | sed 's/^[* ] //' | sed 's/^remotes\/origin\///')
[[ "$branch" =~ ^(HEAD|main|master|develop)$ ]] && continue
# Check if we already have this branch locally
local found=false
for local_branch in "${branches[@]}"; do
if [[ "$local_branch" == "$branch" ]]; then
found=true
break
fi
done
[[ "$found" == "false" ]] && branches+=("🌐 origin/$branch")
done < <(git branch -r 2>/dev/null)
fi
printf '%s\n' "${branches[@]}" | sort -u
}
get_branch_display_info() {
local branch="$1"
local clean_branch="$branch"
# Remove remote prefix for processing
if [[ "$branch" =~ ^🌐\ origin/ ]]; then
clean_branch="${branch#🌐 origin/}"
fi
# Get last commit date and message
local last_commit_date last_commit_msg
last_commit_date=$(git log -1 --format="%cr" "$clean_branch" 2>/dev/null || echo "unknown")
last_commit_msg=$(git log -1 --format="%s" "$clean_branch" 2>/dev/null | cut -c1-50)
# Check if branch has upstream
local upstream_status=""
if git rev-parse --verify "$clean_branch@{upstream}" >/dev/null 2>&1; then
local ahead behind
ahead=$(git rev-list --count "$clean_branch@{upstream}..$clean_branch" 2>/dev/null || echo "0")
behind=$(git rev-list --count "$clean_branch..$clean_branch@{upstream}" 2>/dev/null || echo "0")
if [[ "$ahead" -gt 0 && "$behind" -gt 0 ]]; then
upstream_status="${ahead}/${behind}"
elif [[ "$ahead" -gt 0 ]]; then
upstream_status="${ahead}"
elif [[ "$behind" -gt 0 ]]; then
upstream_status="${behind}"
else
upstream_status="="
fi
fi
printf "%s %s %s [%s]" "$branch" "$upstream_status" "$last_commit_date" "$last_commit_msg"
}
prepare_branch_list() {
local include_remote="${1:-$SHOW_REMOTE}"
ALL_BRANCHES=()
while IFS= read -r branch; do
[[ -n "$branch" ]] && ALL_BRANCHES+=("$(get_branch_display_info "$branch")")
done < <(get_all_branches "$include_remote")
}
# Main interactive interface using gum (React-like layout)
show_main_interface() {
clear
# Create the main interface layout similar to React components
gum style \
--border normal \
--margin "1" \
--padding "1 2" \
--border-foreground "$BB_HEADER_COLOR" \
--bold \
--foreground "$BB_SUCCESS_COLOR" \
"BBManager - Git Branch Manager"
echo
gum style \
--foreground "#888888" \
--margin "0 1" \
"Select a branch to start or resume a git session:"
echo
# Get current branch status for display
local current_branch
current_branch=$(git branch --show-current 2>/dev/null || echo "No repository")
# Create status display with icons and labels
local status_display="${STATUS_ICONS[$BRANCH_STATUS]} ${STATUS_LABELS[$BRANCH_STATUS]}"
local waiting_display="${STATUS_ICONS[WAITING]} ${STATUS_LABELS[WAITING]}"
local idle_display="${STATUS_ICONS[IDLE]} ${STATUS_LABELS[IDLE]}"
# Status information
gum join --vertical \
"$(gum style --foreground "#888888" "Status: $status_display $waiting_display $idle_display")" \
"$(gum style --foreground "#888888" "Controls: ↑↓ Navigate Enter Select")"
echo
# Prepare branch options with numbers for quick selection
local menu_options=(
"🔀 Select/Switch Branch"
"🆕 Create New Branch"
"🔄 Merge Branch"
"🗑️ Delete Branch"
"⚙️ Configuration"
"📊 Repository Status"
"❓ Help"
"🚪 Exit"
)
# Add numbered options for quick selection
local numbered_options=()
local i=0
for option in "${menu_options[@]}"; do
numbered_options+=("[$i] $option")
((i++))
done
# Main menu selection
local action
action=$(gum choose \
--header "Choose an action:" \
--selected.foreground="$GIT_COLOR" \
--height=10 \
"${numbered_options[@]}")
# Extract action from numbered format
action=$(echo "$action" | sed 's/^\[[0-9]\] //')
case "$action" in
"🔀 Select/Switch Branch")
action_select_branch
;;
"🆕 Create New Branch")
action_create_branch
;;
"🔄 Merge Branch")
action_merge_branch
;;
"🗑️ Delete Branch")
action_delete_branch
;;
"⚙️ Configuration")
action_config
;;
"📊 Repository Status")
action_status
;;
"❓ Help")
show_help_screen
;;
"🚪 Exit"|"")
bb_info "Goodbye!"
return 1
;;
*)
bb_error "Unknown action selected"
;;
esac
}
# Branch selection interface
action_select_branch() {
prepare_branch_list "$SHOW_REMOTE"
if [[ ${#ALL_BRANCHES[@]} -eq 0 ]]; then
bb_error "No branches available"
gum input --placeholder "Press Enter to continue..."
return 1
fi
# Toggle remote branches option
local toggle_text="Show Remote Branches"
[[ "$SHOW_REMOTE" == "true" ]] && toggle_text="Hide Remote Branches"
# Add toggle option at the top
local options=("📡 $toggle_text" "${ALL_BRANCHES[@]}")
local selected_branch
selected_branch=$(gum choose --header "Select a branch:" \
--selected.foreground="$GIT_COLOR" \
"${options[@]}")
if [[ "$selected_branch" =~ ^📡 ]]; then
# Toggle remote branch display
if [[ "$SHOW_REMOTE" == "true" ]]; then
SHOW_REMOTE=false
else
SHOW_REMOTE=true
fi
action_select_branch # Recursive call to refresh
return
fi
if [[ -z "$selected_branch" ]]; then
return 0
fi
# Extract branch name from the display format
local branch_name
branch_name=$(echo "$selected_branch" | awk '{print $1}')
if [[ "$branch_name" =~ ^🌐 ]]; then
# Remote branch - ask to checkout as new local branch
local clean_name="${branch_name#🌐 }"
local local_name="${clean_name#origin/}"
local new_local_name
new_local_name=$(bb_input "Create local branch from $clean_name as:" "$local_name")
[[ -z "$new_local_name" ]] && new_local_name="$local_name"
bb_info "Creating local branch '$new_local_name' from '$clean_name'"
BRANCH_STATUS="BUSY"
if git checkout -b "$new_local_name" "$clean_name" 2>/dev/null; then
bb_success "Successfully checked out branch: $new_local_name"
CURRENT_BRANCH="$new_local_name"
BRANCH_STATUS="SUCCESS"
else
bb_error "Failed to create branch: $new_local_name"
BRANCH_STATUS="ERROR"
fi
else
# Local branch
bb_info "Switching to branch: $branch_name"
BRANCH_STATUS="BUSY"
if git checkout "$branch_name" 2>/dev/null; then
bb_success "Successfully switched to: $branch_name"
CURRENT_BRANCH="$branch_name"
BRANCH_STATUS="SUCCESS"
else
bb_error "Failed to switch to branch: $branch_name"
BRANCH_STATUS="ERROR"
fi
fi
gum input --placeholder "Press Enter to continue..."
}
action_create_branch() {
bb_header
echo
gum style --foreground "$BB_HEADER_COLOR" --bold "Create New Branch"
echo
# Show available branch types using gum
bb_info "Available branch types:"
local types=(feature bugfix hotfix release experiment docs chore ci refactor perf test)
local type_options=()
for type in "${types[@]}"; do
type_options+=("$type - ${BRANCH_DESCRIPTIONS[$type]}")
done
local selected_type
selected_type=$(gum choose --header "Select branch type:" \
--selected.foreground="$GIT_COLOR" \
"${type_options[@]}")
if [[ -z "$selected_type" ]]; then
bb_warning "Branch creation cancelled"
gum input --placeholder "Press Enter to continue..."
return 0
fi
local branch_type
branch_type=$(echo "$selected_type" | awk '{print $1}')
validate_branch_type "$branch_type" || {
gum input --placeholder "Press Enter to continue..."
return 1
}
# Get issue number (optional for some types)
local issue_number=""
if [[ "$branch_type" =~ ^(feature|bugfix|hotfix)$ ]]; then
issue_number=$(bb_input "Issue number (required for $branch_type):")
if [[ -z "$issue_number" ]]; then
bb_error "Issue number is required for $branch_type branches"
gum input --placeholder "Press Enter to continue..."
return 1
fi
elif [[ "$branch_type" == "release" ]]; then
issue_number=$(bb_input "Version number (e.g., 1.2.0):")
if [[ -z "$issue_number" ]]; then
bb_error "Version number is required for release branches"
gum input --placeholder "Press Enter to continue..."
return 1
fi
else
issue_number=$(bb_input "Issue number or identifier (optional):")
fi
# Get description
local description
description=$(bb_input "Branch description:")
if [[ -z "$description" && -z "$issue_number" ]]; then
bb_error "Either issue number or description is required"
gum input --placeholder "Press Enter to continue..."
return 1
fi
# Create the branch using brancher.sh function
BRANCH_STATUS="BUSY"
bb_info "Creating branch..."
if create_standard_branch "$branch_type" "$issue_number" "$description"; then
BRANCH_STATUS="SUCCESS"
CURRENT_BRANCH=$(git branch --show-current)
bb_success "Branch created and checked out successfully: $CURRENT_BRANCH"
else
BRANCH_STATUS="ERROR"
bb_error "Failed to create branch"
fi
gum input --placeholder "Press Enter to continue..."
}
action_merge_branch() {
bb_header
echo
gum style --foreground "$BB_HEADER_COLOR" --bold "Merge Branch"
echo
local current_branch
current_branch=$(git branch --show-current)
if [[ -z "$current_branch" ]]; then
bb_error "Not on any branch"
gum input --placeholder "Press Enter to continue..."
return 1
fi
# Determine appropriate target branch
local default_target="develop"
if [[ "$current_branch" =~ ^hotfix/ ]]; then
default_target="main"
elif [[ "$current_branch" =~ ^release/ ]]; then
default_target="main"
fi
local target_branch
target_branch=$(bb_input "Target branch for merge:" "$default_target")
[[ -z "$target_branch" ]] && target_branch="$default_target"
# Check if target branch exists
if ! git rev-parse --verify --quiet "$target_branch" >/dev/null; then
bb_error "Target branch '$target_branch' does not exist"
gum input --placeholder "Press Enter to continue..."
return 1
fi
# Show merge information
gum join --vertical \
"$(gum style --foreground "$BB_WARNING_COLOR" "About to merge:")" \
"$(gum style --foreground "$GIT_COLOR" " From: $current_branch")" \
"$(gum style --foreground "$GIT_COLOR" " To: $target_branch")" \
""
if ! bb_confirm "Continue with merge?"; then
bb_info "Merge cancelled"
gum input --placeholder "Press Enter to continue..."
return 0
fi
BRANCH_STATUS="BUSY"
# Switch to target branch and pull latest
bb_info "Switching to $target_branch and pulling latest changes"
if ! git checkout "$target_branch" 2>/dev/null; then
bb_error "Failed to checkout target branch '$target_branch'"
bb_info "Make sure the branch exists locally. Run 'git branch' to see available branches."
BRANCH_STATUS="ERROR"
gum input --placeholder "Press Enter to continue..."
return 1
fi
bb_success "Successfully switched to $target_branch"
# Try to pull latest changes, but don't fail if there's no remote or network issues
bb_info "Checking for remote tracking branch"
if git rev-parse --verify --quiet "origin/$target_branch" >/dev/null 2>&1; then
bb_info "Pulling latest changes from remote"
if git pull origin "$target_branch" 2>/dev/null; then
bb_success "Successfully pulled latest changes"
else
bb_warning "Could not pull from remote (network issue). Continuing with local branch."
fi
else
bb_warning "No remote tracking branch found for '$target_branch'. Continuing with local branch."
fi
# Perform merge
bb_info "Merging $current_branch into $target_branch"
if git merge --no-ff "$current_branch" 2>&1; then
bb_success "Successfully merged $current_branch into $target_branch"
# Ask if they want to push
if bb_confirm "Push changes to remote?" true; then
if git push origin "$target_branch" 2>&1; then
bb_success "Changes pushed to remote"
else
bb_warning "Failed to push to remote. You may need to push manually later."
fi
fi
# Ask if they want to delete the merged branch
if bb_confirm "Delete merged branch '$current_branch'?"; then
if git branch -d "$current_branch" 2>/dev/null; then
bb_success "Deleted branch: $current_branch"
else
bb_warning "Could not delete branch '$current_branch'. You may need to force delete it manually."
fi
fi
BRANCH_STATUS="SUCCESS"
else
bb_error "Merge failed - resolve conflicts and try again"
bb_info "Run 'git status' to see conflicted files"
BRANCH_STATUS="ERROR"
fi
gum input --placeholder "Press Enter to continue..."
}
action_delete_branch() {
bb_header
echo
gum style --foreground "$BB_ERROR_COLOR" --bold "Delete Branch"
echo
# Get local branches (excluding protected ones)
local local_branches=()
while IFS= read -r branch; do
branch=$(echo "$branch" | sed 's/^[* ] //')
[[ "$branch" =~ ^(main|master|develop)$ ]] && continue
local_branches+=("$branch")
done < <(git branch 2>/dev/null)
if [[ ${#local_branches[@]} -eq 0 ]]; then
bb_error "No branches available for deletion"
gum input --placeholder "Press Enter to continue..."
return 1
fi
local branch_to_delete
branch_to_delete=$(gum choose --header "Select branch to delete:" \
--selected.foreground="$GIT_COLOR" \
"${local_branches[@]}")
if [[ -z "$branch_to_delete" ]]; then
bb_info "Deletion cancelled"
gum input --placeholder "Press Enter to continue..."
return 0
fi
local current_branch
current_branch=$(git branch --show-current)
# Can't delete current branch
if [[ "$branch_to_delete" == "$current_branch" ]]; then
bb_error "Cannot delete current branch. Switch to another branch first."
gum input --placeholder "Press Enter to continue..."
return 1
fi
# Show warning
gum join --vertical \
"$(gum style --foreground "$BB_ERROR_COLOR" "⚠️ WARNING: This will permanently delete the branch!")" \
"$(gum style --foreground "$BB_WARNING_COLOR" "Branch to delete: $branch_to_delete")" \
""
# Require typing DELETE for confirmation
local confirm_text
confirm_text=$(bb_input "Type 'DELETE' to confirm:")
if [[ "$confirm_text" != "DELETE" ]]; then
bb_info "Deletion cancelled"
gum input --placeholder "Press Enter to continue..."
return 0
fi
BRANCH_STATUS="BUSY"
# Check if branch has been merged
if git branch --merged | grep -q "^[* ] $branch_to_delete$"; then
# Safe deletion
if git branch -d "$branch_to_delete" 2>/dev/null; then
bb_success "Successfully deleted branch: $branch_to_delete"
BRANCH_STATUS="SUCCESS"
else
bb_error "Failed to delete branch: $branch_to_delete"
BRANCH_STATUS="ERROR"
fi
else
# Force deletion required
bb_warning "Branch has unmerged changes!"
if bb_confirm "Force delete anyway?"; then
if git branch -D "$branch_to_delete" 2>/dev/null; then
bb_success "Force deleted branch: $branch_to_delete"
BRANCH_STATUS="SUCCESS"
else
bb_error "Failed to force delete branch: $branch_to_delete"
BRANCH_STATUS="ERROR"
fi
else
bb_info "Deletion cancelled"
gum input --placeholder "Press Enter to continue..."
return 0
fi
fi
# Ask about remote deletion
if git ls-remote --heads origin "$branch_to_delete" 2>/dev/null | grep -q "$branch_to_delete"; then
if bb_confirm "Also delete remote branch?"; then
git push origin --delete "$branch_to_delete" 2>/dev/null && bb_success "Deleted remote branch: $branch_to_delete"
fi
fi
gum input --placeholder "Press Enter to continue..."
}
action_config() {
bb_header
echo
gum style --foreground "$BB_HEADER_COLOR" --bold "BBManager Configuration"
echo
# Show current configuration
gum join --vertical \
"$(gum style --foreground "$BB_WARNING_COLOR" "Current Configuration:")" \
"$(gum style --foreground "#888888" "Config file: $BB_CONFIG_FILE")" \
"$(gum style --foreground "#888888" "Debug mode: ${gum_debug:-off}")" \
"$(gum style --foreground "#888888" "Git repository: $(git rev-parse --show-toplevel 2>/dev/null || echo 'Not in repository')")" \
""
bb_info "Default base branches:"
for type in "${!BASE_BRANCHES[@]}"; do
gum style --foreground "#888888" " $(printf "%-12s -> %s" "$type" "${BASE_BRANCHES[$type]}")"
done
echo
# Configuration options
local config_action
config_action=$(gum choose --header "Configuration Options:" \
--selected.foreground="$GIT_COLOR" \
"Edit base branch mappings" \
"Set default branch types" \
"Configure aliases" \
"Reset to defaults" \
"Back to main menu")
case "$config_action" in
"Edit base branch mappings")
bb_info "Edit Base Branch Mappings"
for type in "${!BASE_BRANCHES[@]}"; do
local new_base
new_base=$(bb_input "Base branch for $type:" "${BASE_BRANCHES[$type]}")
[[ -n "$new_base" ]] && BASE_BRANCHES[$type]="$new_base"
done
bb_success "Base branch mappings updated"
;;
"Set default branch types")
bb_info "Default Branch Types"
gum style --foreground "#888888" "Current types: ${!BRANCH_TYPES[*]}"
bb_warning "This feature is planned for future release"
;;
"Configure aliases")
bb_info "Configure Aliases"
bb_warning "This feature is planned for future release"
;;
"Reset to defaults")
bb_info "Reset to Defaults"
if bb_confirm "Reset all configuration to defaults?"; then
[[ -f "$BB_CONFIG_FILE" ]] && rm "$BB_CONFIG_FILE"
bb_success "Configuration reset to defaults"
fi
;;
*)
return 0
;;
esac
gum input --placeholder "Press Enter to continue..."
}
action_status() {
bb_header
echo
gum style --foreground "$BB_HEADER_COLOR" --bold "Repository Status"
echo
# Git status
bb_info "Git Status:"
local git_status
git_status=$(git status --short 2>/dev/null || echo "Not in a git repository")
if [[ -n "$git_status" ]]; then
echo "$git_status"
else
gum style --foreground "#888888" "Working tree clean"
fi
echo
# Branch information
bb_info "Branch Information:"
local current_branch
current_branch=$(git branch --show-current 2>/dev/null)
if [[ -n "$current_branch" ]]; then
gum style --foreground "#888888" "Current branch: $current_branch"
# Check for upstream
if git rev-parse --verify "$current_branch@{upstream}" >/dev/null 2>&1; then
local ahead behind
ahead=$(git rev-list --count "$current_branch@{upstream}..$current_branch" 2>/dev/null || echo "0")
behind=$(git rev-list --count "$current_branch..$current_branch@{upstream}" 2>/dev/null || echo "0")
gum style --foreground "#888888" "Upstream: ${current_branch}@{upstream}"
gum style --foreground "#888888" "Ahead: $ahead commits"
gum style --foreground "#888888" "Behind: $behind commits"
else
gum style --foreground "#888888" "No upstream configured"
fi
# Last commit
local last_commit
last_commit=$(git log -1 --format="%h %s (%cr)" 2>/dev/null || echo "No commits")
gum style --foreground "#888888" "Last commit: $last_commit"
else
gum style --foreground "#888888" "Not on any branch"
fi
echo
# Recent branches
bb_info "Recent Branches:"
local recent_branches
recent_branches=$(git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname:short) (%(committerdate:relative))' 2>/dev/null | head -5)
if [[ -n "$recent_branches" ]]; then
echo "$recent_branches" | while read -r line; do
gum style --foreground "#888888" " $line"
done
else
gum style --foreground "#888888" " No branches found"
fi
echo
gum input --placeholder "Press Enter to continue..."
}
# Interactive main loop using gum with keyboard shortcuts
interactive_mode() {
# Initialize
validate_git_repo || {
bb_error "Not in a git repository"
return 1
}
CURRENT_BRANCH=$(git branch --show-current)
# Check if gum is available
if ! command -v gum >/dev/null 2>&1; then
echo "Gum is not installed. Checking installation..."
check_gum_installation || return 1
fi
# Main loop with keyboard shortcut handling
while true; do
# Check for keyboard shortcuts using environment or direct input
local shortcut_action=""
# Show main interface
if ! show_main_interface; then
break
fi
# Handle quick shortcuts if implemented
case "$shortcut_action" in
"n"|"N")
action_create_branch
;;
"m"|"M")
action_merge_branch
;;
"d"|"D")
action_delete_branch
;;
"c"|"C")
action_config
;;
"s"|"S")
action_status
;;
"h"|"H"|"?")
show_help_screen
;;
"q"|"Q")
bb_info "Goodbye!"
break
;;
[0-9])
# Quick numeric selection (could be implemented)
;;
esac
done
}
show_help_screen() {
bb_header
echo
gum style --foreground "$BB_HEADER_COLOR" --bold "BBManager Help"
echo
gum join --vertical \
"$(gum style --foreground "$BB_WARNING_COLOR" "Navigation:")" \
"$(gum style --foreground "#888888" " ↑↓ Arrow Keys Navigate branch list")" \
"$(gum style --foreground "#888888" " Enter Select highlighted branch")" \
"$(gum style --foreground "#888888" " ESC Return to main menu")" \
"" \
"$(gum style --foreground "$BB_WARNING_COLOR" "Quick Actions:")" \
"$(gum style --foreground "#888888" " N Create new branch")" \
"$(gum style --foreground "#888888" " M Merge current branch")" \
"$(gum style --foreground "#888888" " D Delete branch")" \
"$(gum style --foreground "#888888" " C Configuration")" \
"$(gum style --foreground "#888888" " S Show status")" \
"$(gum style --foreground "#888888" " H or ? Show this help")" \
"$(gum style --foreground "#888888" " Q Quit")" \
"" \
"$(gum style --foreground "$BB_WARNING_COLOR" "Status Indicators:")"
for status in BUSY WAITING IDLE ERROR SUCCESS INFO WARNING; do
gum style --foreground "#888888" " ${STATUS_ICONS[$status]} ${STATUS_LABELS[$status]}"
done
echo
gum input --placeholder "Press Enter to continue..."
}
check_gum_installation() {
if ! command -v gum >/dev/null 2>&1; then
echo -e "\033[1;33m⚠️ gum is not installed\033[0m"
echo
echo -e "\033[0;34mgum is required for this script to work properly.\033[0m"
echo
echo -e "\033[0;34mInstall with one of the following commands:\033[0m"
echo
echo -e "\033[0;37m# macOS or Linux\033[0m"
echo -e "\033[0;32mbrew install gum\033[0m"
echo
echo -e "\033[0;37m# Arch Linux (btw)\033[0m"
echo -e "\033[0;32mpacman -S gum\033[0m"
echo
echo -e "\033[0;37m# Nix\033[0m"
echo -e "\033[0;32mnix-env -iA nixpkgs.gum\033[0m"
echo
echo -e "\033[0;37m# Flox\033[0m"
echo -e "\033[0;32mflox install gum\033[0m"
echo
echo -e "\033[0;37m# Windows (via WinGet or Scoop)\033[0m"
echo -e "\033[0;32mwinget install charmbracelet.gum\033[0m"
echo -e "\033[0;32mscoop install charm-gum\033[0m"
echo
echo -e "\033[0;37m# Debian/Ubuntu\033[0m"
echo -e "\033[0;32msudo mkdir -p /etc/apt/keyrings\033[0m"
echo -e "\033[0;32mcurl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg\033[0m"
echo -e "\033[0;32mecho \"deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *\" | sudo tee /etc/apt/sources.list.d/charm.list\033[0m"
echo -e "\033[0;32msudo apt update && sudo apt install gum\033[0m"
echo
echo -e "\033[0;37m# Fedora/RHEL/OpenSuse\033[0m"
echo -e "\033[0;32mecho '[charm]\nname=Charm\nbaseurl=https://repo.charm.sh/yum/\nenabled=1\ngpgcheck=1\ngpgkey=https://repo.charm.sh/yum/gpg.key' | sudo tee /etc/yum.repos.d/charm.repo\033[0m"
echo -e "\033[0;32msudo rpm --import https://repo.charm.sh/yum/gpg.key\033[0m"
echo -e "\033[0;32msudo yum install gum\033[0m"
echo
echo -e "\033[0;37m# FreeBSD\033[0m"
echo -e "\033[0;32msudo pkg install gum\033[0m"
echo
echo -e "\033[0;37m# Go\033[0m"
echo -e "\033[0;32mgo install github.com/charmbracelet/gum@latest\033[0m"
echo
read -p "Install gum now using apt? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "\033[0;34mℹ️ Installing gum...\033[0m"
if sudo apt update && sudo apt install gum; then
echo -e "\033[0;32m🎉 gum installed successfully\033[0m"
return 0
else
echo -e "\033[0;31m❌ Failed to install gum\033[0m"
return 1
fi
else
echo -e "\033[0;31m❌ gum is required for this script\033[0m"
return 1
fi
else
local gum_version
gum_version=$(gum --version 2>/dev/null || echo "unknown")
bb_success "gum is already installed (version: $gum_version)"
gum style --foreground "$BB_HEADER_COLOR" "Location: $(which gum)"
return 0
fi
}
# Main function for gum integration
main() {
# Handle command line arguments directly
local action=""
local check_gum_flag=false
local debug_flag=false
local no_color_flag=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--check-gum)
check_gum_flag=true
shift
;;
--debug)
debug_flag=true
shift
;;
--no-color)
no_color_flag=true
shift
;;
--config-file)
BB_CONFIG_FILE="$2"
shift 2
;;
*)
action="$1"
shift
break # Exit the parsing loop to preserve remaining arguments
;;
esac
done
# Handle flags first
if [[ "$check_gum_flag" == "true" ]]; then
check_gum_installation
return $?
fi
if [[ "$debug_flag" == "true" ]]; then
export DEBUG=1
fi
if [[ "$no_color_flag" == "true" ]]; then
export NO_COLOR=1
fi
# Default action
[[ -z "$action" ]] && action="select"
# Set up cleanup
trap 'rm -rf "$BB_TEMP_DIR" 2>/dev/null; [[ -f "$BB_LOCK_FILE" ]] && rm -f "$BB_LOCK_FILE"' EXIT
# Create temp directory
mkdir -p "$BB_TEMP_DIR"
# Handle actions
case "$action" in
"select"|"interactive"|"")
interactive_mode
;;
"create"|"new")
validate_git_repo || return 1
action_create_branch
;;
"merge")
validate_git_repo || return 1
action_merge_branch
;;
"delete"|"del"|"remove")
validate_git_repo || return 1
action_delete_branch
;;
"config"|"conf")
action_config
;;
"status"|"st")
validate_git_repo || return 1
action_status
;;
"help"|"h"|"--help")
show_help_screen
;;
"check-gum"|"check_gum")
check_gum_installation
;;
"list"|"l"|"--list")
validate_git_repo || return 1
list_branches
;;
"legacy")
validate_git_repo || return 1
create_feature_branch_legacy "$@"
;;
# Handle direct brancher.sh style commands
"feature"|"bugfix"|"hotfix"|"release"|"experiment"|"docs"|"chore"|"ci"|"refactor"|"perf"|"test")
validate_git_repo || return 1
brancher "$action" "$@"
;;
*)
# Check if it's a brancher-style command
if [[ -n "${BRANCH_TYPES[$action]:-}" ]]; then
validate_git_repo || return 1
brancher "$action" "$@"
else
bb_error "Unknown action: $action"
echo
show_brancher_usage
return 1
fi
;;
esac
}
# Export functions for external use and brancher compatibility
export -f main interactive_mode action_select_branch action_create_branch
export -f action_merge_branch action_delete_branch action_config action_status
export -f validate_git_repo log_info log_success log_warning log_error
export -f create_standard_branch validate_branch_type sanitize_input check_branch_exists
# Legacy brancher.sh aliases for backward compatibility
alias br="bbmanager"
alias branch="bbmanager"
alias fb="bbmanager legacy"
# Auto-completion for bash (from brancher.sh)
if [[ -n "${BASH_VERSION:-}" ]]; then
_bbmanager_completion() {
local cur prev
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [[ ${COMP_CWORD} == 1 ]]; then
COMPREPLY=($(compgen -W "${!BRANCH_TYPES[*]} help list legacy select create merge delete config status check-gum" -- "$cur"))
fi
}
complete -F _bbmanager_completion bbmanager
fi
# Main brancher function for legacy compatibility
brancher() {
# Validate git repository
validate_git_repo || return 1
local first_arg="${1:-}"
if [[ "$first_arg" == "help" ]] || [[ "$first_arg" == "-h" ]] || [[ "$first_arg" == "--help" ]]; then
show_brancher_usage
return 0
elif [[ "$first_arg" == "list" ]] || [[ "$first_arg" == "-l" ]] || [[ "$first_arg" == "--list" ]]; then
list_branches
return 0
elif [[ "$first_arg" == "legacy" ]]; then
shift
create_feature_branch_legacy "$@"
return $?
elif [[ -z "$first_arg" ]]; then
bb_error "Branch type required"
show_brancher_usage
return 1
else
local branch_type="$1"
local issue_number="$2"
local description="$3"
# Additional arguments become part of description
if [[ $# -gt 3 ]]; then
shift 3
description="$description $*"
fi
validate_branch_type "$branch_type" || return 1
create_standard_branch "$branch_type" "$issue_number" "$description"
return $?
fi
}
# Show usage for brancher compatibility
show_brancher_usage() {
cat << EOF
${CYAN}Git-Flow Branching Automation Utility (BBManager)${NC}
${YELLOW}USAGE:${NC}
bbmanager <type> [issue-number] [description]
bbmanager help
bbmanager list
bbmanager legacy [description...]
${YELLOW}BRANCH TYPES:${NC}
EOF
for type in "${!BRANCH_TYPES[@]}"; do
printf " %-12s %s\n" "$type" "${BRANCH_DESCRIPTIONS[$type]}"
done
cat << EOF
${YELLOW}EXAMPLES:${NC}
bbmanager feature 123 add-login-api -> feature/123-add-login-api
bbmanager bugfix 456 fix-nullpointer -> bugfix/456-fix-nullpointer
bbmanager hotfix 789 patch-security -> hotfix/789-patch-security
bbmanager release 1.4.0 -> release/1.4.0
bbmanager experiment new-graphql -> experiment/new-graphql-prototype
bbmanager docs update-api -> docs/update-api-reference
bbmanager chore update-deps -> chore/update-dependencies
bbmanager ci add-actions -> ci/add-github-actions
bbmanager refactor extract-service -> refactor/extract-user-service
bbmanager perf cache-token -> perf/cache-auth-token
bbmanager test integration -> test/add-integration-tests
bbmanager legacy utils package -> feature/username/utils-package/2025-07-08/1
${YELLOW}SPECIAL COMMANDS:${NC}
help Show this help message
list List all branches by type
legacy Use legacy date-indexed feature branch naming
select Interactive branch selection
create Interactive branch creation
merge Interactive branch merging
delete Interactive branch deletion
config Configuration management
status Repository status
${YELLOW}ENVIRONMENT VARIABLES:${NC}
DEBUG=1 Enable debug output
EOF
}
# Run main function if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment