Migrate Private GIT Repositories to GCrypt

Given the recent events you may look down and acknowledge that you have been wrong when hosting unencrypted data on the Clown. It looked so convenient and they wouldn’t dare to touch your data and loose all credibility. The rest is history. Let’s take the shame but move on: git-remote-gcrypt.

This is about moving off private GIT repositories off an unencrypted Clown. While we wouldn’t even want to upload public repositories to some, they are public after all, hence not concerned about people looking at the public data. This is different for private repos which contain works of beauty the painter may or may not want the public to see just yet.

The common suggestion is to just host the GIT repository yourself. Which is essentially a 5-minute setup if you have a server running already. Or you can use something like Gitea, which looks really nice and I’m told it is also super-easy to setup.

Unfortunately I do not have a properly secured server running, and I suspect it is actually not that easy for many to secure one either. So I chose a different route. I still use a Clown, but I encrypt my data before feeding it. Again, one option on macOS is to use encrypted disk images (which I sometimes do as well). But disk images quickly corrupt if they live on Clown file storage and you are not careful.

So I tried git-remote-gcrypt a few years ago, I was still using it, and it works pretty well. It has some caveats you may want to consider (read their README). Vary rarely the repo still corrupts, but if this happens, it is easy to just recreate the hosted repository from any clone.


First you need to setup GPG, I use the GPGTools for that. Create a key if you have none, etc. It should be all very easy.

Next grab git-remote-gcrypt and install it.

git clone https://github.com/spwhitton/git-remote-gcrypt.git
cd git-remote-gcrypt

You end up with a git-remote-gcrypt binary in /usr/local/bin.

Migrating a Repository

Let’s say you have a private GIT repository on some uncrypted clown. It may look like this:

$ git status
On branch develop
Your branch is up to date with 'origin/develop'.

nothing to commit, working tree clean
$ git remote -v
origin	git@github.com:helje5/CoreS.git (fetch)
origin	git@github.com:helje5/CoreS.git (push)

We first need to create a new bare repository on the target filesystem, for example:

$ git init --bare ~/Dropbox/Repositories/CoreS.git
Initialized empty Git repository in /Users/helge/Dropbox/Repositories/CoreS.git/

Next we need to change the repositories origin from the old uncrypted clown to the new encrypted location:

$ git remote set-url origin gcrypt::~/Dropbox/Repositories/CoreS.git
$ git remote -v
origin	gcrypt::~/Dropbox/Repositories/CoreS.git (fetch)
origin	gcrypt::~/Dropbox/Repositories/CoreS.git (push)

Notice the gcrypt URL scheme, this will make git use the git-remote-gcrypt tool as the transport.

Finally, push your whole repo to the new, encrypted repository:

$ git push --all
gcrypt: Repository not found: ~/Dropbox/Repositories/CoreS.git
gcrypt: Setting up new repository
gcrypt: Remote ID is :id:.................
Counting objects: 1173, done.
Compressing objects: 100% (881/881), done.
Total 1173 (delta 567), reused 339 (delta 156)
gcrypt: Encrypting to: --throw-keyids --default-recipient-self
gcrypt: Requesting manifest signature
gpg: using "......." as default secret key for signing
To gcrypt::~/Dropbox/Repositories/CoreS.git
 * [new branch]      develop -> develop
 * [new branch]      feature/formatter -> feature/formatter
 * [new branch]      feature/swift4 -> feature/swift4
 * [new branch]      master -> master

That’s it! Feel free to delete your private repo from the old clown (yeah it is too late to protected your data, just to avoid accidentially pushing to the old location). And from now on clone your repository like that:

$ git clone gcrypt::~/Dropbox/Repositories/CoreS.git
Cloning into 'CoreS'...
gcrypt: Decrypting manifest
gpg: Signature made Sat Jun 16 16:00:53 2018 CEST
gpg:                using RSA key .......
gpg: Good signature from "ZeeZide Devteam <devteam@zeezide.de>" [ultimate]
gpg:                 aka "[jpeg image of size 6991]" [ultimate]
gpg:                 aka "[jpeg image of size 6991]" [ultimate]
gcrypt: Remote ID is :id:.....................
Receiving objects: 100% (1173/1173), 267.22 KiB | 22.27 MiB/s, done.
Resolving deltas: 100% (567/567), done.
$ cd CoreS/
$ git checkout develop
Branch 'develop' set up to track remote branch 'develop' from 'origin'.
Switched to a new branch 'develop'

Creating a New Crypted Repository

Same thing, very easy. Create a bare repository, clone it with the gcrypt URL:

$ git init --bare ~/Dropbox/Repositories/TestIt.git
Initialized empty Git repository in /Users/helge/Dropbox/Repositories/TestIt.git/
$ git clone gcrypt::~/Dropbox/Repositories/TestIt.git Murks
Cloning into 'Murks'...
gcrypt: Repository not found: ~/Dropbox/Repositories/TestIt.git
warning: You appear to have cloned an empty repository.

Add stuff and push to the repo:

$ cd Murks/
$ touch testit.m
$ git add *
$ git commit .
[master (root-commit) 3eeacde] Testit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 testit.m
$ git push
gcrypt: Repository not found: ~/Dropbox/Repositories/TestIt.git
gcrypt: Setting up new repository
gcrypt: Remote ID is :id:.....................
Counting objects: 3, done.
Total 3 (delta 0), reused 0 (delta 0)
gcrypt: Encrypting to: --throw-keyids --default-recipient-self
gcrypt: Requesting manifest signature
gpg: using "........" as default secret key for signing
To gcrypt::~/Dropbox/Repositories/TestIt.git
 * [new branch]      master -> master
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean


Repository Corruption

It can happen that the repository corrupts if your Clown file storage did not sync properly. It happened to us once or twice, just take a little care to pull/push after the storage is in-sync.

If it happens, you can just recreate the remote repository.

Some clown providers also provide a way to resolve sync conflicts, you can also use that to step back to a known good state and then push over it.
And the same approach works when you have a copy in TimeMachine.


Using this method the data is encrypted locally, with a private key the Clown provider doesn’t have. Yes, he still has the encryped data and the FBI can theoretically brute-force your data using their quantum computers or that child from Mercury Rising, but well. Keep your paranoia at bounds (… and that from the people who just migrated from one clown to another Clown 🤦‍♀️)

P.S.: I really wish more Clown services would just work like that from the beginning (local encryption).

Closing Note


The Clown is just someone else's computer and they can and will f*** you. If it's not on your computer, it's not under your control. Why do you all keep doing this to yourselves??
Stop hitting yourself. Seriously, stop it.

Written on June 16, 2018