Syncing Git Repos Between Computers

Musa Haydar | Mar 03, 2024

This post outlines a method for syncronizing a Git repository between two computers, where one is running Linux or MacOS (the "local" machine) and the other is running Windows (the "remote" machine). My use case for this was to synchronize my Obsidian vault between my laptop and desktop computers, but this method can really be used to synchronize any content between computers using Git, without using any intermediary Git server.

The approach taken is as follow: first, we configure the SSH server on the remote machine through Windows Subsystem for Linux (WSL). Then, we create a repo on the remote machine which the local machine will pull from and push to.

Setting Up SSH via WSL

The first step will be to configure the SSH server on the Windows machine through which Git will connect. I opted to do this through WSL-2 (Ubuntu), since that will make it easy to run Git commands on my Windows machine as well. My source for these instructions is Julio Merino's blog post on this topic. Take a look at the troubleshooting section at the end of this post if you encounter any errors while starting the SSH server. For instance, on my machine, I had WSL-2 installed beforehand, but had to reinstall the SSH service before it could run.

Note that on this page, an initial $ symbol represents the prompt of a WSL command and a > symbol represents the prompt of a Windows Powershell command. Neither are part of the actual command.

On WSL, run the following command to start the SSH server:

$ sudo /usr/sbin/service ssh start

The following command can be used to check the status of the SSH server:

$ systemctl status ssh.service

If the service started successfully, the output should include something like this—note the "active (running)":

● ssh.service - OpenBSD Secure Shell server
    Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
    Active: active (running) since Sun 2024-03-03 17:36:43 EST; 1h 57min ago

Next, we'll configure the port we want the SSH server to listen to. I expect the default port may be used since Git will be operating over SSH, but I used the custom port 2022 as the guide linked above did, perhaps so that one might run SSH on their Windows machine via port 22. (Anyway, it seems that port 2022 is no longer the well-known port of any extant application.) We can configure the port and restart the service with the following commands:

$ sudo sed -i -E 's,^#?Port.*$,Port 2022,' /etc/ssh/sshd_config
$ sudo service ssh restart

Next, we have to open a firewall rule on Windows to allow incoming traffic on port 2022. (Again, credit for these instructions is to Julio Merino) In Powershell (with administrator privleges) run the following command:

> New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd) for WSL' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 2022

In Merino's words: "And then we have to route incoming traffic on the physical interface to the WSL interface via a 'port proxy' rule. This is made extra complicated because the IP given to the WSL instance is not stable over time, so we need to figure that out dynamically." We'll create a batch script called sshd.bat. The contents of the file will be the following:

@echo off
setlocal

C:\Windows\System32\bash.exe -c "sudo /usr/sbin/service ssh start"

C:\Windows\System32\netsh.exe interface portproxy delete v4tov4 listenport=2022 listenaddress=0.0.0.0 protocol=tcp

for /f %%i in ('wsl hostname -I') do set IP=%%i
C:\Windows\System32\netsh.exe interface portproxy add v4tov4 listenport=2022 listenaddress=0.0.0.0 connectport=2022 connectaddress=%IP%

endlocal

Store this file somewhere you remember, as you may need to run it before you attempt to connect over SSH in the future. You can also follow these instructions to run this script automatically on login (though you may need to ensure WSL starts before sshd.bat is run—I didn't bother with this, as it seems sshd.bat doesn't need to be run frequently).

At this point, the SSH server over port 2022 should be accessible from either machine. You can connect to it from SSH on Powershell (via ssh -p 2022 <user>@localhost) or from the local machine (via ssh -p 2022 <user>@<machine>.local) to ensure that it's working (filling in <user> and <machine> with the WSL username and Windows computer name respectively).

Configuring Git

Now, we'll create the Git repo on the remote machine and configure Git on the local machine to push to it. On the remote machine, we'll create a new repo with the following commands:

$ mkdir path/to/repo
$ cd path/to/repo
$ git init
$ git checkout -b tmp

Per the last command, we checkout a branch (in this case, tmp) different from the one we'll be pushing to (in this case, master); Git will complain when we try to push otherwise.

Now, on the local machine, we need to configure Git to connect to the remote machine via port 2022 by appending the following lines to ~/.ssh/config:

Host <machine>.local
    User <user>
    Port 2022

Finally, we'll run these commands in the local machine's repo to push it to the remote repo. This assumes that the remote repo named "origin" is not in use, for example by a GitHub repo. If this is not the case, we can simply give the remote branch a different name.

$ git remote add origin <user>@<machine>.local:path/to/repo
$ git push origin master

Once everything is set up, we can take the following steps to push to our remote repo in the future:

  • Ensure the SSH server is running on WSL on the remote machine with systemctl status ssh.service; if necessary start it with sudo /usr/sbin/service ssh start
  • Run sshd.bat if the connection from local fails
  • Push to the remote repo using git push

If you check out the master branch on the remote machine, you'll need to pull your changes to the local repo and then temporarily checkout another branch before you can push your changes to it.

Troubleshooting SSH on WSL

● When setting up the SSH server on my machine, I encountered a problem where the server could not start. Unfortunately, I was unable to reproduce the exact error. However, if none of the following troubleshooting advice works, it can't hurt to reinstall the SSH server package, which was what resolved my issue:

$ sudo apt-get remove --purge openssh-server
$ sudo apt-get install openssh-server

● If running git push on the local machine hangs (without any output or error), ensure the ~/.ssh/config local machine name is correct. Note that the remote machine name name is case sensitive.

● If running sudo /usr/sbin/service ssh start produces the following error

 * Starting OpenBSD Secure Shell server sshd
   sshd: no hostkeys available -- exiting.

generate SSH keys with the following command:

$ sudo ssh-keygen -A

● If starting the SSH server and checking its status produces the following output

$ sudo /usr/sbin/service ssh start

* Starting OpenBSD Secure Shell server sshd

$ systemctl status ssh.service

System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

then you need to enable systemd on WSL-2. More information on this issue can be found here. The steps for this are the following: update to WSL-2 by running wsl --update in Windows Powershell. Then, in WSL, add the following lines to /etc/wsl.conf:

[boot]
systemd=true

Finally, restart WSL-2 (run wsl --shutdown in Powershell)