Skip to content

Commit 4eda983

Browse files
authored
fix: count worktree branches in git extension numbering (#3054)
* fix: count worktree branches in git extension numbering * fix: preserve literal plus branch prefixes
1 parent afff4eb commit 4eda983

3 files changed

Lines changed: 62 additions & 2 deletions

File tree

extensions/git/scripts/bash/create-new-feature-branch.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ get_highest_from_specs() {
127127

128128
# Function to get highest number from git branches
129129
get_highest_from_branches() {
130-
git branch -a 2>/dev/null | sed 's/^[* ]*//; s|^remotes/[^/]*/||' | _extract_highest_number
130+
git branch -a 2>/dev/null | sed -E 's/^[+*][[:space:]]+//; s/^[[:space:]]+//; s|^remotes/[^/]*/||' | _extract_highest_number
131131
}
132132

133133
# Extract the highest sequential feature number from a list of ref names (one per line).

extensions/git/scripts/powershell/create-new-feature-branch.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ function Get-HighestNumberFromBranches {
8888
$branches = git branch -a 2>$null
8989
if ($LASTEXITCODE -eq 0 -and $branches) {
9090
$cleanNames = $branches | ForEach-Object {
91-
$_.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', ''
91+
$_.Trim() -replace '^[+*]?\s+', '' -replace '^remotes/[^/]+/', ''
9292
}
9393
return Get-HighestNumberFromNames -Names $cleanNames
9494
}

tests/extensions/git/test_git_extension.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ def _write_config(project: Path, content: str) -> Path:
8989
return config_path
9090

9191

92+
def _add_sibling_worktree(project: Path, path: Path, branch: str) -> None:
93+
"""Add a sibling worktree so `git branch -a` marks it with `+`."""
94+
subprocess.run(
95+
["git", "worktree", "add", "-q", "-b", branch, str(path), "HEAD"],
96+
cwd=project,
97+
check=True,
98+
capture_output=True,
99+
text=True,
100+
)
101+
102+
92103
# Git identity env vars for CI runners without global git config
93104
_GIT_ENV = {
94105
"GIT_AUTHOR_NAME": "Test User",
@@ -312,6 +323,40 @@ def test_increments_from_existing_specs(self, tmp_path: Path):
312323
data = json.loads(result.stdout)
313324
assert data["FEATURE_NUM"] == "003"
314325

326+
def test_dry_run_counts_branches_checked_out_in_worktrees(self, tmp_path: Path):
327+
"""Branches checked out in sibling worktrees still reserve their prefix."""
328+
project = _setup_project(tmp_path / "project")
329+
_add_sibling_worktree(project, tmp_path / "sibling-worktree", "007-worktree-feature")
330+
331+
result = _run_bash(
332+
"create-new-feature-branch.sh", project,
333+
"--json", "--dry-run", "--short-name", "next", "Next feature",
334+
)
335+
336+
assert result.returncode == 0, result.stderr
337+
data = json.loads(result.stdout)
338+
assert data["BRANCH_NAME"] == "008-next"
339+
assert data["FEATURE_NUM"] == "008"
340+
341+
def test_dry_run_preserves_literal_plus_branch_prefix(self, tmp_path: Path):
342+
"""A literal leading plus in a branch name is not a git worktree marker."""
343+
project = _setup_project(tmp_path)
344+
subprocess.run(
345+
["git", "branch", "+007-plus-prefix"],
346+
cwd=project,
347+
check=True,
348+
)
349+
350+
result = _run_bash(
351+
"create-new-feature-branch.sh", project,
352+
"--json", "--dry-run", "--short-name", "next", "Next feature",
353+
)
354+
355+
assert result.returncode == 0, result.stderr
356+
data = json.loads(result.stdout)
357+
assert data["BRANCH_NAME"] == "001-next"
358+
assert data["FEATURE_NUM"] == "001"
359+
315360
def test_no_git_graceful_degradation(self, tmp_path: Path):
316361
"""create-new-feature-branch.sh works without git (outputs branch name, skips branch creation)."""
317362
project = _setup_project(tmp_path, git=False)
@@ -351,6 +396,21 @@ def test_creates_branch_sequential(self, tmp_path: Path):
351396
data = json.loads(result.stdout)
352397
assert data["BRANCH_NAME"] == "001-user-auth"
353398

399+
def test_dry_run_counts_branches_checked_out_in_worktrees(self, tmp_path: Path):
400+
"""Branches checked out in sibling worktrees still reserve their prefix."""
401+
project = _setup_project(tmp_path / "project")
402+
_add_sibling_worktree(project, tmp_path / "sibling-worktree", "007-worktree-feature")
403+
404+
result = _run_pwsh(
405+
"create-new-feature-branch.ps1", project,
406+
"-Json", "-DryRun", "-ShortName", "next", "Next feature",
407+
)
408+
409+
assert result.returncode == 0, result.stderr
410+
data = json.loads(result.stdout)
411+
assert data["BRANCH_NAME"] == "008-next"
412+
assert data["FEATURE_NUM"] == "008"
413+
354414
def test_creates_branch_timestamp(self, tmp_path: Path):
355415
"""Extension create-new-feature-branch.ps1 creates timestamp branch."""
356416
project = _setup_project(tmp_path)

0 commit comments

Comments
 (0)