./git-rename-branch.sh --current
File: /tmp/git-rename-branch.sh — a comprehensive script demonstrating all 5 Git branch rename scenarios with full edge-case handling.
git branch -m <new-name>
# or via the script:
./git-rename-branch.sh --current <new-name>
git branch -m <old-name> <new-name>
# or:
./git-rename-branch.sh <old-name> <new-name>
The script auto-detects if old-name == current branch and uses the single-arg form.
# Manual:
git branch -m <new-name>
git push -u origin <new-name>
git push origin --delete <old-name>
# Script (one command):
./git-rename-branch.sh --push <old> <new> [remote]
git push origin --delete <old-name>
git remote prune origin # clean up local tracking refs
# Script:
./git-rename-branch.sh --delete-remote <old> [remote]
# Full sequence:
git branch -m master main
git push -u origin main
git push origin --delete master
# Then in GitHub/GitLab: Settings → Branches → change default to "main"
git remote prune origin
# Script (one command):
./git-rename-branch.sh --master-to-main [remote]
The script also handles git check-ref-format validation, detached HEAD detection, same-name no-ops, non-existent branches, and already-on-main scenarios.
All **23 tests pass** across 10 test suites covering every edge case:
| # | Test | Result |
|---|------|--------|
| 1 | Rename current branch | ✓ old branch gone, new exists, on new branch |
| 2 | Rename non-current branch | ✓ old gone, new exists, stayed on original |
| 3 | Rename + push + set upstream + delete remote | ✓ local, remote, and upstream all correct |
| 4 | Delete stale remote branch | ✓ remote ref removed |
| 5 | Master → Main migration (with remote) | ✓ master gone, main exists, remote master deleted, upstream set |
| 6 | Rename to same name | ✓ graceful no-op |
| 7 | Detached HEAD | ✓ prevented with clear error |
| 8 | Non-existent branch | ✓ fails gracefully |
| 9 | Invalid branch name (`.lock`) | ✓ rejected by `git check-ref-format` |
| 10 | Already on main before migration | ✓ no-op detected |
Edge cases verified:
- **Bare remote refuses to delete HEAD branch**: handled with `receive.denyDeleteCurrent` config note in script output
- **Branch name validation**: uses `git check-ref-format` — catches `..`, spaces, `~^:?*[\`, leading `.`, trailing `.lock`, `@{`
- **Tracking branch format**: upstream stored as `origin/branch` not `refs/remotes/origin/branch`
- **Remote doesn't exist**: skipped gracefully
- **Already on target name**: early return with no-op
---{"model": "deepseek-v4-flash", "problem_class": "so-git-branch-rename", "result": "passed", "tests": 23}