Skip to content

Instantly share code, notes, and snippets.

@readingdancer
Created July 3, 2025 06:26
Show Gist options
  • Select an option

  • Save readingdancer/7ec5825923dc5e78104818bad67fabfe to your computer and use it in GitHub Desktop.

Select an option

Save readingdancer/7ec5825923dc5e78104818bad67fabfe to your computer and use it in GitHub Desktop.
A PowerShell script that automatically rebases multiple pull request branches that were created from a specific old dev commit onto the latest dev branch.
param(
[Parameter(Position=0, Mandatory=$false)]
[string]$OldDevCommit,
[switch]$DryRun
)
function Show-Help {
Write-Host "Usage: .\Rebase-PRs.ps1 <old-dev-commit> [-DryRun]"
Write-Host ""
Write-Host "Example:"
Write-Host " .\Rebase-PRs.ps1 abc123def4567890"
Write-Host ""
Write-Host "Options:"
Write-Host " -DryRun Show what would happen without changing anything."
Write-Host ""
Write-Host "This script rebases only PR branches branched from the specified old dev commit"
Write-Host "onto the latest dev branch and updates them on the remote."
Write-Host ""
Write-Host "Note: This script will never operate on the 'main' branch for safety."
}
if (-not $OldDevCommit) {
Show-Help
exit 1
}
$remote = "origin"
$devBranch = "dev"
$mainBranch = "main"
$protectedBranches = @($devBranch, $mainBranch)
$ErrorActionPreference = "Stop"
# Safety check: Ensure we're not currently on main branch
$currentBranch = git rev-parse --abbrev-ref HEAD
if ($currentBranch -eq $mainBranch) {
Write-Host "❌ Error: Currently on '$mainBranch' branch. This script will not operate on the main branch for safety."
Write-Host "Please switch to a different branch before running this script."
exit 1
}
Write-Host "Using old dev commit: $OldDevCommit"
if ($DryRun) {
Write-Host "Running in DRY RUN mode..."
}
Write-Host "`nFetching latest $devBranch..."
git checkout $devBranch
git fetch $remote
git pull $remote $devBranch
Write-Host "`nBuilding list of remote branches..."
$remoteBranches = git ls-remote --heads $remote | ForEach-Object {
($_ -split "refs/heads/")[-1].Trim()
} | Where-Object {
# Exclude protected branches (dev and main)
$_ -notin $protectedBranches
}
if (-not $remoteBranches) {
Write-Host "No remote branches found (excluding protected branches: $($protectedBranches -join ', ')). Exiting."
exit 0
}
Write-Host "Found these remote branches (excluding protected branches):`n$($remoteBranches -join "`n")"
foreach ($branch in $remoteBranches) {
Write-Host "`nProcessing branch: $branch"
# Additional safety check: Never process main branch
if ($branch -eq $mainBranch) {
Write-Host " ⚠️ Skipping '$mainBranch' branch for safety (this should not happen due to filtering)."
continue
}
# Fetch the branch tip from the remote (safer and simpler)
git fetch $remote $branch
# Compute fork point with dev
$forkPoint = git merge-base "$remote/$branch" $devBranch
Write-Host " -> Fork point is $forkPoint"
if ($forkPoint -eq $OldDevCommit) {
Write-Host " -> Branch $branch was based on old dev ($OldDevCommit)."
if ($DryRun) {
Write-Host " [DryRun] Would rebase $branch onto latest dev and push."
continue
}
# Create or update local branch tracking the remote tip
if (git show-ref --verify --quiet "refs/heads/$branch") {
git branch -f "$branch" "$remote/$branch"
} else {
git branch "$branch" "$remote/$branch"
}
# Final safety check before checkout
if ($branch -eq $mainBranch) {
Write-Host " ❌ Error: Attempted to checkout '$mainBranch' branch. Skipping for safety."
continue
}
git checkout "$branch"
try {
git rebase $devBranch
} catch {
Write-Host " !! Conflict occurred while rebasing $branch. Resolve manually."
exit 1
}
git push $remote "$branch" --force-with-lease
Write-Host " -> Rebased and pushed $branch successfully."
} else {
Write-Host " -> Skipping $branch (fork point doesn't match old dev)."
}
}
Write-Host "`n✅ Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment