Skip to content

Instantly share code, notes, and snippets.

@ychin
Last active January 16, 2022 17:36
Show Gist options
  • Save ychin/d9f83a8053ab4f2452b716123599eca3 to your computer and use it in GitHub Desktop.
Save ychin/d9f83a8053ab4f2452b716123599eca3 to your computer and use it in GitHub Desktop.
Powershell scripts to find the "parent" branch (aka the branch with the closest parent commit) to the current one.
@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
}
@ychin
Copy link
Author

ychin commented Jan 16, 2022

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment