How to manage private development and public releases in Git

Published on January 24, 2026


Motivation

When at the review stage of a manuscript, I often need to modify the original methods and code. However, there are temporary code changes and intermediate progress that I want to keep as a work journal for myself, rather than publishing everything to the public repository that accompanies the manuscript. At the same time, I want to make sure the public repo does not contain all the mumbling commits along the way, so using multiple branches in the public repo is also out of the picture.

Here is a method to keep a mirrored private repo for my own logs, while publishing only a final, clean commit to the public repo when it’s ready.


Initial setup

At this point, I already had a public GitHub repository for the manuscript code, and my local main branch was synced with the last public commit. I then created a new private repository (PROJECTNAME_private.git) on GitHub, which would serve as my personal work log. Note that when creating the private repository on the Github website, it should be empty.

Next, I added the private repository as a second remote to my existing local project, naming it to origin as the default push destination:

git remote add origin <private-repo-url>

I kept the public repository as a separate remote named public:

git remote add public <public-repo-url>

At this point, the local repository is connected to two remotes:

Before doing any further work, I tagged the current public commit as a reference point. This tag marks the last synchronized state between the local codebase and the public repository, and it becomes the baseline for all future releases:

git tag public-v1 public/main
git push origin --tags

From here on, all development happens normally on the local main branch and is pushed to the private repository. The public repository remains untouched until a clean release is ready.

Day-to-day workflow (push to private)

Most of the time, I treat the private repo as my real workspace, e.g.

git add -A
git commit -m "Update permutation tests in section xx"
git push origin main

Publishing a clean public release

When the code is ready to be shared publicly, I create a temporary release branch and squash all changes since the last public release into a single commit.

git checkout -b release-public
git reset --soft public-v1
git commit -m "Release: update permutation tests"
git push public release-public:main

After the release, I tag the new public baseline:

git tag public-v2
git push origin --tags

Then I can switch back to my normal workflow branch:

git checkout main

The private history remains untouched, while the public repo gains exactly one clean commit.

Summary