Skip to content

Instantly share code, notes, and snippets.

@edavis
Last active March 27, 2023 03:48
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save edavis/4191457 to your computer and use it in GitHub Desktop.
Save edavis/4191457 to your computer and use it in GitHub Desktop.
Use Dropbox as a git remote

Intro

Every developer eventually faces the challenge of managing their personal "dotfiles" among the different machines he or she uses.

This post details how I tackled this issue by using Dropbox as a git remote while avoiding the pitfalls of storing the repository itself in Dropbox.

In the beginning

My approach had been to store my dotfiles in a dedicated Dropbox folder and symlink them on each machine. It worked okay, but the lack of version control was beginning to be a problem. I wanted to be able to to track changes over time as well as have known "good revisions" to fall back on.

Early attempts

After deciding to use git to track my dotfiles, I needed to figure out how to share changes between my machines.

A lot of people use Github for this sort of thing, but I wanted to include sensitive information and didn't want to go the whole private repository route.

I already use Dropbox, so I thought why not see if I could use that to share changes between my dotfiles repositories on different machines.

Store repository directly in Dropbox

The simplest approach would have been to store the working directory and repository directly in Dropbox. However, nearly everything I read about this approach made it seem like repository corruption was a matter of "when" rather than "if." Dropbox was, after all, designed for .doc files, not the git object database.

Separate repository and working directory

I then tried storing the working directory in Dropbox while keeping the repository outside it. Theoretically, this would be a pretty neat solution that would quickly propagate files between machines while also getting the benefits of version control. However, I couldn't find a clean way to tell git "when in X directory, use Y as the git repository."

Patch files

The git project itself uses patch files sent via email to develop git, so I thought maybe I could replace email as the transfer mechanism and use patch files stored in Dropbox to share changes between my machines. I would run git format-patch -o ~/Dropbox/Patches/ <since>.. which would create a series of patch containing all commits starting with up to HEAD. But it became pretty clear format-patch was designed for sending topic branches that eventually get merged into a "canonical" repository rather than what I was trying to do.

A solution emerges

Luckily, after a bit more searching, I stumbled upon a pretty solid technique that leverages the easy and robust syncing ability of Dropbox with the benefits of git-backed version control.

Bundles

Bundles are a way to "export" your git repository as a single file. Bundles are used when you need to share commits between repositories without using the standard git protocols (i.e., git, ssh, http, etc.)

Creating the first bundle

For my situation, I needed to manage a home desktop and work laptop.

First, I created a ~/dotfiles/ directory on the desktop, populating it with dotfiles and symlinking as appropriate.

Once the git repository has been initialized and has at least one commit, we're ready to create the bundle:

desktop:~/dotfiles$ mkdir -p ~/Dropbox/Bundles/
desktop:~/dotfiles$ git bundle create ~/Dropbox/Bundles/dotfiles.bundle master

This creates a dotfiles.bundle file containing the entire history of the master branch.

Now set the bundle file as the origin remote and have your 'master' branch track 'origin/master':

desktop:~/dotfiles$ git remote add origin ~/Dropbox/Bundles/dotfiles.bundle
desktop:~/dotfiles$ git remote update
desktop:~/dotfiles$ git branch -u origin/master master

Clone on the laptop

Now let's clone the repository on the laptop.

laptop:~$ git clone -b master ~/Dropbox/Bundles/dotfiles.bundle

The '-b master' flag is needed to tell git which branch to initially checkout. As best I can tell, this is needed as 'git bundle' was designed to move commits between already cloned repositories rather than bootstrapping one as we're doing here.

There's now a complete copy of the dotfiles repository on my work laptop. Just symlink the files as necessary.

Pushing to Dropbox

Now let's say you make some changes on the laptop. Here's how you share those changes with the desktop:

laptop:~/dotfiles$ git commit -m 'Set EDITOR environment variable'
laptop:~/dotfiles$ git bundle create ~/Dropbox/Bundles/dotfiles.bundle master

This is the biggest change: instead of 'git push' you run 'git bundle' to create a new bundle file that contains the complete history of the master branch.

Updating origin/master

One caveat: creating a bundle will not update 'origin/master' (like 'git push' does) so it will still look like 'master' branch is ahead of 'origin/master' even though it isn't. Run 'git remote update' after creating the bundle to fix this.

To save yourself some keystrokes you could create a 'dropbox' alias here:

$ git config --get alias.dropbox
!git bundle create ~/Dropbox/Bundles/dotfiles.bundle master && git remote update

Merge changes back in

Now we hop back on our home desktop and want to pull in any changes made while on the laptop.

First, update the remote:

desktop:~/dotfiles$ git remote update

To git, the bundle is like any other remote. Finally, merge the new commit:

desktop:~/dotfiles$ git merge origin/master

And just like that you're up to date with the bundle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment