One can use ssh -R to open a reverse tunnel from a remote back to your local machine, allowing one to use git to clone from your local machine to the remote server.

One feature/drawback of git is that git clone is a pull-only operation: it must be able to see a remote to clone it. This is fine in 99% of use cases, but sometimes, one wishes it were possible to “push clone” a new repository, e.g. from a laptop to a server.

However, by using the reverse tunneling feature of ssh, we can achieve this behaviour in a round-about way.

Specifically:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Open an ssh connection to your server as usual, as well as a "reverse
# tunnel", mapping localhost:22222 on the server to localhost:22 on the client.
ssh -R 22222:localhost:22 user@server-hostname

cd /path/to/where/we/want/our/gitrepo

# Now, we clone as per normal, using our reverse tunnel back to the laptop as
# the remote server.
git clone ssh://${LAPTOP_USERNAME}@localhost:22222/path/to/repo/on/laptop

cd ${new_repo}

# we should remove the 'origin' remote, as it will depend on the (soon to be
# removed) reverse tunnel back to our laptop.
git remote rm origin

# OPTIONAL: allow pushes direct to the checked out files (see note below)
git config --set receive.denyCurrentBranch updateInstead

# Close the ssh session, and the remote tunnel. next time you ssh, you don't
# need to use the remote tunnel.
exit

# We now have a clone of our repo on the remote server. You can now add this as
# a remote as per normal on the original laptop copy of the repo.

Notes:

  • Your laptop (or the client end of the original ssh connection) must be running sshd, and you must be able to log in (just run ssh ${laptop_username}@localhost on your laptop to check). If not, enable it.
  • You may need to adjust the port (22222) if there is already something running on this port on the server. You should see ssh complain if that’s the case.
  • If you’re using this primarily as a backup of the local git repository, you’ll probably want to investigate the receive.denyCurrentBranch git config option. Specifically, you’ll probably want to set it to updateInstead, and read the info on push hooks in the git docs.