Skip to main content

Create a Private Fork of a Public Repository

The Problem

GitHub doesn't allow you to fork a public repository as private. This is by design, but sometimes you need a private copy of a public repo where you can:

  • Make experimental changes without cluttering the public fork network
  • Keep work-in-progress code private
  • Maintain your own version while still pulling upstream updates
  • Preserve access even if the original repo changes visibility

This guide shows you how to create a proper private fork that maintains an upstream connection.

This method creates a true mirror of the repository and lets you pull changes from the original repo later.

Step 1: Create a Bare Clone

Clone the repository without a working directory (temporary, will be removed):

git clone --bare git@github.com:original-owner/repo-name.git

Step 2: Create Your Private Repository

Go to GitHub and create a new private repository with the same name. Don't initialise it with any files.

Student tip: If you can't create private repos, get the GitHub Student Developer Pack for unlimited private repositories.

Step 3: Mirror Push to Your Private Repo

Replace <your_username> with your actual GitHub username:

cd repo-name.git
git push --mirror git@github.com:<your_username>/repo-name.git

Step 4: Clean Up the Bare Clone

Remove the temporary repository:

cd ..
rm -rf repo-name.git

Step 5: Clone Your Private Repository

Now clone your private repo to work with it:

cd ~/code
git clone git@github.com:<your_username>/repo-name.git

This lets you pull future changes from the original repository:

cd repo-name
git remote add upstream git@github.com:original-owner/repo-name.git
git remote set-url --push upstream DISABLE

The DISABLE prevents accidental pushes to the upstream repo.

Step 7: Verify Your Remotes

Check your remote configuration:

git remote -v

You should see:

origin    git@github.com:<your_username>/repo-name.git (fetch)
origin git@github.com:<your_username>/repo-name.git (push)
upstream git@github.com:original-owner/repo-name.git (fetch)
upstream DISABLE (push)

Pulling Upstream Changes

When you want to pull changes from the original repository:

git fetch upstream
git rebase upstream/main

Or if the default branch is master:

git fetch upstream
git rebase upstream/master

Resolve any conflicts if they arise, then push to your private repo:

git push origin main

Method 2: GitHub Import (Simpler but No Upstream Tracking)

If you don't need to pull upstream changes, use GitHub's import feature:

  1. Go to https://github.com/new/import
  2. Enter the URL of the public repository
  3. Choose a name for your repository
  4. Select Private visibility
  5. Click Begin import

Pros: Simple, one-step process
Cons: No automatic upstream tracking (you'll need to manually add it later if needed)

To add upstream tracking after import:

git remote add upstream git@github.com:original-owner/repo-name.git
git remote set-url --push upstream DISABLE

Method 3: Leave Fork Network (Web Interface)

If you've already forked the repository publicly, you can convert it to private by leaving the fork network:

  1. Go to your fork's ⚙️ Settings
  2. Scroll to Danger Zone
  3. Click Leave Fork Network (confirm)
  4. Refresh the page
  5. Go back to Danger Zone
  6. Click Change visibility > Change to Private

⚠️ Important: This method works, but you lose the official fork relationship. You can still add the original repo as an upstream remote manually (see Method 1, Step 6).

Which Method Should You Use?

MethodBest ForUpstream TrackingDifficulty
Bare CloneFull control, upstream tracking✅ YesMedium
GitHub ImportQuick private copy⚠️ Manual setupEasy
Leave Fork NetworkExisting public fork⚠️ Manual setupEasy

Common Issues

Default Branch Not Set

Sometimes after a bare clone, GitHub loses track of the default branch. Fix this in your repository settings:

  1. Go to ⚠️ Settings > Branches
  2. Set the default branch (usually main or master)

Push Conflicts

If you get push conflicts when pulling upstream changes:

git fetch upstream
git rebase upstream/main
# Resolve conflicts in your editor
git add .
git rebase --continue
git push origin main --force-with-lease

The --force-with-lease is safer than --force as it won't overwrite changes pushed by others.

Important Notes

  1. Fork visibility: According to GitHub's documentation, if a public repository becomes private, its public forks remain public in their own network. Your private clone created with these methods is independent.

  2. Not a "fork" in GitHub's eyes: These methods create a new repository that's not officially linked as a fork. This is intentional and gives you more control.

  3. Backup your work: If you're working on something important, push to your private repo frequently. Don't rely on the upstream repository staying accessible.


Credit: Based on this GitHub Gist by @0xjac, with additional methods and clarifications from community contributors.