Last active
September 16, 2025 19:55
-
-
Save dirq/05903577e18ebb40b37f60a9a9b2b083 to your computer and use it in GitHub Desktop.
Clean up old local Git branches with smart archiving - renames old/merged branches with "old/" prefix instead of deleting them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Rename old local git branches script | |
| # | |
| # This script renames local git branches as follows: | |
| # - Branches not 'main', 'master', or the current branch | |
| # - Branches not already starting with 'old/' and not ending with 'release' | |
| # - If the branch has not had a commit in over the specified days, it is renamed to 'old/{branch}' | |
| # - If the branch has been merged into 'eagleeye-prod-release' or 'eagleeye-stage-release', it is renamed to 'old/merged/{branch}' | |
| # | |
| # Usage: | |
| # .\rename-old-local-git-branches.ps1 -FolderPath <path-to-git-repo> -DaysOld <days> [-DryRun] | |
| # -FolderPath: Path to the git repository (optional, defaults to current directory) | |
| # -DaysOld: Number of days since last commit to consider a branch old (optional, defaults to 30) | |
| # -DryRun: If specified, only print what would be renamed, do not actually rename branches | |
| param( | |
| [string]$FolderPath = (Get-Location), | |
| [int]$DaysOld = 30, | |
| [switch]$DryRun | |
| ) | |
| Set-Location -Path $FolderPath | |
| Write-Host "π Fetching latest branch info..." -ForegroundColor Cyan | |
| git fetch --prune 2>$null | Out-Null | |
| Write-Host "β Fetch complete!" -ForegroundColor Green | |
| $now = Get-Date | |
| $thresholdDate = $now.AddDays(-$DaysOld) | |
| $thresholdUnix = [int][double]::Parse($thresholdDate.ToUniversalTime().Subtract([datetime]'1970-01-01').TotalSeconds) | |
| if ($DryRun) | |
| { | |
| Write-Host "π§ͺ DRY RUN: No branches will be renamed." -ForegroundColor Magenta | |
| } | |
| $currentBranch = git branch --show-current | |
| $branches = git branch --format="%(refname:short)" | Where-Object { | |
| $_ -notin @("main", "master") ` | |
| -and $_ -ne $currentBranch ` | |
| -and -not $_.StartsWith("old/") ` | |
| -and -not $_.ToLower().EndsWith("release") | |
| } | |
| $mergedIntoProd = git branch --merged eagleeye-prod-release | ForEach-Object { $_.Trim() } | |
| $mergedIntoStage = git branch --merged eagleeye-stage-release | ForEach-Object { $_.Trim() } | |
| $mergedBranches = ($mergedIntoProd + $mergedIntoStage) | Select-Object -Unique | |
| Write-Host ("πΏ Current branch: {0}`nβ° Using threshold of {1} days ({2})" -f $currentBranch, $DaysOld, $thresholdDate) -ForegroundColor Magenta | |
| foreach ($branch in $branches) { | |
| $lastCommitUnix = git log -1 --format="%ct" $branch 2>$null | |
| $isMerged = $mergedBranches -contains $branch | |
| $isOld = $false | |
| $lastCommitDate = "N/A" | |
| # Parse commit timestamp safely | |
| if (![string]::IsNullOrWhiteSpace($lastCommitUnix) -and $lastCommitUnix.Trim() -ne "") { | |
| try { | |
| $commitUnixNum = [long]$lastCommitUnix.Trim() | |
| if ($commitUnixNum -gt 0) { | |
| # Convert Unix timestamp to DateTime using .NET method | |
| $epoch = [datetime]::new(1970, 1, 1, 0, 0, 0, [DateTimeKind]::Utc) | |
| $lastCommitDate = $epoch.AddSeconds($commitUnixNum).ToLocalTime() | |
| $isOld = $commitUnixNum -lt $thresholdUnix | |
| # Write-Host "DEBUG: Branch '$branch' - Unix: $commitUnixNum, Date: $lastCommitDate, IsOld: $isOld, Threshold: $thresholdUnix" -ForegroundColor Cyan | |
| } | |
| } | |
| catch [System.Exception] { | |
| # If parsing fails, keep defaults (N/A date, not old) | |
| Write-Host "β ERROR parsing timestamp '$lastCommitUnix' for branch '$branch': $($_.Exception.Message)" -ForegroundColor Red | |
| $lastCommitDate = "N/A" | |
| $isOld = $false | |
| } | |
| } else { | |
| Write-Host "π DEBUG: No commit timestamp found for branch '$branch'" -ForegroundColor Red | |
| } | |
| if ($isMerged) { | |
| $newBranch = "old/merged/$branch" | |
| Write-Host "π¦ [ARCHIVE MERGED] $branch -> $newBranch (last commit: $lastCommitDate, merged: $isMerged)" -ForegroundColor Yellow | |
| if (-not $DryRun) { | |
| git branch -m $branch $newBranch | |
| } | |
| } elseif ($isOld) { | |
| $newBranch = "old/$branch" | |
| Write-Host "ποΈ [ARCHIVE OLD] $branch -> $newBranch (last commit: $lastCommitDate, merged: $isMerged)" -ForegroundColor Yellow | |
| if (-not $DryRun) { | |
| git branch -m $branch $newBranch | |
| } | |
| } else { | |
| Write-Host "βοΈ [skip] $branch (last commit: $lastCommitDate, merged: $isMerged)" -ForegroundColor DarkGray | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment