One repo, two remotes
So you have a Git repo linked to a particular remote. But you need your code available somewhere else as well. Be it because of functionality which you want to keep private, a deploy to cloud environment or the reason lies elsewhere.
How can one approach this kind of situation, i.e. how to add and manage multiple remotes?
One remote
As an example we will be working with an extremely simple repo called test. Let's create it first.
dm@Z580:~/workspace$ mkdir test dm@Z580:~/workspace$ cd test dm@Z580:~/workspace/test$ git init Initialized empty Git repository in /home/dm/workspace/test/.git/ dm@Z580:~/workspace/test$ git checkout -b master Switched to a new branch 'master' dm@Z580:~/workspace/test$ echo "test file" > testfile.txtThere, a remote-less Git repo with a branch called master containing only a single file testfile.txt.
Next we will add a GitHub remote called origin and list all available remotes. Of course, you have to create the repo on GitHub first in order to obtain it's URL.
dm@Z580:~/workspace/test$ git remote add origin git@github.some_user/test.git dm@Z580:~/workspace/test$ git remote -v origin git@github.com:some_user/test.git (fetch) origin git@github.com:some_user/test.git (push)Now it's time to push our local repo (it's master branch) to GitHub.
dm@Z580:~/workspace/test$ git add testfile.txt dm@Z580:~/workspace/test$ git commit -m 'Initial commit' [master (root-commit) f49cafd] Initial commit 1 file changed, 1 insertion(+) create mode 100644 testfile.txt dm@Z580:~/workspace/test$ git push -u origin master Counting objects: 3, done. Writing objects: 100% (3/3), 229 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@github.some_user/test.git * [new branch] master -> master Branch master set up to track remote branch master from origin.
Adding another remote
Right, that's a public GitHub remote. We will carry on and add a new private Bitbucket remote as well (Bitbucket offers it for free!). First create the repo on Bitbucket and then add a new remote to our local repo. List remotes to see what's available.
dm@Z580:~/workspace/test$ git remote add bitbucket ssh://git@bitbucket.org/some_user/test.git dm@Z580:~/workspace/test$ git remote -v bitbucket ssh://git@bitbucket.org/some_user/test.git (fetch) bitbucket ssh://git@bitbucket.org/some_user/test.git (push) origin git@github.com:some_user/test.git (fetch) origin git@github.com:some_user/test.git (push)Same as with GitHub, the Bitbucket remote has no branch. Let's push our local master branch to the new remote. Afterwards, list all available branches to see what happened.
dm@Z580:~/workspace/test$ git push -u bitbucket master Writing objects: 100% (3/3), 229 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To ssh://git@bitbucket.org/some_user/test.git * [new branch] master -> master Branch master set up to track remote branch master from bitbucket. dm@Z580:~/workspace/test$ git branch -a * master remotes/bitbucket/master remotes/origin/masterAs you can see, the master branch is now present in each repo - local and both remotes.
Private content
We are finally going to add and push a private file. To keep content separated, we will create a new branch called private.
dm@Z580:~/workspace/test$ git checkout -b private Switched to a new branch 'private' dm@Z580:~/workspace/test$ echo "private file" > privatefile.txt dm@Z580:~/workspace/test$ git add privatefile.txt dm@Z580:~/workspace/test$ git commit -m 'Add a private file' [private 42caa23] Add a private file 1 file changed, 1 insertion(+) create mode 100644 privatefile.txtWe need to setup branch tracking prior to pushing our private content to remote. In other words - specify which remote branch is tracked by our local private branch.
Branch mapping
Currently, no mapping is defined.
dm@Z580:~/workspace/test$ git branch -vv master f49cafd [bitbucket/master] Initial commit * private bdc169d Add a private fileAs our local and remote branch names are different, we have to change our repo's config. Change the git push behavior to be specific.
dm@Z580:~/workspace/test$ git config push.default upstreamNow we can setup upstream and push our private content.
dm@Z580:~/workspace/test$ git branch -u bitbucket/master Branch private set up to track remote branch master from bitbucket. dm@Z580:~/workspace/test$ git push Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 298 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To ssh://git@bitbucket.org/some_user/test.git f49cafd..67bc2eb private -> masterGood, so if you now check both remotes you will see that privatefile.txt is present only on Bitbucket. Exactly as we had in mind!
Although, one more thing requires our attention. The local master branch is still pointed to Bitbucket. Thankfully, the fix is quite straightforward.
dm@Z580:~/workspace/test$ git branch -vv master f49cafd [bitbucket/master: behind 1] Initial commit * private 67bc2eb [bitbucket/master] Add a private file dm@Z580:~/workspace/test$ git checkout master Switched to branch 'master' Your branch is behind 'bitbucket/master' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) dm@Z580:~/workspace/test$ git branch -u origin/master Branch master set up to track remote branch master from origin. dm@Z580:~/workspace/test$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean dm@Z580:~/workspace/test$ git branch -vv * master f49cafd [origin/master] Initial commit private 67bc2eb [bitbucket/master] Add a private file
Final touches
Don't you think that it's a bit weird we have an origin and Bitbucket remotes? Also, there are master and private branches. Renaming both GitHub remote and branch will be more clean and concise.
dm@Z580:~/workspace/test$ git remote rename origin github dm@Z580:~/workspace/test$ git branch -m master public dm@Z580:~/workspace/test$ git remote -v bitbucket ssh://git@bitbucket.org/some_user/test.git (fetch) bitbucket ssh://git@bitbucket.org/some_user/test.git (push) github git@github.com:some_user/test.git (fetch) github git@github.com:some_user/test.git (push) dm@Z580:~/workspace/test$ git branch -vv private 67bc2eb [bitbucket/master] Add a private file * public f49cafd [github/master] Initial commitNow, that's better. Local branch public is tracking master on GitHub and private is tracking bitbucket's master. Moreover, using git push will push only to the linked remote branch.