feat: check remote branches to prevent duplicate branch numbers

- Add --number parameter to create-new-feature scripts (bash & PowerShell)
- Add check_existing_branches() function to fetch and scan remote branches
- Update branch numbering logic to check remotes before creating new branches
- Update /speckit.specify command to document remote branch checking workflow
- Prevents duplicate branch numbers when branches exist on remotes but not locally
- Maintains backward compatibility with existing workflows
- Falls back to local directory scanning when Git is not available
This commit is contained in:
Simon Gent
2025-10-23 12:14:48 +01:00
parent 926836e0fc
commit 1f3d9b5fdd
3 changed files with 151 additions and 38 deletions

View File

@@ -4,6 +4,7 @@ set -e
JSON_MODE=false
SHORT_NAME=""
BRANCH_NUMBER=""
ARGS=()
i=1
while [ $i -le $# ]; do
@@ -26,17 +27,31 @@ while [ $i -le $# ]; do
fi
SHORT_NAME="$next_arg"
;;
--number)
if [ $((i + 1)) -gt $# ]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
i=$((i + 1))
next_arg="${!i}"
if [[ "$next_arg" == --* ]]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
BRANCH_NUMBER="$next_arg"
;;
--help|-h)
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>"
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>"
echo ""
echo "Options:"
echo " --json Output in JSON format"
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
echo " --number N Specify branch number manually (overrides auto-detection)"
echo " --help, -h Show this help message"
echo ""
echo "Examples:"
echo " $0 'Add user authentication system' --short-name 'user-auth'"
echo " $0 'Implement OAuth2 integration for API'"
echo " $0 'Implement OAuth2 integration for API' --number 5"
exit 0
;;
*)
@@ -48,7 +63,7 @@ done
FEATURE_DESCRIPTION="${ARGS[*]}"
if [ -z "$FEATURE_DESCRIPTION" ]; then
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>" >&2
echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>" >&2
exit 1
fi
@@ -65,6 +80,28 @@ find_repo_root() {
return 1
}
# Function to check existing branches (local and remote) and return next available number
check_existing_branches() {
local short_name="$1"
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
git fetch --all --prune 2>/dev/null || true
# Find all branches matching the pattern (local and remote)
local branches=$(git branch -a 2>/dev/null | grep -E "feature/[0-9]+-${short_name}$" | sed 's/.*feature\///' | sed "s/-${short_name}$//" | sort -n)
# Get the highest number
local max_num=0
for num in $branches; do
if [ "$num" -gt "$max_num" ]; then
max_num=$num
fi
done
# Return next number
echo $((max_num + 1))
}
# Resolve repository root. Prefer git information when available, but fall back
# to searching for repository markers so the workflow still functions in repositories that
# were initialised with --no-git.
@@ -87,20 +124,6 @@ cd "$REPO_ROOT"
SPECS_DIR="$REPO_ROOT/specs"
mkdir -p "$SPECS_DIR"
HIGHEST=0
if [ -d "$SPECS_DIR" ]; then
for dir in "$SPECS_DIR"/*; do
[ -d "$dir" ] || continue
dirname=$(basename "$dir")
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
number=$((10#$number))
if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi
done
fi
NEXT=$((HIGHEST + 1))
FEATURE_NUM=$(printf "%03d" "$NEXT")
# Function to generate branch name with stop word filtering and length filtering
generate_branch_name() {
local description="$1"
@@ -157,6 +180,28 @@ else
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
fi
# Determine branch number
if [ -z "$BRANCH_NUMBER" ]; then
if [ "$HAS_GIT" = true ]; then
# Check existing branches on remotes
BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX")
else
# Fall back to local directory check
HIGHEST=0
if [ -d "$SPECS_DIR" ]; then
for dir in "$SPECS_DIR"/*; do
[ -d "$dir" ] || continue
dirname=$(basename "$dir")
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
number=$((10#$number))
if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi
done
fi
BRANCH_NUMBER=$((HIGHEST + 1))
fi
fi
FEATURE_NUM=$(printf "%03d" "$BRANCH_NUMBER")
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
# GitHub enforces a 244-byte limit on branch names