Skip to content

Instantly share code, notes, and snippets.

@kkoziarski
Last active April 7, 2024 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkoziarski/51ecacc66dcbe8018e441a530a75d85a to your computer and use it in GitHub Desktop.
Save kkoziarski/51ecacc66dcbe8018e441a530a75d85a to your computer and use it in GitHub Desktop.
Create git worktree from powershell
function Git-Worktree {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$BranchName,
[Parameter(Mandatory=$false)]
[switch]$Delete,
[Parameter(Mandatory=$false)]
[switch]$Current
)
function Resolve-GitRoot {
$dotGitpath = git rev-parse --path-format=absolute --git-common-dir #includes '.git' at the end
$gitTopLevel = Split-Path -Path $dotGitpath -Parent
if ($LASTEXITCODE -eq 0 -and $gitTopLevel) {
return $gitTopLevel
} else {
Write-Error "Not inside a git repository or unable to find the git repository root."
throw "Not a git repository (or any of the parent directories)"
}
}
try {
$gitRoot = Resolve-GitRoot
}
catch {
Write-Error "Error: $($_.Exception.Message)"
}
if ($BranchName -eq 'list') {
git worktree list
return;
}
if($BranchName -eq 'master') {
Write-Output "Switching to the root of the repository for main branch 'master' at '$gitRoot'"
Set-Location -Path $gitRoot
return
}
function Get-GitWorktrees {
$worktrees = git worktree list --porcelain | Where-Object { $_ -match '^worktree (.+)' } | ForEach-Object {
$Matches[1].Replace('\', '/')
}
return $worktrees
}
$existingWorktreePaths = Get-GitWorktrees
$worktreePath = Join-Path $gitRoot '.worktrees' $BranchName
if ($Delete) {
if (Test-Path -Path $worktreePath) {
try {
Write-Output "Switching to root"
Set-Location -Path $gitRoot
git worktree remove $worktreePath
if ($LASTEXITCODE -ne 0) {
throw "Could not remove worktree"
}
if (Test-Path -Path $worktreePath){
Remove-Item $worktreePath -Recurse
Write-Host "'$worktreePath' folder removed successfully."
}
Write-Output "Worktree for branch '$BranchName' has been removed."
} catch {
Write-Error "Error: Failed to remove worktree for branch '$BranchName' at '$worktreePath'."
}
} else {
Write-Output "No worktree for branch '$BranchName' at '$worktreePath' exists to remove."
}
return
}
$normalizedWorktreePath = $worktreePath.Replace('\', '/')
if ($existingWorktreePaths -like "*$normalizedWorktreePath*") {
Write-Output "Worktree for branch '$BranchName' already exists at '$worktreePath'. Switching to that directory."
Set-Location -Path $worktreePath
return
}
function Create-GitWorktree {
param (
[string]$BranchName,
[string]$WorktreePath,
[switch]$Current
)
git show-ref --quiet -- "refs/heads/$BranchName"
$branchExists = $LASTEXITCODE -eq 0
if (-not $branchExists) {
git ls-remote --quiet --exit-code origin "refs/heads/$BranchName" > $null
$branchExists = $LASTEXITCODE -eq 0
}
if ($branchExists) {
git worktree add $worktreePath $branchName
} else {
$checkoutBranch = $Current ? $null : ($branchExists ? $BranchName : 'master')
git worktree add -b $branchName $worktreePath $checkoutBranch
}
if ($LASTEXITCODE -ne 0) {
throw "Could not add new worktree for branch '$BranchName' at '$worktreePath'."
}
}
try {
Create-GitWorktree -BranchName $BranchName -WorktreePath $worktreePath -Current $Current
Write-Output "Worktree for branch '$BranchName' successfully created at '$worktreePath'."
Set-Location -Path $worktreePath
}
catch {
Write-Error "Error: Failed to create worktree for branch '$BranchName' and path '$worktreePath'."
}
}
Set-Alias worktree Git-Worktree
Set-Alias gw Git-Worktree
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment