Repository navigation
Recovery
GitHub Mirror Backup creates bare Git mirrors that can be used to restore repositories after accidental deletion, repository corruption, migration, or loss of access.
A mirror contains the Git repository's refs and objects, but it is not a normal working directory.
There are two common recovery scenarios:
- Restore a working copy from a mirror
- Restore the repository itself to GitHub or another Git server
If you simply need the source code again, clone directly from the mirror:
git clone /path/to/repository.gitFor example:
git clone /volume1/Archivum/project.gitThis creates a normal working directory:
project/
├── .git/
├── src/
├── README.md
└── ...
You can then continue working normally.
If the original GitHub repository was deleted or needs to be recreated, first create an empty repository on GitHub.
Do not initialize it with:
- README
.gitignore- license
- any other files
The new repository should be completely empty.
For example:
github.com/USERNAME/project
Then push the mirror to the new repository.
From the backup machine:
git --git-dir=/path/to/project.git push --mirror git@github.com:USERNAME/project.gitExample:
git --git-dir=/volume1/Archivum/project.git \
push --mirror git@github.com:csiber/project.git--mirror pushes all refs maintained by the mirror.
This includes branches and tags, rather than requiring them to be pushed individually.
Another approach is to clone the backup mirror first:
git clone /path/to/project.git project
cd projectThen configure the new GitHub repository:
git remote set-url origin git@github.com:USERNAME/project.gitFinally:
git push --mirror originFor a pure backup recovery, the direct --git-dir ... push --mirror method is usually simpler.
After the restore, compare the refs.
On the backup:
git --git-dir=/path/to/project.git show-refOn GitHub:
git ls-remote git@github.com:USERNAME/project.gitThe refs should correspond.
You can also compare the two lists:
git --git-dir=/path/to/project.git show-ref | sortand:
git ls-remote git@github.com:USERNAME/project.git | sortThe object IDs should match for corresponding refs.
The mirror is not tied to GitHub.
It can be pushed to another Git server supporting Git over SSH.
For example:
git --git-dir=/path/to/project.git \
push --mirror git@server.example.com:git/project.gitThis makes the local mirror useful for migrations as well as disaster recovery.
Possible destinations include:
- another GitHub repository
- GitLab
- Gitea
- Forgejo
- a self-hosted Git server
- another bare Git repository
Normally, a full mirror restore is preferable.
If only one branch is needed, it can be restored separately.
First inspect available refs:
git --git-dir=/path/to/project.git show-refThen push the required branch:
git --git-dir=/path/to/project.git \
push git@github.com:USERNAME/project.git \
refs/heads/main:refs/heads/mainReplace main with the required branch.
Tags are normally included automatically when using:
git push --mirrorIf tags need to be restored separately:
git --git-dir=/path/to/project.git \
push git@github.com:USERNAME/project.git \
--tagsA full mirror restore is still preferable when the goal is to recreate the repository as closely as possible.
Before restoring a damaged or questionable backup, run:
git --git-dir=/path/to/project.git fsckFor a healthy repository, Git should not report missing or corrupted objects.
A repository with errors should be investigated before using it as the recovery source.
A typical recovery sequence is:
GitHub repository deleted
↓
Local mirror still exists
↓
Create empty GitHub repository
↓
Push mirror
↓
Verify refs
↓
Repository restored
Example:
git --git-dir=/volume1/Archivum/project.git \
push --mirror git@github.com:csiber/project.gitThe local mirror remains unchanged.
If GitHub renamed a repository, the local backup may still use the old filename.
For example:
project.git
may correspond to the renamed GitHub repository:
new-project
The local mirror itself does not need to be modified to recover the Git data.
Create or select the destination repository and push the mirror:
git --git-dir=/path/to/project.git \
push --mirror git@github.com:USERNAME/new-project.gitA Git mirror restores the Git repository, not the complete GitHub web service state.
The following are not recreated by git push --mirror:
- Issues
- Pull Requests and discussions
- GitHub Actions configuration/state outside the repository
- Actions artifacts
- Releases metadata
- Packages
- repository settings
- branch protection rules
- collaborators and permissions
- webhooks
- secrets
- GitHub Wiki
- other GitHub-specific metadata
These require separate recovery procedures using GitHub's web interface or API.
Repositories using Git LFS require additional consideration.
The Git repository may contain LFS pointer files while the actual large objects are stored separately.
Check whether the repository uses LFS:
git --git-dir=/path/to/project.git \
grep -R "filter=lfs" -- .gitattributesIf LFS is used, the LFS objects should be backed up separately.
A Git mirror alone should therefore not automatically be considered a complete LFS backup.
Do not perform recovery directly against the only copy of the mirror.
If possible:
Backup mirror
│
├── Keep original untouched
│
└── Use it as the recovery source
↓
New repository
Before a destructive operation such as replacing an existing remote repository, verify:
git --git-dir=/path/to/project.git show-ref
git --git-dir=/path/to/project.git fsckThen push the mirror.
git clone /path/to/repository.gitgit --git-dir=/path/to/repository.git \
push --mirror git@github.com:USERNAME/repository.gitgit --git-dir=/path/to/repository.git show-refgit --git-dir=/path/to/repository.git fsckgit --git-dir=/path/to/repository.git \
push --mirror git@SERVER:git/repository.gitThe fundamental rule is simple:
The mirror is the recovery source. Do not modify it just to perform a recovery.
Use the mirror to create a new working copy or push the repository to a new Git server.