As of recent I've been working a lot on remote machines without an internet connection. This can be a real annoyance for many reasons, but it also forces you to really learn your tools and some of their often overlooked features.
Through the following rather peculiar scenario, I will demonstrate how one can use bare git repositories as intermediate remotes to "proxy" to a remote git server.
- running Windows in a VM :(
- connected to a git server
- can login to machine B with ssh client
- running Linux :)
- cannot reach the git server
How do you get a copy of the git repository from the git server to the Linux machine while maintaining a reasonably usable workflow?
scp files (or git bundles) between the machines, but who really wants to do that all the time?
"Bare" repositories are git repositories without a working tree. Git servers use them behind the scenes, since they don't need to edit files and stage changes.
This is what I came up with:
On Windows I clone the repository in question into a bare repository:
git clone git@git-server:squ94wk/sample.git --bare
This creates a directory
./sample.git with basically the contents of the
.git directory that you normally get with
Then I create an empty bare repository on Linux:
git init --bare remote/sample.git
I created this in the
./remote directory, because this is not actually the repository I will be working with; rather, it acts as a "fake" remote in the sense that it isn't on another machine.
I can now set up the bare repository on Linux (with ssh host alias "linuxvm") as a remote on the Windows machine and push to it:
git remote add linux linuxvm:remote/sample.git git push linux master:master
The contents of the master branch on Linux are now the same as on Windows and the git server alike.
There is still no working tree though. To fix that I just clone the bare repository that exists locally on Linux:
git clone ./remote/sample.git sample
I can now make changes to my working tree, commit and push them:
# cd sample echo "a change" >> file git add file git commit -m "add 'a change' to file" git push # origin master:master
The commit and the updated reference still needs to go to the Windows machine and to the git server.
If Windows was running a ssh server I could push directly from the Linux machine to Windows (that would come with other benefits as well, like automating the next step with a
post-update hook). But since it only works the other way around, I fetch the changes from the Linux machine and push them to the git server manually:
git fetch linux git push origin linux/master:master
linux/master is tracking the remote master branch of the bare repository on the Linux machine.
It works the other way around, too. I fetch changes from the git server and push them to the bare repo on Linux:
git fetch origin git push linux origin/master:master
There I can then fetch/pull the changes, hence updating my remote tracking branches and my working tree:
git fetch git merge
Now although this workaround is quite a stretch, it comes closest to the familiar "fetch-commit-push" workflow and is quite robust.
--bare saves you from having working trees everywhere that you don't use and would otherwise only get in the way.
You might never have to use bare repositories yourself (or frankly even work in such an atrocious environment), but I hope you can still take something away.