Skip to content

Instantly share code, notes, and snippets.

@michaelkc
Last active October 26, 2020 08:26
Show Gist options
  • Save michaelkc/d44b4dd79770a4624e8d28fdc47c8559 to your computer and use it in GitHub Desktop.
Save michaelkc/d44b4dd79770a4624e8d28fdc47c8559 to your computer and use it in GitHub Desktop.
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$git = "git.exe"
$master = "master"
$protectedBranches = "$master|main"
# This script was adapted from ZSH script at
# https://blog.takanabe.tokyo/en/2020/04/remove-squash-merged-local-git-branches/
# It is supplemented with code to track and pull all remote branches, to make sure all
# remote branches ready for deletion are accounted for
# It outputs the commands needed to delete the remote branches matching the ones it
# deletes locally.
function track_all_remote_branches() {
$localBranches = &$git branch -l | Foreach-Object { $_.Trim() }
&$git branch -r |
Foreach-Object { $_.Trim() } |
Where-Object { -not ($_ -match '\->') } |
Where-Object { -not ($_ -match "(^\*|$protectedBranches)") } |
ForEach-Object {
$local = $_ -Replace 'origin/', ''
if ($localBranches.Contains($local)) {
Write-Host "Already tracking $_"
}
else {
Write-Host "Tracking $_"
&$git branch --track "$local" "$_"
}
}
&$git fetch --all
&$git pull --all
}
function git_prune_remote() {
Write-Host "Start removing out-dated remote merged branches"
&$git fetch --prune | Out-Null
Write-Host "Finish removing out-dated remote merged branches"
}
function git_remove_merged_local_branch() {
Write-Host "Start removing out-dated local merged branches"
$mergedLocalBranches = &$git branch --merged | Where-Object { -not ($_ -match "(^\*|$protectedBranches)") }
$deletedBranches = New-Object System.Collections.Generic.List[string]
foreach ($branch in $mergedLocalBranches) {
$branch = $branch.Trim()
$deletedBranches.Add($branch)
Write-Host "Removing $branch locally"
&$git branch -D $branch | Out-Null
}
Write-Host "Finish removing out-dated local merged branches"
return $deletedBranches
}
# When we use `Squash and merge` on GitHub,
# `&$git branch --merged` cannot detect the squash-merged branches.
# As a result, git_remove_merged_local_branch() cannot clean up
# unused local branches. This function detects and removes local branches
# when remote branches are squash-merged.
#
# There is an edge case. If you add suggested commits on GitHub,
# the contents in local and remote are different. As a result,
# This clean up function cannot remove local squash-merged branch.
function git_remove_squash_merged_local_branch() {
Write-Host "Start removing out-dated local squash-merged branches"
&$git checkout -q $master
$branches = &$git for-each-ref refs/heads/ "--format=%(refname:short)"
$deletedBranches = New-Object System.Collections.Generic.List[string]
foreach ($branch in $branches) {
#Write-Host $branch
$ancestor = $(&$git merge-base $master $branch)
#Write-Host "A: $ancestor"
$rp = &$git rev-parse "$branch^{tree}"
#Write-Host "RP: $rp"
$ct = &$git commit-tree "$rp" -p $ancestor -m _
#Write-Host "CT: $ct"
$cherry = &$git cherry $master "$ct"
#Write-Host "Cherry: $cherry"
if ($cherry -match "\-.*") {
Write-Host "Removing $branch locally"
&$git branch -D $branch | Out-Null
$deletedBranches.Add($branch)
}
}
Write-Host "Finish removing out-dated local squash-merged branches"
return $deletedBranches
}
# Clean up remote and local branches
track_all_remote_branches
git_prune_remote
$mergedBranches = git_remove_merged_local_branch
$squashMergedBranches = git_remove_squash_merged_local_branch
Write-Host "Script to delete remote branches"
foreach ($b in ($mergedBranches + $squashMergedBranches | Select-Object -uniq)) {
Write-Output "git push origin --delete $b"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment