git push --mirror Explained: What It Copies and Deletes
git push --mirror makes the destination's refs match the refs in the local mirror, including creating new refs, force-updating changed refs, and deleting destination refs that no longer exist locally. It is powerful for repository migration and replication, but it can remove data on the destination, so the command should be tested and aimed only at a repository intended to be a mirror.
What --mirror means
A normal git push usually updates a selected branch or the branches configured by a refspec. The --mirror option instead applies to all refs under the local refs/ namespace, which can include branches, tags, notes, and remote-tracking refs. The destination is made to resemble the local repository rather than merely receiving one new branch tip.
Mirroring is intentionally forceful. If a local ref was rewritten, Git attempts to force-update the corresponding destination ref, and if a local ref was deleted, Git attempts to delete it from the destination. This is correct for a controlled replica but dangerous for a shared repository containing independent work.
Start with a mirror clone
For repository duplication, begin with git clone --mirror rather than an ordinary working clone. A mirror clone is bare, maps the source refs for mirroring, and configures the repository for remote updates without creating a checked-out working tree.
git clone --mirror https://github.com/example/source.git
cd source.git
The resulting directory is intended for repository operations, not file editing. Inspect its remotes and refs before changing the push destination. Keep it in a protected temporary or automation workspace because it contains the repository's Git objects and configuration.
Push the mirror to a new destination
Create an empty destination repository and avoid initializing it with a README, license, or other independent commit. Then push the local mirror to the destination URL.
git push --mirror https://gitlab.com/example/destination.git
Authentication must permit repository writes and any force updates required by the mirror. If the destination rejects protected branch changes or provider-controlled refs, review the error instead of weakening security controls blindly. Hosted Git providers do not necessarily accept every ref present on another platform.
Preview with --dry-run
A dry run asks Git to report the updates it would attempt without sending them. Use it before the first mirror push and whenever the destination may contain work that should not be removed.
git push --mirror --dry-run https://gitlab.com/example/destination.git
Read the output for forced updates, new refs, and deletions. A dry run improves visibility but does not replace destination backups or access controls, and server-side policy can still produce a different final outcome when the real push is attempted. For a valuable destination, test the workflow in a disposable namespace first.
Understand destination deletions
Suppose the destination contains a branch named experiment, but no matching local ref exists in the mirror. A successful git push --mirror can delete that destination ref because the command treats the local ref set as authoritative. This is one of the most important differences between mirroring and simply pushing all local branches.
Do not point --mirror at a collaborative repository where people create destination-only branches or tags. Use a dedicated mirror project, restrict direct writes, and label it clearly so developers do not treat it as a second independent source. If work must happen on both sides, a one-way mirror command is not a conflict-resolution system.
Understand force updates
If a source branch history is rewritten, the mirror push attempts to reproduce that rewritten history on the destination. This can move a destination branch backward or replace commits that are no longer reachable from the local ref. Protected branch policies may reject the operation, causing the mirror to become stale until the policy or workflow is resolved.
Force behavior is useful during an exact migration because it makes the destination match the selected source. It also means a live mirror can copy an accidental or malicious force push. Historical archives, immutable snapshots, or another retained recovery point are needed when the goal includes restoring the state from before a destructive change.
Update an existing mirror later
To refresh the local mirror from its original source, fetch using the mirror's configured refspec and pruning behavior. Then push the updated ref set to the destination.
git remote update --prune
git push --mirror https://gitlab.com/example/destination.git
Run these commands only after confirming which remote is used for fetching and which URL receives the push. Automation should fail on errors, preserve useful logs, and avoid overlapping jobs for the same repository. A schedule without monitoring can leave a failed mirror unnoticed for a long time.
Use separate fetch and push URLs carefully
A mirror repository can be configured to fetch from the source and push to a different destination. This reduces the chance of accidentally pushing back into the source, but the configuration should be inspected and documented.
git remote set-url origin https://github.com/example/source.git
git remote set-url --push origin https://gitlab.com/example/destination.git
git remote -v
After setting the URLs, git remote update --prune reads from the fetch URL and a mirror-configured push targets the push URL. Always verify git remote -v in the automation environment because a reversed URL can turn a routine job into an unwanted overwrite attempt.
Compare --mirror, --all, and --tags
git push --all pushes refs under refs/heads/, which covers local branches but not every ref category. git push --tags adds tags, while git push --mirror attempts to synchronize all refs under refs/ and includes deletion and force-update behavior. These commands are not interchangeable even when a small repository makes their first results look similar.
For a one-time migration, pushing branches and tags separately may be easier to reason about when destination-only data must remain untouched. For an exact controlled replica, mirror semantics are usually more appropriate. Select the command based on the desired destination behavior rather than convenience.
Account for provider-specific refs
GitHub, GitLab, and Bitbucket can expose internal refs associated with pull requests, merge requests, or other platform features. A different provider may reject updates to those namespaces, and copying them does not recreate the corresponding user interface records. Provider metadata should be migrated through supported APIs or export tools when it is part of the requirement.
Do not assume that a successful Git push reproduced repository permissions, branch protection, webhooks, deployment keys, CI configuration, secrets, issues, or review history. Git mirroring preserves Git data, while provider application data requires a separate checklist. State that distinction in migration and recovery documentation.
Handle Git LFS separately
Git refs can point to files managed by Git Large File Storage, but the Git repository normally contains pointer objects rather than all large file content. A mirror operation that transfers refs does not automatically prove that every LFS object is available on the destination. Fetch and push LFS objects explicitly when the repository uses LFS.
git lfs fetch --all
git lfs push --all https://gitlab.com/example/destination.git
Provider support, quotas, authentication, and transfer limits still apply. Verify representative large files by cloning from the destination into a clean environment. A list of matching Git refs is not enough to validate LFS recovery.
Verify the mirror after pushing
Compare source and destination refs with git ls-remote, inspect important branch tips, and clone the destination independently. Automated comparison can identify missing or unexpected refs, while a clean clone confirms that the destination is usable by an ordinary developer.
git ls-remote https://github.com/example/source.git
git ls-remote https://gitlab.com/example/destination.git
Exact raw output may differ when providers expose internal refs that cannot or should not be copied. Define which namespaces are required and compare those intentionally. Record the last verified commit for critical branches as part of the migration or recovery log.
A mirror is not a historical backup
A continuously updated mirror provides a current secondary repository, but its accuracy can work against historical recovery. Deletions and rewritten refs from the source can be reproduced at the destination. Keep retained snapshots or archives if the organization needs to return to an earlier point in time.
The combination is stronger than either component alone. The live mirror helps the team resume work during an outage, while historical recovery points help after corruption, force pushes, or delayed discovery of a mistake. Test both paths before an incident.
Automate mirroring without owning every failure mode
A shell script can run the fetch and push commands, but production automation also needs secret management, job locking, retries, notifications, provider authentication, logs, scheduling, repository discovery, and retention. Those operational requirements grow quickly across many repositories and provider combinations.
GitReplica manages recurring repository bindings and synchronization history across supported providers and destinations. Teams can use it when they want mirror semantics without maintaining a separate automation stack, while still keeping a clear source of truth and testing recovery from the resulting destination.
Frequently asked questions
Does git push --mirror delete branches?
It can delete destination refs that do not exist in the local mirror. Use it only when the local ref set is intended to be authoritative for a dedicated mirror destination.
Is git push --mirror the same as pushing all branches?
No. --all targets local branches, while --mirror synchronizes the broader refs/ namespace and includes forced updates and deletions. Tags and provider-specific refs also require careful consideration.
Does git push --mirror copy pull requests and issues?
No. Pull requests, issues, comments, permissions, and most provider settings are application metadata rather than portable Git refs. Migrate them separately if they are required.
Can I use git push --mirror as my only backup?
It provides a current replica but can copy destructive changes. Combine it with retained historical archives or snapshots when point-in-time recovery matters.
Mirror semantics, without the automation stack.
Connect a source and a destination, and GitReplica keeps the mirror running with a full synchronization history.
Get started free