Git branch management tool. Detects main iteration branch and branch naming conventions, handles branch creation and switching. Referenced by blocklet-dev-setup, blocklet-pr, and other skills.
Unified Git branch management tool providing branch detection, creation, and switching capabilities.
"Detect dynamically, never assume."
Branch management must not hardcode main or master. Different ArcBlock repositories follow different branch conventions. By analyzing PR history dynamically, branch operations adapt to each repository automatically.
main or master; detect dynamically through merged PR historyREMOTE_URL=$(git remote get-url origin)
# Parse org/repo
ORG=$(echo $REMOTE_URL | sed -E 's/.*[:/]([^/]+)\/([^/]+)(\.git)?$/\1/')
REPO=$(echo $REMOTE_URL | sed -E 's/.*[:/]([^/]+)\/([^/]+)(\.git)?$/\2/' | sed 's/\.git$//')
echo "Repository: $ORG/$REPO"
CURRENT_BRANCH=$(git branch --show-current)
echo "Current branch: $CURRENT_BRANCH"
Important: Must determine the main iteration branch by analyzing the last 10 merged PRs, rather than simply assuming it is main or master.
# Get target branches of the last 10 merged PRs, count occurrences to find the main iteration branch
MAIN_BRANCH=$(gh pr list --repo $ORG/$REPO --state merged --limit 10 --json baseRefName \
| jq -r '.[].baseRefName' | sort | uniq -c | sort -rn | head -1 | awk '{print $2}')
# Get detection rationale
BRANCH_STATS=$(gh pr list --repo $ORG/$REPO --state merged --limit 10 --json baseRefName \
| jq -r '.[].baseRefName' | sort | uniq -c | sort -rn)
echo "Main iteration branch: $MAIN_BRANCH"
echo "Detection rationale (target branch statistics from last 10 merged PRs):"
echo "$BRANCH_STATS"
| Variable | Description | Example |
|---|---|---|
MAIN_BRANCH |
Detected main iteration branch | main, develop, master |
MAIN_BRANCH_REASON |
Detection rationale | "8 out of 10 recent merged PRs targeted main" |
Important: Determine branch naming prefix conventions by analyzing the last 10 merged PRs.
# Get source branch names from the last 10 merged PRs, analyze naming conventions
BRANCH_NAMES=$(gh pr list --repo $ORG/$REPO --state merged --limit 10 --json headRefName \
| jq -r '.[].headRefName')
# Extract prefixes (supports both / and - separators)
BRANCH_PREFIXES=$(echo "$BRANCH_NAMES" | sed -E 's/^([a-zA-Z]+)[\/\-].*/\1/' | sort | uniq -c | sort -rn)
echo "Branch naming prefix statistics (from last 10 merged PRs):"
echo "$BRANCH_PREFIXES"
# Detect separator style (/ or -)
if echo "$BRANCH_NAMES" | grep -q '/'; then
SEPARATOR="/"
else
SEPARATOR="-"
fi
echo "Separator style: $SEPARATOR"
| Prefix | Purpose | Example |
|---|---|---|
feat / feature |
New feature | feat/add-login, feature/user-profile |
fix / bugfix |
Bug fix | fix/login-error, bugfix/issue-123 |
chore |
Routine maintenance | chore/update-deps |
refactor |
Code refactoring | refactor/auth-module |
docs |
Documentation update | docs/api-guide |
test |
Test-related | test/add-unit-tests |
style |
Code style | style/format-code |
perf |
Performance optimization | perf/optimize-query |
| Variable | Description | Example |
|---|---|---|
BRANCH_PREFIX_CONVENTION |
Primary prefix convention | feat, fix |
BRANCH_SEPARATOR |
Separator style | / or - |
Important: Before switching branches, uncommitted changes must be handled first.
UNCOMMITTED_CHANGES=$(git status --porcelain)
if [ -n "$UNCOMMITTED_CHANGES" ]; then
echo "β οΈ Uncommitted changes detected:"
git status --short
fi
If there are uncommitted changes, use AskUserQuestion to ask the user:
Uncommitted changes detected. Please choose how to proceed:
Options:
A. Stash changes (git stash) - can be restored later (Recommended)
B. Commit changes - create a temporary commit
C. Discard changes (git checkout .) - β οΈ cannot be undone
D. Cancel operation
Execute handling:
# Option A: Stash
git stash push -m "Auto stash before branch switch"
# Option B: Commit
git add -A && git commit -m "WIP: auto commit before branch switch"
# Option C: Discard
git checkout . && git clean -fd
# Ensure local has latest remote branch info
git fetch origin
# Switch to main iteration branch and update
git checkout $MAIN_BRANCH
git pull origin $MAIN_BRANCH
echo "β
Switched to main iteration branch: $MAIN_BRANCH"
TARGET_BRANCH="feat/my-feature"
# Check if branch exists
if git show-ref --verify --quiet refs/heads/$TARGET_BRANCH; then
# Local branch exists
git checkout $TARGET_BRANCH
elif git show-ref --verify --quiet refs/remotes/origin/$TARGET_BRANCH; then
# Remote branch exists, create local tracking branch
git checkout -b $TARGET_BRANCH origin/$TARGET_BRANCH
else
echo "β Branch $TARGET_BRANCH does not exist"
fi
Generate suggested branch name based on task type and repository naming conventions:
# Input parameters
TASK_TYPE="fix" # feat, fix, chore, refactor, docs, test
TASK_DESCRIPTION="login" # Brief description
ISSUE_NUMBER="" # Optional issue number
# Generate branch name
if [ -n "$ISSUE_NUMBER" ]; then
SUGGESTED_BRANCH="${TASK_TYPE}${BRANCH_SEPARATOR}issue-${ISSUE_NUMBER}-${TASK_DESCRIPTION}"
else
SUGGESTED_BRANCH="${TASK_TYPE}${BRANCH_SEPARATOR}${TASK_DESCRIPTION}"
fi
echo "Suggested branch name: $SUGGESTED_BRANCH"
Prerequisite: Must be created based on the latest main iteration branch.
# 1. Ensure main iteration branch is up to date
git fetch origin $MAIN_BRANCH
git checkout $MAIN_BRANCH
git pull origin $MAIN_BRANCH
# 2. Create and switch to new branch
NEW_BRANCH="feat/my-new-feature"
git checkout -b $NEW_BRANCH
echo "β
Created and switched to branch: $NEW_BRANCH (based on $MAIN_BRANCH)"
Use AskUserQuestion to confirm branch name:
Will create new branch based on {MAIN_BRANCH}.
Please select branch name:
Options:
A. {SUGGESTED_BRANCH} (Recommended)
B. Enter custom branch name
C. Cancel operation
if [ "$CURRENT_BRANCH" = "$MAIN_BRANCH" ]; then
echo "β οΈ Currently on main iteration branch"
ON_MAIN_BRANCH=true
else
ON_MAIN_BRANCH=false
fi
# Check if branch name follows common prefix conventions
if echo "$CURRENT_BRANCH" | grep -qE "^(feat|fix|chore|refactor|docs|test|style|perf|hotfix|release)[/\-]"; then
echo "β
Branch naming follows convention"
BRANCH_NAME_VALID=true
else
echo "β οΈ Branch naming does not follow common conventions: $CURRENT_BRANCH"
BRANCH_NAME_VALID=false
fi
# Get local and remote differences
git fetch origin
LOCAL_COMMIT=$(git rev-parse HEAD)
REMOTE_COMMIT=$(git rev-parse origin/$CURRENT_BRANCH 2>/dev/null || echo "")
if [ -z "$REMOTE_COMMIT" ]; then
echo "π€ Branch not yet pushed to remote"
SYNC_STATUS="not_pushed"
elif [ "$LOCAL_COMMIT" = "$REMOTE_COMMIT" ]; then
echo "β
Branch is in sync with remote"
SYNC_STATUS="synced"
else
AHEAD=$(git rev-list origin/$CURRENT_BRANCH..HEAD --count)
BEHIND=$(git rev-list HEAD..origin/$CURRENT_BRANCH --count)
echo "π Local is $AHEAD commits ahead, $BEHIND commits behind"
SYNC_STATUS="diverged"
fi
This skill is referenced by the following skills:
| Skill | Features Used |
|---|---|
blocklet-dev-setup |
Detect main iteration branch, handle uncommitted changes, switch branches, create working branch |
blocklet-pr |
Detect main iteration branch, branch naming conventions, enforce working branch creation |
How to reference:
Refer to blocklet-branch skill for branch operations.
Skill location: `blocklet-branch/SKILL.md`
| Error | Cause | Solution |
|---|---|---|
| Cannot get PR history | gh not authenticated or network issue | Run gh auth status to check authentication |
| Branch switch failed | Conflicting uncommitted changes | Handle uncommitted changes first |
| Branch creation failed | Branch name already exists | Use different branch name or switch to existing branch |
| Cannot detect main iteration branch | Repository has no merged PRs | Fall back to default branch gh repo view --json defaultBranchRef |