Public/Save-GitWorktree.ps1
|
<#
.SYNOPSIS Stages all changes, commits, pushes, and then prunes the worktree. .DESCRIPTION Runs `git add -A`, commits with -Message, pushes the branch to origin, then changes location to the bare repo root and prunes the worktree entry. Use -NoPush to skip pushing (local commit only). Use -NoPrune to keep the worktree after pushing. .EXAMPLE Save-GitWorktree -Message "Fix login bug" .EXAMPLE Save-GitWorktree -Message "WIP" -NoPush -NoPrune #> function Save-GitWorktree { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Message, [Parameter()] [switch] $NoPush, [Parameter()] [switch] $NoPrune, # Open the pull/merge request creation page in the default browser after pushing. # Works with any hosting provider (GitHub, Azure DevOps, Bitbucket, GitLab, etc.). [Parameter()] [switch] $PullRequest, [Parameter()] [string] $Path = (Get-Location).Path ) $Path = (Resolve-Path $Path -ErrorAction Stop).Path $root = Get-GitRoot -Path $Path # Confirm this is actually a worktree (not the bare repo itself) $worktrees = Get-WorktreeList -RepoPath $root $entry = $worktrees | Where-Object { $_.Path -eq $Path -and -not $_.IsBare } if (-not $entry) { throw "'$Path' is not a non-bare worktree. Navigate into a worktree first." } $branch = $entry.Branch if (-not $branch) { throw "Worktree at '$Path' is in a detached HEAD state — cannot push." } if ($PSCmdlet.ShouldProcess($Path, "Stage, commit '$Message', push '$branch', and prune worktree")) { Write-Verbose "Staging all changes in $Path" git -C $Path add -A if ($LASTEXITCODE -ne 0) { throw "git add failed in '$Path'" } # Check if there's anything to commit $staged = git -C $Path diff --cached --name-only 2>$null if (-not $staged) { Write-Warning "Nothing staged to commit in '$Path'" } else { Write-Verbose "Committing: $Message" git -C $Path commit -m $Message if ($LASTEXITCODE -ne 0) { throw "git commit failed in '$Path'" } } if (-not $NoPush) { Write-Verbose "Pushing branch '$branch' to origin" git -C $Path push if ($LASTEXITCODE -ne 0) { throw "git push failed for branch '$branch'" } if ($PullRequest) { $remoteUrl = git -C $Path remote get-url origin 2>$null if ($remoteUrl) { $prUrl = Get-PullRequestUrl -RemoteUrl $remoteUrl -Branch $branch Write-Host "Opening PR: $prUrl" -ForegroundColor Cyan Start-Process $prUrl } else { Write-Warning "No remote 'origin' configured — cannot open pull request URL." } } } elseif ($PullRequest) { Write-Warning "-PullRequest has no effect when -NoPush is set." } if (-not $NoPrune) { Write-Verbose "Pruning worktree '$Path'" # cd to bare root before removing the worktree beneath us Set-Location $root git -C $root worktree remove $Path if ($LASTEXITCODE -ne 0) { Write-Warning "Push succeeded but worktree remove failed. Run: git worktree prune" } else { git -C $root worktree prune Write-Host "Worktree saved and removed: $Path" -ForegroundColor Green } } else { Write-Host "Committed and pushed from: $Path" -ForegroundColor Green } } } |