I’m all about Open Source development as you know, but sometimes you want to keep certain content in your Open Source Application private, or tailored for your specific requirements. There are several ways to approach this, but the way we’ll do it here is to use two separate repositories, a Private Repo and a Public Repo.
Our Private git-private Repository will be our ORIGIN while our Public git-public Repository will be our UPSTREAM repository. Here’s our Public Repo on BitBucket. The Private BitBucket Repo is of course very similar.
The PUBLIC BitBucket Repository is a fork of PRIVATE. With a forked relationship we could consider using Pull Requests from an ORIGIN (forked repository) to an UPSTREAM repository in GitHub, BitBucket or some other provider. Our approach is a bit more Client IDE focused, maintaining both versions and updating both from a single IntelliJ Project.
As for the differences between the two applications, there will be some source code and corresponding test differences, but the biggest difference is a /resources/private area in the PRIVATE repo…
and a corresponding /resources/public area in the PUBLIC distribution.
Notice one other “Developer Aid” Item, the public.txt or private.txt file in the project root as a reminder to the Developer of which mode we’re currently working in.
Remote Repository Setup
Our PRIVATE Repository is our ORIGIN Remote Repository, which is tracked by the local master branch. Our PUBLIC Repository is tracking UPSTREAM/MASTER from our local public branch.
The ORIGIN and UPSTREAM Remote configurations look like this.
To initially setup this configuration we use the following Git commands.
$ git remote add origin https://...bitbucket.org/git-private.git
$ git remote add upstream https://...bitbucket.org/git-public.git
$ git fetch upstream
$ git checkout -b public upstream/master
Notice we checkout the upstream/master branch (a fork of our PRIVATE repo) in a new branch called public. We push updates to upstream/master with
$ git push upstream HEAD:master
We don’t want to type that in every time we push to UPSTREAM so we created an alias called push-public.
$ git push-public
Updating from Master, or from Private to Public
We’re regarding our Private version as our primary workspace, as it tracks ORIGIN with the master branch. So our update process is to code as usual in our Private workspace, then typically before pushing to the PRIVATE Repository, we’ll
- Stage and Commit our master branch
- Checkout the public branch
- Merge the master branch into public
- Use Meld to handle any Merge conflicts
- If present, transfer and update any /resources/public contents from /resources/private
- Remove any new /resources/private content with a Git Remove command
- Stage and Commit the public branch updates as usual
- Push public to UPSTREAM/MASTER, which is the PUBLIC Repository
That seems like a lot of steps, but it really isn’t a hardship as you’ll soon see.
We checkout public and merge master. That would be the end of the process 95% of the time, where we could then stage, commit and push to the PUBLIC Repository. We could, of course, encounter a merge conflict.
That’s a non-issue for us because we’ve configured Git to use Meld as our MergeTool. Here’s the .gitconfig info.
To make merging even simpler we created a Git alias meld-merge which fires up Meld for us. The alias actually executes !git mergetool –tool=meld.
So instead of dealing with this…
We’re pointing and clicking with Meld!
When finished, we’ll stage and commit our public branch as usual, then push to UPSTREAM/MASTER with our Git alias push-public.
Again, that push-public alias executes
$ git push upstream HEAD:master
Optional Rebase Action
You may consider consolidating multiple Private commits to keep the Public Repo a bit cleaner. If you do, Pick and Squash in nano or your preferred editor in master PRIOR to merging with the public branch. Keyword: prior to merging.
Meaningless Postscript: I’m a joe man and use the Joe Editor for all console editing, but IntelliJ seems to have issues with it in the Terminal toolbox and my rebase sessions are aborted. So I use Nano with Git in IntelliJ (and ONLY with Git in IntelliJ…haha)