Working as a consultant, opposed for the company one is employed by, can introduce some peculiar situations and the tech side of work is no different. Each client is different and will have a variable degree of tech savviness. One scenario I’ve experienced many times is having to maintain two separate Git repositories, an internal one for messier in progress work and an external “for deliverables only” repository.
A naive approach would involve cloning the internal and external repositories locally and using some tool like cp
to copy from the internal to the external repositories when one wanted to commit an external “deliverable”. While this would work, this would prove to be messy and prone to human error. A blind cp
of every file may copy over large files or directories that are included in one’s .gitignore
, say a venv/
directory. Additionally, forgetting to copy a file would cause for a missing file in one’s deliverable.
An alternative, and easier approach, would involve setting up multiple git remotes, one for the internal repository and one for the external repository. This will allow one to take advantage of all the native Git commands. To do this:
- Clone one of the repositories, say the internal one, like you normally would.
$ git clone <url of internal git repo>
- Inspect your existing remotes. We should see the default
fetch
andpush
remotes that come configured when we cloned our internal repository and are bound to the nameorigin
.
$ git remote -v
- Add our external repository as a second remote
$ git remote add <shortcut name> <url of external git repo>
- Verify that we now can see two sets of fetch and push, one for our internal repository
origin
, and one for our external repository<shortcut name>
.
$ git remote -v
- At this point we can use the internal repository like we normally would, branching, committing, pushing and merging.
$ git checkout -b <some branch
$ git commit add <some file>
$ git push origin <some branch>
$ git merge <some other branch>
- When we’re ready to make a “deployment” push to our external respoitory, we simply push to our external repository’s remote, which instead of using the internal nickname of
origin
, instead we’ll use the<shortcut name>
we assigned in step 3.
$ git push origin <shortcut name>
This approach also allows you to control which Git history you’re going to expose to the external repository. If you want the full history, then simply push from a branch with all the non-squashed commits. If you want a more cleaned up, and polished approach, simply push from a branch with squashed commits with nicer commit messages.
What’s nice about this approach is it can work for different scenarios as well. One additional example would be supporting one’s modifications to an open source project. One could have a remote for their forked copy of an open source project, while also maintaining a remote to the original open source repository as well. This would allow one to push their code changes to their own repository, while pulling down updates from the original project.
I hope this demystifies some common misconceptions I see regarding Git’s remotes and highlights two use cases for using multiple remotes.