fix: use global maximum for branch numbering to prevent collisions

The check_existing_branches (bash) and Get-NextBranchNumber (PowerShell)
functions were only looking for branches/specs matching the SAME short name
when determining the next feature number. This caused collisions where
multiple features could be assigned the same number if they had different
short names.

For example, if feature 023-ci-optimization existed, creating a new feature
with a different short name would incorrectly use 001 instead of 024.

This fix changes both functions to:
1. Use get_highest_from_branches() / Get-HighestNumberFromBranches to find
   the highest number across ALL branches globally
2. Use get_highest_from_specs() / Get-HighestNumberFromSpecs to find the
   highest number across ALL spec directories globally
3. Return the maximum of both + 1

The helper functions already existed but were not being used. This fix
properly utilizes them to ensure features are numbered sequentially
regardless of their short names.

Issue: Branch number collisions when creating features with different names
Impact: Prevents multiple features from sharing the same number prefix
This commit is contained in:
Joseph Mearman
2025-11-23 16:01:56 +00:00
parent f205fa3b58
commit 33df8976ca
2 changed files with 24 additions and 75 deletions

View File

@@ -104,66 +104,23 @@ function Get-NextBranchNumber {
[string]$ShortName,
[string]$SpecsDir
)
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
try {
git fetch --all --prune 2>$null | Out-Null
} catch {
# Ignore fetch errors
}
# Find remote branches matching the pattern using git ls-remote
$remoteBranches = @()
try {
$remoteRefs = git ls-remote --heads origin 2>$null
if ($remoteRefs) {
$remoteBranches = $remoteRefs | Where-Object { $_ -match "refs/heads/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
if ($_ -match "refs/heads/(\d+)-") {
[int]$matches[1]
}
}
}
} 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
}
}
# Get highest number from ALL branches (not just matching short name)
$highestBranch = Get-HighestNumberFromBranches
# Get highest number from ALL specs (not just matching short name)
$highestSpec = Get-HighestNumberFromSpecs -SpecsDir $SpecsDir
# Take the maximum of both
$maxNum = [Math]::Max($highestBranch, $highestSpec)
# Return next number
return $maxNum + 1
}