Back up a Git repository — properly
Most "backups" are a stale clone of one branch. Here's what a real Git backup contains, and the four ways teams create one.
Why git clone is not a backup
A clone captures a single moment. Without something that reruns it automatically, that moment gets further from true every day.
One branch, not the repository
A default git clone brings down one branch's tip and a working tree. Every other branch, every tag, and repository notes are left on the server — invisible until the day you go looking for them.
Stale the moment someone pushes
A backup taken once is accurate for exactly as long as nobody commits. On a repository anyone is actively working in, that's minutes, not days.
--mirror fixes the refs, not the freshness
git clone --mirror captures every ref — branches, tags, notes, the full graph — but only for the instant it runs. It solves completeness. It does nothing about how current the copy stays afterward.
Four ways to back up a repository
Every approach on this list can produce a working backup. They differ in what happens the day you need to prove it.
| Feature | Manual clone | Cron script | Provider export | Git Replica |
|---|---|---|---|---|
| Runs automatically | — | ✓ | ✓ | ✓ |
| Captures every ref | — | ✓ | ✓ | ✓ |
| Freshness | Whenever you remember | Up to the interval | Provider's schedule | Seconds after each push |
| Cross-provider | — | ✓ | — | ✓ |
| Restore effort | Manual | Manual | Import job | Single git push |
| Ongoing maintenance | Yours | Yours — scripts, creds, alerts | Provider's | None |
What a complete backup contains
A backup that's missing refs, or missing context, isn't incomplete by accident — it's incomplete by definition.
Every ref
Branches, tags, notes and the full commit graph, using git clone --mirror semantics. Provider-internal refs like refs/pull/* are deliberately excluded — every provider rejects pushes to them, so keeping them would only break the restore.
Repository metadata
Issues, pull requests, reviews, comments, labels, milestones and release notes, optionally captured as JSON alongside the code when the destination is object storage. See what's inside an archive →
The archive itself
Timestamped per repository and retained on the rules you set — never silently overwritten, never shared across repositories.
One more thing "complete" doesn't cover: Git LFS pointer files are included in every backup, but the LFS object content they point to is not.
Four steps to an automatic backup
Connect once. Everything after the first push runs without you.
Connect a source account
GitHub, GitLab or Bitbucket over OAuth, or any Git server reachable over HTTPS or SSH.
Create a binding
Pick the source repository and a destination — another Git host, or an object-storage bucket.
Pushes trigger the sync
The moment you push, GitHub, GitLab and Bitbucket sources fire a webhook and the backup starts. Custom and self-hosted remotes sync hourly, daily or weekly, or on demand.
Watch the sync log
Every step is recorded, with email on failure so a broken backup doesn't go unnoticed.
Where the backup should live
A replica and an archive both keep your code safe — they just answer different follow-up questions on the day something breaks.
Another Git host
A live, clonable replica somebody can work from today — point CI at it, or keep going if the primary host is unreachable. See how mirroring works →
Object storage
Point-in-time archives with retention, written to a bucket you own. See backups to S3 →
Backup questions
Is git clone enough to back up a repository?
No. A default git clone gives you one branch's tip and a working tree — every other branch, tag and note is left behind. Running git clone --mirror fixes that by capturing every ref, but only for the instant it runs; the moment someone pushes again, that mirror is stale. A real backup needs full-ref coverage and something that reruns automatically after every push, not a command you remember to type.
What does a complete Git backup include?
Every ref in the repository — branches, tags, notes and the full commit graph, using the same semantics as git clone --mirror. Provider-internal refs such as refs/pull/* and refs/merge-requests/* are deliberately excluded, since every provider rejects pushes to them. A complete backup can also optionally include the repository's metadata — issues, pull requests, reviews, comments, labels, milestones and release notes — captured as JSON alongside the code when the destination is object storage. Git LFS pointer files replicate; the LFS object content itself does not.
How often should Git repositories be backed up?
As often as the repository changes, which is why a fixed interval is the wrong starting point. GitHub, GitLab and Bitbucket sources back up on every push, the moment your provider delivers the webhook. Self-hosted and custom remotes don't support webhooks, so they sync on a schedule instead — hourly, daily or weekly — or on demand before a risky operation. Push-triggered wherever it's available, with a schedule as the floor everywhere else.
How do I restore a repository from a backup?
It depends on where the backup lives. If it's a replica on another Git host, point your remote at it — it's already a working repository. If it's an archive in object storage, download the zip, unzip it, and run git push --mirror against a new remote; every ref goes back in a single push. Either way, restoring is an ordinary Git operation, not a proprietary import process.
Keep reading
Real-time Git backup
Webhook-triggered backups that are current the moment you push.
Git backup archives
What's inside an archive, how retention works, and how to restore.
Git disaster recovery
Outage, lockout, force-push, deletion — and the recovery path for each.
Automated GitHub backup
Back up GitHub repositories to another provider or storage you control.
Secure repository mirroring
Least-privilege connections, controlled destinations, and auditable synchronization.
Git archive examples
Practical ZIP, TAR, folder, tag, prefix, and export-ignore examples.
Back up your first repository in two minutes.
Connect a provider account, create a binding, and your next push is protected. Free for open source and private non-commercial use.
Get started free