Public/New-GitWorktree.ps1
|
<#
.SYNOPSIS Creates a new git worktree with a prefixed branch name. .DESCRIPTION Creates a worktree adjacent to the bare repo directory with a branch named <prefix>/<author>/<slug>[-<descriptionSlug>] for development paths (feature, bug, temp), or <prefix>/<slug> for production paths (hotfix, release). The author segment is derived from $env:GIT_USER_SHORTNAME, then `git config user.name`, then $env:USERNAME (first non-empty wins). Use -NoAuthor to suppress. Prefix is determined by the chosen parameter set. .EXAMPLE New-GitWorktree -Feature "user-auth" -Description "Add OAuth login" # branch: feature/snkemp/user-auth-add-oauth-login # worktree: ..\feature\snkemp\user-auth-add-oauth-login .EXAMPLE New-GitWorktree -Hotfix "2.1.1" -SourceBranch main # branch: hotfix/2.1.1 (no author — production path) .EXAMPLE New-GitWorktree -Release "3.0.0" # branch: release/3.0.0 .EXAMPLE New-GitWorktree -Bug "null-ref" -NoAuthor # branch: bug/null-ref (author suppressed) .EXAMPLE New-GitWorktree -Feature "login" -OpenTerminal # Creates worktree and opens a new terminal window in that directory. .EXAMPLE New-GitWorktree -Feature "login" -NoSolution # Creates worktree without opening any detected solution file. #> function New-GitWorktree { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Feature')] param( [Parameter(Mandatory, ParameterSetName = 'Feature', Position = 0)] [string] $Feature, [Parameter(Mandatory, ParameterSetName = 'Hotfix', Position = 0)] [string] $Hotfix, [Parameter(Mandatory, ParameterSetName = 'Release', Position = 0)] [string] $Release, [Parameter(Mandatory, ParameterSetName = 'Bug', Position = 0)] [string] $Bug, [Parameter(Mandatory, ParameterSetName = 'Temp', Position = 0)] [string] $Temp, [Parameter()] [string] $Description, [Parameter()] [string] $SourceBranch, # Suppress author segment on dev-path branches (feature/bug/temp) [Parameter()] [switch] $NoAuthor, # Open a new terminal window in the created worktree directory [Parameter()] [switch] $OpenTerminal, # Suppress auto-opening any .sln/.slnx file found in the worktree [Parameter()] [switch] $NoSolution, [Parameter()] [string] $RepoPath = (Get-Location).Path ) # Resolve bare repo root $root = Get-GitRoot -Path $RepoPath # Determine prefix, raw name, and whether this is a production path $isProdPath = $false switch ($PSCmdlet.ParameterSetName) { 'Feature' { $prefix = 'feature'; $rawName = $Feature } 'Hotfix' { $prefix = 'hotfix'; $rawName = $Hotfix; $isProdPath = $true } 'Release' { $prefix = 'release'; $rawName = $Release; $isProdPath = $true } 'Bug' { $prefix = 'bug'; $rawName = $Bug } 'Temp' { $prefix = 'temp'; $rawName = $Temp } } $slug = ConvertTo-SafeBranchName -Name $rawName if ($Description) { $descSlug = ConvertTo-SafeBranchName -Name $Description $slug = "$slug-$descSlug" } # Include author segment for non-production paths (unless suppressed) if (-not $isProdPath -and -not $NoAuthor) { $authorSlug = Get-GitAuthorSlug -RepoPath $root $branchName = "$prefix/$authorSlug/$slug" } else { $branchName = "$prefix/$slug" } # Resolve source branch — default to repo's HEAD symbolic ref if (-not $SourceBranch) { $SourceBranch = git -C $root symbolic-ref --short HEAD 2>$null if ($LASTEXITCODE -ne 0 -or -not $SourceBranch) { foreach ($candidate in @('main', 'master')) { $exists = git -C $root branch --list $candidate 2>$null if ($exists) { $SourceBranch = $candidate; break } } } if (-not $SourceBranch) { throw "Could not determine a default source branch. Use -SourceBranch." } } # Worktree lives adjacent to the bare repo, under <prefix>[/<author>]/<slug> $wtDir = Join-Path (Split-Path $root -Parent) $branchName if ($PSCmdlet.ShouldProcess($wtDir, "Create worktree for branch '$branchName' off '$SourceBranch'")) { $wtParent = Split-Path $wtDir -Parent if (-not (Test-Path $wtParent)) { New-Item -ItemType Directory -Path $wtParent -Force | Out-Null } Write-Verbose "Creating branch '$branchName' from '$SourceBranch'" git -C $root worktree add -b $branchName $wtDir $SourceBranch if ($LASTEXITCODE -ne 0) { throw "Failed to create worktree at '$wtDir' for branch '$branchName'" } git config --global --add safe.directory $wtDir 2>$null Write-Host "Worktree created : $wtDir" -ForegroundColor Green Write-Host "Branch : $branchName" -ForegroundColor Cyan if (-not $NoSolution) { Open-WorktreeSolution -WorktreePath $wtDir } if ($OpenTerminal) { Open-WorktreeTerminal -WorktreePath $wtDir } return [PSCustomObject]@{ Path = $wtDir; Branch = $branchName; SourceBranch = $SourceBranch } } } |