Synchronize Git repositories between dom0, a dedicated SyncVM, and GitHub in Qubes OS.
This script enables you to keep full Git history while respecting Qubes’ strict isolation model:
- dom0: edit files, stage, and commit (but never connect to the network).
- SyncVM: acts as a proxy — it receives commit bundles from dom0 and pushes them to GitHub.
- GitHub: stores your full repository history.
To stay reasonable secure: Please review and understand what the script does before adding it to your own qubes installation (as with every other piece of code you get from the internet ;-)
Qubes OS intentionally disconnects dom0 from the network for security.
That means you cannot git push from dom0 directly.
This script provides a secure workflow:
- Keep real Git history in dom0.
- Use
git bundleto export commits from dom0. - Transfer the bundle to SyncVM via
qvm-run --pass-io. - SyncVM imports the commits and pushes to GitHub.
- Optionally, SyncVM can pull updates from GitHub and copy them back to dom0.
-
Copy the script into dom0:
sudo install -m 755 qubes-git-sync /usr/local/bin/qubes-git-sync
-
Adjust these variables in the script if needed:
SYNCVM="my-git-sync"→ name of your dedicated AppVM that has network access to GitHub.GITHUB_USER="your-github-username"→ your GitHub username.ALL_REPOS="my-qubes another-repo scripts-docs"→ list of repositories managed by--all.
-
In your SyncVM:
- Configure SSH access to GitHub (e.g. deploy your SSH keys).
- If you don´t have exuisting SSH keys: run ssh-keygen and copy & paste ./ssh/id_ed25519.pug to github > settings > SSH keys
- Ensure
gitis installed.
-
Make sure that user.email and user.name for git commits are setup correctly in the SyncVM an dom0! This is required so that pushing commits will work. To do so run the following commands:
git config --global user.name 'NAME'git config --global user.email 'EMAIL'
-
You need to run git at least once in the SYNCVM to answer the question regarding a new SSH key.
- The easiest way is to run a
git clone git@github.com:<USERNAME>/<REPOSITTORY.git>. After this the script from dom0 should work flawlessly
- The easiest way is to run a
-
In dom0
- Edit your files as usual.
- Stage and commit changes:
git add file1 file2 git commit -m "Describe your changes"
-
Sync changes to GitHub
qubes-git-sync gitpush <repository>
This will:
- Create a
git bundlein dom0. - Transfer it securely to your SyncVM.
- Import the bundle and push commits to GitHub.
- Create a
-
Pull updates from GitHub into dom0
qubes-git-sync gitpull <repository>
This will:
git pullin SyncVM from GitHub.- Copy the updated repository tree back to dom0.
Push one repository:
qubes-git-sync gitpush my-qubesPush all repositories defined in ALL_REPOS:
qubes-git-sync gitpush --allPull latest changes from GitHub into dom0:
qubes-git-sync gitpull my-qubesAll actions are logged in dom0 at:
~/.qubes-git-sync.log
- dom0 never connects to the network; only SyncVM interacts with GitHub.
- Only committed changes are synchronized. Uncommitted edits in dom0 will not be included.
- Temporary bundle files are removed after each sync (both in dom0 and SyncVM).
- Only the
mainbranch is synchronized. - Merge conflicts are not automatically resolved — the script enforces fast-forward merges only.
- If you forget to commit in dom0 before running
gitpush, no changes will be transferred.
GPLv3 License – see LICENSE file for details.
- 👉 Tested successfully on Qubes 4.3.0
- 👉 With this setup, you can safely manage your configuration and documentation repos in dom0 while still keeping them synchronized with GitHub.
- 👉 If you run into issues do not hesitate to open a github issue. Please include details how to reproduce the issue and also the exakt error messages you are getting.