497

How can I fork a public repository, but make my fork private? I do have the subscription to support private repositories.

Ben Creasy
  • 3,825
  • 4
  • 40
  • 50
zer0stimulus
  • 22,306
  • 30
  • 110
  • 141

7 Answers7

707

The answers are correct but don't mention how to sync code between the public repo and the fork.

Here is the full workflow (we've done this before open sourcing React Native):


First, duplicate the repo as others said (details here):

Create a new repo (let's call it private-repo) via the Github UI. Then:

git clone --bare https://github.com/exampleuser/public-repo.git
cd public-repo.git
git push --mirror https://github.com/yourname/private-repo.git
cd ..
rm -rf public-repo.git

Clone the private repo so you can work on it:

git clone https://github.com/yourname/private-repo.git
cd private-repo
make some changes
git commit
git push origin master

To pull new hotness from the public repo:

cd private-repo
git remote add public https://github.com/exampleuser/public-repo.git
git pull public master # Creates a merge commit
git push origin master

Awesome, your private repo now has the latest code from the public repo plus your changes.


Finally, to create a pull request private repo -> public repo:

Use the GitHub UI to create a fork of the public repo (the small "Fork" button at the top right of the public repo page). Then:

git clone https://github.com/yourname/the-fork.git
cd the-fork
git remote add private_repo_yourname https://github.com/yourname/private-repo.git
git checkout -b pull_request_yourname
git pull private_repo_yourname master
git push origin pull_request_yourname

Now you can create a pull request via the Github UI for public-repo, as described here.

Once project owners review your pull request, they can merge it.

Of course the whole process can be repeated (just leave out the steps where you add remotes).

Martin Konicek
  • 39,126
  • 20
  • 90
  • 98
  • 11
    Why can't one simply add the empty private repo as a new remote to a normal clone of the public repo and then push to the remote? What would be the difference? – Falko Menge Jul 28 '17 at 21:30
  • 2
    @FalkoMenge I have the same question. Reading https://www.git-scm.com/docs/git-clone, it sounds like a normal `git clone` will set up remote tracking branches and maybe some other config in the cloned repo that you don't really want. Whereas a --bare clone just copies the .git dir from the remote as is. – bennlich Dec 11 '17 at 18:40
  • 1
    @Sukhjinder Singh Yes, the last step will push the private commit history to the public repo. If you don't want that, you could squash your commits when merging them to the public repo, and push a single commit with all your changes. See e.g. https://stackoverflow.com/questions/5308816/how-to-use-git-merge-squash – Martin Konicek Sep 02 '18 at 21:01
  • 1
    I got to step where I clone my private repo and then make a change then push. Any changes I made went unnoticed by git. `git status` shows everything up to date, working tree clean no matter what I change. Consequently I can't commit and push anything. I deleted the new private repo I made 2 more times to attempt this but kept running into this same issue. Any suggestions? – Will Dec 19 '18 at 07:18
  • Looks like there's a way to merge back into the public repo, without actually requiring push access to that public repo. Makes sense: https://stackoverflow.com/a/8834984/90998 – Martin Konicek Jan 16 '20 at 16:30
  • 4
    @FalkoMenge Because going the mirror route duplicates all branches, tags, etc. In the simplest case, if the repo only has only 1 branch, no tags, nothing else special, then I think your approach would work. In all other cases, it's best to mirror. – Mike B Feb 18 '22 at 00:24
  • 1
    This is great! However pushing will probably fail as "Support for password authentication was removed on August 13, 2021". Instead use something like `git push --mirror git@github.com:yourname/private-repo.git`. – ariels Jan 22 '23 at 11:33
  • Could the rules have changed? I am getting: remote: Permission to YY/XX.git denied to [me]. – R Claven Mar 29 '23 at 18:43
  • We're in 2023 and I have no idea what is the correct answer to this very old question... When I look at the "danger zone", still I see that "**Change repository visibility For security reasons, you cannot change the visibility of a fork.**" – gianni May 15 '23 at 13:40
174

There is one more option now ( January-2015 )

  1. Create a new private repo
  2. On the empty repo screen there is an "import" option/button enter image description here
  3. click it and put the existing github repo url There is no github option mention but it works with github repos too. enter image description here
  4. DONE
szydan
  • 2,318
  • 1
  • 15
  • 16
  • 27
    This works, albeit a little differently. ( I tried in August 2015). I didn't find the import option/button, so googled it and ended up in this URL. https://import.github.com/new Here, you can enter the existing github url and click the *Check it* button. Once verified, you can enter the name of your new repo and click the Private button and then click *Begin Import* – Shiva Aug 06 '15 at 03:32
  • 2
    I believe @MattvanAndel means that the comment is correct, not the original answer. I too followed Shiva's comment and it worked. Note that you should NOT create the local private repository first! – David H Apr 28 '16 at 18:38
  • If I create a private "fork" in this way and want to make it a public fork again, can I do that? – Anders Lindén Dec 30 '16 at 08:53
  • @Shiva I found the button at the bottom of the page in empty repo screen. I think it is because I created the repository without README, LICENSE or .gitignore, totally empty. – Burak Nov 20 '20 at 09:29
  • 3
    NOT SUPPORTED: Per GitHub Support, import is solely intended for converting external projects into github and using it on github repos may have unexpected consequences. Obviously works for some projects, based on answers here, but I ran into problems using import on a large project (that's what led me to github support). IMO it's not worth the risk when duplicating a repo is straightforward. – cb4 Feb 26 '21 at 18:08
  • This works good. I successfully turned a public fork to a private repo with all the commit history. – 慕冬亮 Dec 09 '22 at 06:08
  • 2
    Seem like the URL should be https://github.com/new/import as of this writing. – Erik Finnman Mar 27 '23 at 08:56
50

Just go to https://github.com/new/import .

GitHub Import

In the section "Your old repository's clone URL" paste the repo URL you want and in "Privacy" select Private.

Gonçalo Peres
  • 11,752
  • 3
  • 54
  • 83
DJTano
  • 1,055
  • 12
  • 12
  • 9
    @cb4 well, if you don't say what problem you ran into, basically it is not adding value. – Luk Aron Mar 14 '21 at 09:33
  • @LukAron I somewhat agree and am sorry I didn't capture the specifics when I went through the process of coming up with the GitHub-supported answer. If I get the time to recreate the original conditions, I will certainly update my comment. – cb4 Sep 07 '21 at 22:39
  • 2
    Using this, I will be be notified as usual of changes in the main branch, and then merge them in my code?? – gianni May 21 '23 at 10:14
49

The current answers are a bit out of date so, for clarity:

The short answer is:

  1. Do a bare clone of the public repo.
  2. Create a new private one.
  3. Do a mirror push to the new private one.

This is documented on GitHub: duplicating-a-repository

2Toad
  • 14,799
  • 7
  • 42
  • 42
stefano
  • 3,753
  • 1
  • 22
  • 15
  • 8
    Is there a way to pull upstream changes? This is important for a repo that has a liberal license - I have made my repo private but would still like to merge the upstream changes. – amarprabhu May 28 '14 at 08:08
  • 4
    Yes. You should be able to add the other repo as a new (tracking) remote (eg. 'other-repo')and then periodically fetch and merge changes from it (eg. 'git merge other-repo/stable'). – stefano Aug 29 '14 at 01:45
39

You have to duplicate the repo

You can see this doc (from github)

To create a duplicate of a repository without forking, you need to run a special clone command against the original repository and mirror-push to the new one.

In the following cases, the repository you're trying to push to--like exampleuser/new-repository or exampleuser/mirrored--should already exist on GitHub. See "Creating a new repository" for more information.

Mirroring a repository

To make an exact duplicate, you need to perform both a bare-clone and a mirror-push.

Open up the command line, and type these commands:

$ git clone --bare https://github.com/exampleuser/old-repository.git
# Make a bare clone of the repository

$ cd old-repository.git
$ git push --mirror https://github.com/exampleuser/new-repository.git
# Mirror-push to the new repository

$ cd ..
$ rm -rf old-repository.git
# Remove our temporary local repository

If you want to mirror a repository in another location, including getting updates from the original, you can clone a mirror and periodically push the changes.

$ git clone --mirror https://github.com/exampleuser/repository-to-mirror.git
# Make a bare mirrored clone of the repository

$ cd repository-to-mirror.git
$ git remote set-url --push origin https://github.com/exampleuser/mirrored
# Set the push location to your mirror

As with a bare clone, a mirrored clone includes all remote branches and tags, but all local references will be overwritten each time you fetch, so it will always be the same as the original repository. Setting the URL for pushes simplifies pushing to your mirror. To update your mirror, fetch updates and push, which could be automated by running a cron job.

$ git fetch -p origin
$ git push --mirror

https://help.github.com/articles/duplicating-a-repository

bsuttor
  • 2,716
  • 2
  • 17
  • 10
  • 1
    This creates a *clone* of the repo but it doesn't create a *fork* in the GitHub sense. When you create an actual fork in GitHub, it shows a text "forked from exampleuser/repository-to-mirror" under the fork name. It also shows a tree of all other forks when you navigate to github.com/exampleuser/new-repository/network/members. – apaatsio Apr 11 '19 at 13:36
28

GitHub now has an import option that lets you choose whatever you want your new imported repository public or private

Github Repository import

Yidir
  • 583
  • 7
  • 12
  • Import is still running on a large repository (5 days), checking them out is much faster but maybe that is more steps to keep it up to date. The slowness is understandable I suppose as it imports everything not just master branch, but I wish it was faster... – Liam Mitchell Jan 08 '20 at 18:19
  • 1
    NOT SUPPORTED: Per GitHub Support, import is solely intended for converting external projects into github and using it on github repos may have unexpected consequences. Obviously works for some projects, based on answers here, but I ran into problems using import on a large project (that's what led me to github support). IMO it's not worth the risk when duplicating a repo is straightforward. – cb4 Feb 26 '21 at 18:10
  • GitHub just breaks if it duplicates one of its own repos, yet doesn't block it? That's really great design, there. – Matthew Read Jun 10 '23 at 00:24
6

2021 Update

I am new to git, so wanted to do as much as possible in the eclipse GUI (v2020-12; EGit v5.11). Details below.

---> The import method in other answers was designed only for Subversion, Mercurial, or TFS projects. It is not supported by GitHub for git projects, as I learned firsthand. It might work, but why risk it?


Repositories and GitHub Connection

eclipse/org.aspectj is the original public repo and the upstream remote for fetching
cb4/org.aspectj is the fork and the origin remote for pushing
cb4/remPrivAJ is the remote private repo and the private remote for pushing
I:\local is the local repo

For github authentication, I used ssh with an ed25519 key (steps in this SO answer) so my connection URIs look like this: ssh://git@github.com/<user>/<repo>.

Notation: -> is a mouse click or selection; right-> is a right click.


STEPS

  1. On github, fork the original public repo to your github account
  2. On github, create the empty remote private repo
  3. In the eclipse Git Perspective, clone the fork to a new local repo and configure it
  • 3.1-> Clone a Git Repository and add clone to this view -> Clone URI -> Next
    • 3.1.1 Enter the URI, Connection, and Authentication info as appropriate -> Next
    • 3.1.2. Select desired branches (I selected only master) -> Next
    • 3.1.3. Enter destination directory for local repo
    • 3.1.4. Import projects now or do it later, then -> Finish to populate the local repo
  • 3.2. Configure the original public repo as a new remote named upstream for pulling down updates
    • 3.2.1. right-> Remotes -> Create Remote -> and enter name upstream
    • 3.2.2. -> Configure fetch -> Create -> Change -> enter original repo URI -> Finish
    • 3.2.3. -> Save and Fetch -> all branches are downloaded -> Close
    • 3.2.4. NOTE: I only wanted the master branch, so did this instead of Step 3.2.3
    • 3.2.5. -> Advanced under Specifications to fetch, delete the lone entry there
    • 3.2.6. Under Add create/update specification -> Source ref: dropdown and select master [branch] -> +Add Spec -> Force Update
    • 3.2.7. -> Save specifications in upstream configuration -> Finish -> Save and Fetch -> only master branch is downloaded -> Close

  1. Duplicate the remote public repo to your remote private repo and configure. This is the only step that can’t be done in eclipse, so I installed Git for Windows and used GitCMD.

Like so:

git clone --bare git://github.com/eclipse/org.aspectj.git tmpRepo
<if prompted, enter ssh passphrase>
cd tmpRepo    
git push --mirror ssh://git@github.com:cb4/private.git
<if prompted, enter ssh passphrase>
cd ..    
rmdir tmpRepo /s /q

  1. Configure the remote private repo as a new remote named private for pushing
  • 5.1. right-> Remotes -> Create Remote -> and enter name private
  • 5.2. -> Configure push -> Create -> Change -> enter remote private repo URI -> Finish
  • 5.3. -> Advanced -> Add All Branches Spec -> Force Update -> Save specifications in origin configuration -> Finish
  • 5.4. -> Save and Push master branch is pushed -> Close

At this point, you have forked a public repo into your private repository. To see how to push private changes to your fork and then open a pull request against the original public repo, see my answer here. The resulting configuration looks like this:
config

cb4
  • 6,689
  • 7
  • 45
  • 57