-
-
Save ychin/d9f83a8053ab4f2452b716123599eca3 to your computer and use it in GitHub Desktop.
@powershell -NoProfile -File %~dp0findParentBranch.ps1 %* |
<# | |
.SYNOPSIS | |
Find the "parent" branch of the current branch. | |
.PARAMETER BranchName | |
If provided, will search for `BranchName` instead of the current branch in the repo. | |
.PARAMETER FindAll | |
Provide the list of all parent and found grandparent branches. Otherwise it will only find the immediate parent. | |
.DESCRIPTION | |
This script is not fool-proof as it's mostly a guess since Git doesn't really know the difference between parent and children branches. It uses "git show-branch", so it will use whatever short name the command decides to name a commit to compute which one is the parent branch. | |
#> | |
Param | |
( | |
[Parameter(Position=0)] | |
[string] $BranchName, | |
[switch] $FindAll | |
) | |
$pinfo = New-Object System.Diagnostics.ProcessStartInfo | |
$pinfo.FileName = "git" | |
$pinfo.RedirectStandardOutput = $true | |
$pinfo.UseShellExecute = $false | |
$pinfo.Arguments = "show-branch --current --topo-order --no-color" | |
$p = New-Object System.Diagnostics.Process | |
$p.StartInfo = $pinfo | |
$p.Start() | Out-Null | |
$stdout = $p.StandardOutput | |
$currentBranchIndex = 0 | |
$currentBranchName = "" | |
$currentBranchFound = $false | |
$allBranchesListed = $false | |
$foundBranch = "" | |
$foundBranches = @{} | |
while ( ($stdout -ne $null) -and (($line = $stdout.ReadLine()) -ne $null) ) | |
{ | |
if (-not $currentBranchFound) | |
{ | |
if ($BranchName -eq "") | |
{ | |
if ($line.Length -gt $currentBranchIndex -and $line[$currentBranchIndex] -eq '*') | |
{ | |
$currentBranchFound = $true | |
# 1) Branch names can contain ']', but not spaces, and the string pattern here is "[<branch_name>] <description>", so search for "] " which will guarantee we find the delimiter rather than part of a branch name. | |
# 2) Use non-greedy (.*?) matching so that commit descriptions that contain "] " wouldn't mess up the search. | |
if ($line -match '\[(.*?)\] ') | |
{ | |
$currentBranchName = $Matches[1] | |
} | |
else | |
{ | |
Write-Host "Error: Couldn't parse current branch info from Git" | |
$stdout.Close() | |
if (-not $p.HasExited) | |
{ | |
$p.Kill() | |
} | |
exit -1 | |
} | |
} | |
else | |
{ | |
$currentBranchIndex += 1 | |
} | |
} | |
else | |
{ | |
if ($line -match '\[(.*?)\] ' -and $Matches[1] -eq $BranchName) | |
{ | |
$currentBranchName = $BranchName | |
$currentBranchFound = $true | |
} | |
else | |
{ | |
$currentBranchIndex += 1 | |
} | |
} | |
} | |
if ($line -match '^-*$') | |
{ | |
if (-not $currentBranchFound) | |
{ | |
Write-Host "Couldn't find the current branch." | |
$stdout.Close() | |
if (-not $p.HasExited) | |
{ | |
$p.Kill() | |
} | |
exit -1 | |
} | |
$allBranchesListed = $true | |
} | |
elseif ($allBranchesListed) | |
{ | |
if ($line[$currentBranchIndex] -ne ' ') | |
{ | |
if ($line -match '\[(.*?)(\] |~|\^)') | |
{ | |
$lineBranch = $Matches[1] | |
if ($lineBranch -ne $currentBranchName) | |
{ | |
$foundBranch = $lineBranch | |
if (-not $foundBranches[$foundBranch]) | |
{ | |
$foundBranches[$foundBranch] = $true | |
Write-Host $foundBranch | |
if (-not $FindAll) | |
{ | |
break | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
$stdout.Close() | |
if (-not $p.HasExited) | |
{ | |
$p.Kill() | |
} | |
if ($foundBranch -eq "") | |
{ | |
Write-Host "Couldn't find parent branch." | |
exit -1 | |
} |
You'd better use bash or any well spread portable scripting language like python.
That's fair, except Python is not guaranteed to be installed on a Windows machine, but PowerShell is. So if you write a script that you want to be guaranteed to work on others' Windows boxes without needing extra dependencies (WSL is a dependency), PowerShell is the way to go. Same reason why people write complicated bash scripts for *nix systems instead of Python/etc when you are trying to maximize compatibility.
If you use PowerShell in Windows as an actual shell, scripts written in PowerShell also gets auto-complete for free, which a script written in other languages don't. It's all about knowing what audience you want for a particular tool and what environments they will be run in.
Scripting git commands is a prime example of where powershell makes little sense
Also, bash isn't that great with Git anyway IMO. You end up scripting complicated awk / sed / grep chains that would make the script much more complicated and unreadable than the PowerShell script here, which can just do regex builtin and loop through each line. My personal opinion is bash / zsh are designed primarily for interactive use, whereas their scripting ability and syntax are actually quite poor, and most people only write bash scripts since it's available everywhere. Python is probably a good choice for a script like this, but there are compatibility issues as I discussed if you are targeting Windows users (which I was at the time).
Heh, let's check what a shell has to be then.
I totally agree that powershell is actually better described as a scripting language like perl, python, etc.
A shell is what the user is interacting with.
One of the things a user does is starting programs, binaries, in separate processes. On Unices, the user also wants to combine programs though pipes without having to become a programmer, so the shell has to make that easy to do.
Now, powershell ceases to be a shell as soon as you want to use programs that haven't been designed and written in or for powershell. It's a closed ecosystem, severed from the world.
Scripting git commands is a prime example of where powershell makes little sense. You'd better use bash or any well spread portable scripting language like python.