Restore a Git repository from a backup

I. Introduction

This package contains only raw Git repository data (the contents of a .git directory). It is not a working tree — no source files will appear until Git recreates them. Because the .git directory is hidden by default, the unpacked repository may initially appear empty.

Contents:

  • Git metadata and object data (i.e., a .git directory or its internal files)

Not a working tree:

  • The source files remain encoded and invisible until a commit is checked out.

To access the source files:

  • Restore the .git directory into a local repository.
  • Run a Git checkout (following the instructions provided) to recreate the working tree.

II. Requirements for restore

A Git client must be installed and available in your system’s PATH.

III. Manual local restore

Follow these steps:

1. Download one of the Git Repos folders.

2. Unpack the folder.

Note: The folder may appear empty unless your file explorer is set to show hidden files.

3. Open the folder in a terminal.

4. Initialize an empty repository:

git init

5. Verify repository integrity:

git fsck --full

6. Recreate working files:

git checkout -f HEAD

The repository is ready for use on a local machine only.

Notes:

  • If git fsck reports missing or corrupt objects, the archive may be incomplete or damaged.
  • Ensure that the extraction process completed successfully and was not interrupted.

IV. Uploading restored files to a remote — risks and safe options

Restoring a repository locally and then pushing to a remote can be risky because the backed-up .git data and the remote may have diverged. Directly pushing the restored refs to the remote (especially using force) can overwrite or delete commits on the remote, break collaborators' clones, and cause problems for forks or CI systems. Below are four pushing options with their trade-offs and commands.


Option 1 — Push as-is (no force)


When to use: 

Use this option when the remote is empty or when you've confirmed that the restored branches are fast-forward relative to the remote.

Risk:

Safe in most cases — the push will simply be rejected if the remote contains commits you don’t have.

Commands:

git remote add origin <remote-url>
git fetch origin
git push origin HEAD
git push --all origin
git push --tags origin


Option 2 — Force push (overwrite remote history)

When to use:

Choose this only if you intend to completely replace the remote history and have explicit authorization and coordination with all affected collaborators.

Risk:

Destructive — overwrites remote branches, loses remote-only commits, breaks forks and clones, and can disrupt CI

Commands (destructive):

git remote add origin <remote-url>
git push --force --all origin
git push --force --tags origin


Option 3 — Push to renamed (restored/*) branches


When to use:

Use this option if you want to preserve the existing remote history while safely making the restored data available. This is the recommended default.

Behavior:

Each local branch is pushed to a new remote branch namespace (for example, restored/main), preventing conflicts with existing branches. This allows for safe review, comparison, and merging via pull requests.

Risk:

May significantly increase repository size if many restored branches or large histories are pushed.

Commands:

git remote add origin <remote-url>
git fetch origin
for b in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
git push origin "refs/heads/$b:refs/heads/restored/$b"
done
git push origin --tags

Option 4 — Push to a new fork (recommended for full isolation)

When to use:

Use this when you need complete separation from the original remote — for example, to avoid any risk to the upstream repository, or to collaborate on the restored history independently.

Behavior:

Create a new repository or fork (under a separate account or organization), add it as a remote, and push your restored data there. This keeps both the upstream and restored histories fully preserved and isolated.

Steps (example flow):

1. Create a new empty repository on your hosting provider (e.g., GitHub/GitLab/Azure DevOps) — for example, restored-repo-fork.
2. Add the new repo as a remote:

git remote add fork <new-remote-url>
git fetch fork

3. Push branches and tags to the fork (non-destructive to the original remote):

git push fork --all
git push fork --tags

Advantages:

Zero risk to the original remote. You can later open pull requests from the fork back to the original repository if desired.


Summary

Avoid force-pushing unless absolutely necessary and fully coordinated with all collaborators. Prefer Option 3 (renamed/restored branches) or Option 4 (push to a new fork) to safely expose restored data while preserving remote history and preventing workflow disruptions.