Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep public and private versions of a git repo in sync?

I'm releasing an open-source Rails app on Github (probably MIT license). I also want to maintain a private branch/fork of the project that we will use as part of a pay service.

What is the best way to organize the repo(s) in this scenario? And, how can I keep the projects in sync when I have updates that should go to both?

like image 706
Callmeed Avatar asked Jun 16 '09 00:06

Callmeed


People also ask

How do I make my git repository private to public?

On GitHub.com, navigate to the main page of the repository. Under your repository name, click Settings. Under "Danger Zone", to the right of to "Change repository visibility", click Change visibility. Select a visibility.

Can you fork a private repository and make it public?

No. You can fork it and it still remains private. Private collaborators may fork any private repository you've added them to without their own paid plan. Their forks do not count against your private repository quota.


1 Answers

The simplest solution would be to have private branch in your 'private' repository, i.e. branch which is simply not pushed to public repository.

For that you would probably need to either specify all branches you want to push to public repository in config (instead of using globbing mirroring refspec +refs/*:refs/*), or push carefully branches you want to publish and rely on Git behaviour of pushing matching branches (those which are present on remote side) setting "push.default" to current default value "matching".

If you by accident push your private branch, you can delete it in remote repository (unless it is configured to forbid this) using "git push <remote> :refs/heads/<private-branch>" (to remember this: push empty value to remote branch). You can protect against accidental pushing of your private branch using hooks on remote side, see e.g. update-paranoid example hook in contrib/examples.


Sidenote: Junio C Hamano, git maintainer, pushes to public git repositories only specified set of branches: 'maint', 'master', 'next', 'pu' (proposed updates), and 'html', 'man', 'todo'; he does not publish short-lived often changing feature branches.



EXAMPLE SETUP:

     working repository  ---->  private repository (bare)  ---->  public repository       \------ private -------/     \------- protected ------------/     \------- public -----/ 

"Working repository" is the repository with working area that you make commits in, where you pull changes and resolve conflicts; repository where you do your work. Let's say it contains the following branches: 'public' with changes that can be published to the world, 'private' that you want to not share with others or share only with selected subset of people, and perhaps some feature branches like 'ticket-234' or 'add-frobnicator', which are not ready even for selected group to see. This repository is non-bare, as it not published.

It would have something like the following configuration for pushing to 'private' repository. Note that "matching branches" behavior is set explicitely here, see git-pull manpage:

[remote "private"]         url = [email protected]:/srv/private/git/repo.git         push = +: 

"Private repository" is public bare repository available only to selected people, for example it is available for fetching only via SSH. It has only branches which are ready, i.e. 'public' and 'private' branches; either those branches were present when creating "private" repository, or were pushed explicitely ("git push private <branch>") from "working" repository. Push from "working" repository pushes (transfers) only matching branches, i.e. only 'public' and 'private' branches.

"Private repository" has post-update or post-receive hook set which pushes 'public' branch only to "public repository" (see below) if it was pushed to it (well, it can push unconditionally).

"Public repository" is public bare repository available to everyone, for example it is hosted on GitHub, and/or Gitorious, and/or repo.or.cz, or perhaps it is served via git:// protocol using git-daemon. It contains only 'public' branch, and it uses update or pre-receive either to accept whilelist of branches (here only 'public' branch is accepted), or reject blacklist of branches (in this example pushes to/creating 'private' branch would be rejected). It is updated automatically when pushing to "private" repository.

This setup might be overly complicated for your needs; "private" repository might be not necessary in your case. In such case the configuration in "working repository" for pushing directly to "public repository" would look like this:

[repository "public"]         url = ssh://example.com/srv/git/repo.git         push = refs/heads/public:refs/heads/public 

I hope this example would help; please however read the documentation and do not use it blindly.

like image 74
Jakub Narębski Avatar answered Oct 04 '22 00:10

Jakub Narębski