Merge pull request #1237 from Mearman/fix/branch-number-collision-bug

fix: use global maximum for branch numbering to prevent collisions
This commit is contained in:
Den Delimarsky
2025-12-02 11:05:15 -08:00
committed by GitHub
2 changed files with 29 additions and 81 deletions

View File

@@ -128,32 +128,23 @@ get_highest_from_branches() {
# Function to check existing branches (local and remote) and return next available number # Function to check existing branches (local and remote) and return next available number
check_existing_branches() { check_existing_branches() {
local short_name="$1" local specs_dir="$1"
local specs_dir="$2"
# Fetch all remotes to get latest branch info (suppress errors if no remotes) # Fetch all remotes to get latest branch info (suppress errors if no remotes)
git fetch --all --prune 2>/dev/null || true git fetch --all --prune 2>/dev/null || true
# Find all branches matching the pattern using git ls-remote (more reliable) # Get highest number from ALL branches (not just matching short name)
local remote_branches=$(git ls-remote --heads origin 2>/dev/null | grep -E "refs/heads/[0-9]+-${short_name}$" | sed 's/.*\/\([0-9]*\)-.*/\1/' | sort -n) local highest_branch=$(get_highest_from_branches)
# Also check local branches # Get highest number from ALL specs (not just matching short name)
local local_branches=$(git branch 2>/dev/null | grep -E "^[* ]*[0-9]+-${short_name}$" | sed 's/^[* ]*//' | sed 's/-.*//' | sort -n) local highest_spec=$(get_highest_from_specs "$specs_dir")
# Check specs directory as well # Take the maximum of both
local spec_dirs="" local max_num=$highest_branch
if [ -d "$specs_dir" ]; then if [ "$highest_spec" -gt "$max_num" ]; then
spec_dirs=$(find "$specs_dir" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) max_num=$highest_spec
fi fi
# Combine all sources and get the highest number
local max_num=0
for num in $remote_branches $local_branches $spec_dirs; do
if [ "$num" -gt "$max_num" ]; then
max_num=$num
fi
done
# Return next number # Return next number
echo $((max_num + 1)) echo $((max_num + 1))
} }
@@ -247,7 +238,7 @@ fi
if [ -z "$BRANCH_NUMBER" ]; then if [ -z "$BRANCH_NUMBER" ]; then
if [ "$HAS_GIT" = true ]; then if [ "$HAS_GIT" = true ]; then
# Check existing branches on remotes # Check existing branches on remotes
BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX" "$SPECS_DIR") BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR")
else else
# Fall back to local directory check # Fall back to local directory check
HIGHEST=$(get_highest_from_specs "$SPECS_DIR") HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
@@ -255,7 +246,8 @@ if [ -z "$BRANCH_NUMBER" ]; then
fi fi
fi fi
FEATURE_NUM=$(printf "%03d" "$BRANCH_NUMBER") # Force base-10 interpretation to prevent octal conversion (e.g., 010 → 8 in octal, but should be 10 in decimal)
FEATURE_NUM=$(printf "%03d" "$((10#$BRANCH_NUMBER))")
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}" BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
# GitHub enforces a 244-byte limit on branch names # GitHub enforces a 244-byte limit on branch names

View File

@@ -101,69 +101,25 @@ function Get-HighestNumberFromBranches {
function Get-NextBranchNumber { function Get-NextBranchNumber {
param( param(
[string]$ShortName,
[string]$SpecsDir [string]$SpecsDir
) )
# Fetch all remotes to get latest branch info (suppress errors if no remotes) # Fetch all remotes to get latest branch info (suppress errors if no remotes)
try { try {
git fetch --all --prune 2>$null | Out-Null git fetch --all --prune 2>$null | Out-Null
} catch { } catch {
# Ignore fetch errors # Ignore fetch errors
} }
# Find remote branches matching the pattern using git ls-remote # Get highest number from ALL branches (not just matching short name)
$remoteBranches = @() $highestBranch = Get-HighestNumberFromBranches
try {
$remoteRefs = git ls-remote --heads origin 2>$null # Get highest number from ALL specs (not just matching short name)
if ($remoteRefs) { $highestSpec = Get-HighestNumberFromSpecs -SpecsDir $SpecsDir
$remoteBranches = $remoteRefs | Where-Object { $_ -match "refs/heads/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
if ($_ -match "refs/heads/(\d+)-") { # Take the maximum of both
[int]$matches[1] $maxNum = [Math]::Max($highestBranch, $highestSpec)
}
}
}
} catch {
# Ignore errors
}
# Check local branches
$localBranches = @()
try {
$allBranches = git branch 2>$null
if ($allBranches) {
$localBranches = $allBranches | Where-Object { $_ -match "^\*?\s*(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
if ($_ -match "(\d+)-") {
[int]$matches[1]
}
}
}
} catch {
# Ignore errors
}
# Check specs directory
$specDirs = @()
if (Test-Path $SpecsDir) {
try {
$specDirs = Get-ChildItem -Path $SpecsDir -Directory | Where-Object { $_.Name -match "^(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
if ($_.Name -match "^(\d+)-") {
[int]$matches[1]
}
}
} catch {
# Ignore errors
}
}
# Combine all sources and get the highest number
$maxNum = 0
foreach ($num in ($remoteBranches + $localBranches + $specDirs)) {
if ($num -gt $maxNum) {
$maxNum = $num
}
}
# Return next number # Return next number
return $maxNum + 1 return $maxNum + 1
} }
@@ -254,7 +210,7 @@ if ($ShortName) {
if ($Number -eq 0) { if ($Number -eq 0) {
if ($hasGit) { if ($hasGit) {
# Check existing branches on remotes # Check existing branches on remotes
$Number = Get-NextBranchNumber -ShortName $branchSuffix -SpecsDir $specsDir $Number = Get-NextBranchNumber -SpecsDir $specsDir
} else { } else {
# Fall back to local directory check # Fall back to local directory check
$Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1