Skip to content

Recovery

Csaba Polyak edited this page Sep 28, 2026 · 1 revision

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:

  1. Restore a working copy from a mirror
  2. Restore the repository itself to GitHub or another Git server

Restore a working copy

If you simply need the source code again, clone directly from the mirror:

git clone /path/to/repository.git

For example:

git clone /volume1/Archivum/project.git

This creates a normal working directory:

project/
├── .git/
├── src/
├── README.md
└── ...

You can then continue working normally.


Restore to GitHub

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.

Option 1 — Push the complete mirror

From the backup machine:

git --git-dir=/path/to/project.git push --mirror git@github.com:USERNAME/project.git

Example:

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.


Restore using a temporary clone

Another approach is to clone the backup mirror first:

git clone /path/to/project.git project
cd project

Then configure the new GitHub repository:

git remote set-url origin git@github.com:USERNAME/project.git

Finally:

git push --mirror origin

For a pure backup recovery, the direct --git-dir ... push --mirror method is usually simpler.


Verify the restored repository

After the restore, compare the refs.

On the backup:

git --git-dir=/path/to/project.git show-ref

On GitHub:

git ls-remote git@github.com:USERNAME/project.git

The refs should correspond.

You can also compare the two lists:

git --git-dir=/path/to/project.git show-ref | sort

and:

git ls-remote git@github.com:USERNAME/project.git | sort

The object IDs should match for corresponding refs.


Restore to another Git server

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.git

This 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

Restore a specific branch

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-ref

Then push the required branch:

git --git-dir=/path/to/project.git \
    push git@github.com:USERNAME/project.git \
    refs/heads/main:refs/heads/main

Replace main with the required branch.


Restore tags

Tags are normally included automatically when using:

git push --mirror

If tags need to be restored separately:

git --git-dir=/path/to/project.git \
    push git@github.com:USERNAME/project.git \
    --tags

A full mirror restore is still preferable when the goal is to recreate the repository as closely as possible.


Verify repository integrity before recovery

Before restoring a damaged or questionable backup, run:

git --git-dir=/path/to/project.git fsck

For 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.


Recovering after accidental GitHub deletion

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.git

The local mirror remains unchanged.


Recovering after a repository rename

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.git

Important: GitHub metadata is separate

A 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.


Git LFS

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" -- .gitattributes

If 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.


Recovery best practice

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 fsck

Then push the mirror.


Quick Recovery Reference

Working copy

git clone /path/to/repository.git

Restore complete repository

git --git-dir=/path/to/repository.git \
    push --mirror git@github.com:USERNAME/repository.git

Check refs

git --git-dir=/path/to/repository.git show-ref

Check integrity

git --git-dir=/path/to/repository.git fsck

Restore to another Git server

git --git-dir=/path/to/repository.git \
    push --mirror git@SERVER:git/repository.git

The 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.