Rename a local and remote Git branch
Rename the local Git branch first, then push the new name and delete the old remote name when that deletion is appropriate. A local rename does not itself rename the remote branch, and the upstream setting must point to the intended remote reference afterward.
Rename local and remote Git branch names
Rename the local branch, push the new remote name, and delete the old remote name only when appropriate. A local rename by itself leaves the remote reference unchanged. The branch reference documents the move operation, while the push reference describes updating remote references12. They are separate operations, which is why a renamed local branch can still track the old remote name immediately afterward.
The example checks out a fictional branch, publishes it to a local bare remote, records its tip and renames the checked-out local branch. It then verifies the same tip and inspects the upstream name. That check comes before the new remote branch is pushed: at that moment the upstream still points to the old remote name. The script subsequently pushes the new name, sets it as upstream and deletes the old remote reference.
Check the people and settings affected
Before any real remote deletion, identify the branch and ask whether its old name is used by other work. A teammate may have an existing checkout or automation may refer to the old name. Communicating an intended change and inspecting the destination are practical preparation; the local fixture does not test another person’s repository or a hosted service’s settings.
The remote in this example is a bare directory created solely for the test. Its main branch is not the branch being deleted. A real server may reject creation or deletion, or may attach settings to a branch name. Do not infer from this local success that a hosted default branch, protection rule or integration will update automatically. Follow the relevant service’s current documentation and team process for those cases.
Understand the first boundary
The local rename does not create a remote branch. In the example, the current commit identifier is checked before and after the rename, and the upstream still names the previous remote branch. The check is useful because it distinguishes the local name from both the commit and its remote-tracking relationship. A branch can move later as commits are added; the assertion concerns only this rename step.
The script does not use an overwrite option to force a rename over an existing local branch. If the desired name already exists, stop and determine what it points to before choosing another action. Overwriting a reference can make work harder to find, and a name collision is not evidence that the two histories are interchangeable. Inspect the state and retain any needed reference before doing more.
Update the remote in two actions
Pushing the new branch name creates or updates that remote reference. Deleting the old name is a separate request. The example checks both results directly against its local bare remote, and checks that the local upstream now identifies the new remote-tracking branch. These assertions show the final state of this fixture; they do not show that links, invitations or build configuration elsewhere have been updated.
The order matters for the example’s stated goal. The new reference is present before the old one is removed, so the checked commit remains named by the new remote branch. In a real workflow, confirm the new reference and its intended upstream before asking to remove the old name. A failed push or rejected deletion should be read as an incomplete operation, not as a successful rename.
Recheck after the change
After updating both sides, verify the current branch, its upstream and the remote’s advertised references. Then inspect any local worktrees and collaborators that may still refer to the old name. A local rename does not rewrite another clone’s configuration. Someone else may need to fetch the new reference and make an informed local change; the details depend on the state of that clone.
This page does not claim that renaming a branch changes the commit content, repairs history or migrates service-specific settings. It also does not encourage deleting a remote branch simply because the local branch was renamed. Preserve an old reference when its removal is not authorized or its consumers are unknown. The example’s deletion is limited to a newly created, fictional local remote.
If a check fails halfway through, identify which reference operations actually succeeded before retrying. The new remote name may already exist even when the old name is still present. Treat that intermediate state as evidence to inspect, not a reason to repeat a deletion without confirming its target. Keep the local commit accessible while deciding how to proceed.
Run the complete local example
Before running: Deleting a remote branch can affect other people and automation. The deletion below targets only the fictional local bare remote. Run this complete MIT-licensed example with Git 2.56.0 in an empty directory. It creates rename-example/, including its own local bare remote. It performs no network access and refuses to reuse an existing example directory.
Download the complete example. The printed file is the one that ran.
#!/bin/sh
# SPDX-License-Identifier: MIT
set -eu
export TZ=UTC LC_ALL=C
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author' GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME='Example Author' GIT_COMMITTER_EMAIL='author@example.invalid'
export GIT_AUTHOR_DATE='2026-10-27T12:00:00+00:00'
export GIT_COMMITTER_DATE='2026-10-27T12:00:00+00:00'
test "$(git version)" = 'git version 2.56.0'
mkdir rename-example
cd rename-example
git init --template= --bare -q --initial-branch=main origin.git
git init --template= -q --initial-branch=main repo
cd repo
printf 'base\n' > note.txt
git add note.txt
git commit -qm 'Base'
git remote add origin ../origin.git
git push -q -u origin main >/dev/null
git switch -qc old-name
printf 'topic\n' >> note.txt
git commit -qam 'Topic work'
git push -q -u origin old-name >/dev/null
before=$(git rev-parse HEAD)
git branch -m new-name
test "$(git rev-parse HEAD)" = "$before"
test "$(git branch --show-current)" = new-name
test "$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}')" = origin/old-name
printf 'Local name changed; upstream still names origin/old-name\n'
git push -q -u origin new-name >/dev/null
git push -q origin --delete old-name
test "$(git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}')" = origin/new-name
git --git-dir=../origin.git show-ref --verify --quiet refs/heads/new-name
test "$(git --git-dir=../origin.git rev-parse refs/heads/new-name)" = "$before"
if git --git-dir=../origin.git show-ref --verify --quiet refs/heads/old-name; then exit 1; fi
printf 'Remote has new-name; old-name was deleted; upstream updated\n'
Both runs produced:
Local name changed; upstream still names origin/old-name
Remote has new-name; old-name was deleted; upstream updated
The script leaves its example directory and its repositories in place. Remove that newly created directory when it is no longer needed; inspect the name first so cleanup does not remove another project. The assertions stop the run if the demonstrated state differs. No command in the example connects to an external remote.
Not covered on this page
- Hosted default-branch changes, protection rules, pull requests or service-specific settings.
- Renaming or overwriting an existing branch with a conflicting name.
- Changing another person’s clone or coordinating a real shared branch.
Sources
-
Git 2.56.0 branch reference. Git v2.56.0; checked 27 October 2026 UTC. ↩
-
Git 2.56.0 push reference. Git v2.56.0; checked 27 October 2026 UTC. ↩
How we test: methodology. Found a mistake? Corrections.