After using GitHub to contribute to a project the other day, I got to thinking about other uses for Git. One was to keep a backup of my
~/bin folder. I write a lot of one-off scripts to make my life easier. Most of the time they’re under 20 lines and previous versions aren’t really needed. But sometimes1 I break things. Other times I’ll go back and wonder what the hell was I thinking.
I already use Dropbox, so why not put a repository there? I just prefer to have the files separate. There’s some talk about how the Dropbox backup version will conflict with the Git files. I’ll only be using it for a bare repository not a working directory. So Dropbox can do it’s thing and it won’t cause me problems.
Since I also use Bitcasa Drive, it seems natural to make that into my upstream repository. Bitcasa is different from Dropbox in that the files stored there are not on your local hard drive. They’re on the Bitcasa drive which is mounted as a network share. So it is true off-site backup. Access to it also depends on having an Internet connection. It’s a place for backups not daily work.
Once set up, I’ll be able to commit changes to either or both remote repositories. If I’m working offline I can push commits to Dropbox and have them synced up later. The reason to add Bitcasa is to have another backup and Git makes this easy.
Most of the guides I found were for creating a new project. I already had a folder of scripts, so the steps are little different. The basic set up is the same. Initialize the repository, then add the files and make the first commit. Now this folder is version controlled.
$ cd ~/bin $ git init Initialized empty Git repository in ~/bin/.git/ $ git add * $ git commit -m "Start tracking ~/bin" \[master (root-commit) 393f7fd] Start tracking ~/bin 60 files changed, 1064 insertions(+) ...
To make it work with Dropbox we have to clone it into wherever Dropbox keeps it’s files. On my laptop, that’s
$ git clone --bare --no-hardlinks . ~/Dropbox/git/bin-git Cloning into bare repository ‘~/Dropbox/git/bin-git'... done.
Do the same for Bitcasa.
$ git clone --bare --no-hardlinks . /Volumes/Bitcasa\ Drive/git/bin-git Cloning into bare repository '/Volumes/Bitcasa Drive/git/bin-git'... done.
- Git will create any folders needed, so there’s no need to create
- I changed the name to
bin-gitso I’ll remameber exactly what it is when looking at file names.
- The option
--no-hardlinksmakes sure the files are physically copied. This might be the reason some people have problems with Dropbox.2
- Don’t forget the dot!
.means use the current folder.
Now we have our remote repositories but they aren’t usable just yet. We can link them with the
remote add command.
$ git remote add origin ~/Dropbox/git/bin-git $ git remote add upstream /Volumes/Bitcasa\ Drive/git/bin-git
I wanted a simple way to remember what I had set up. My
~/bin scripts aren’t something I work on everyday. So the less remembering I have to do, the better.
First track Bitcasa as the default.
$ git push --set-upstream upstream Branch master set up to track remote branch master from upstream. Everything up-to-date
The way I set up a working folder was to create a new branch for Dropbox called amazingly enough
$ git co -b dropbox Switched to a new branch 'dropbox'
This will be the branch that I’ll use for most of my work. I can also set it to push to Dropbox as the default.
$ git push --set-upstream origin dropbox Total 0 (delta 0), reused 0 (delta 0) To ~/Dropbox/git/bin-git * [new branch] dropbox -> dropbox Branch dropbox set up to track remote branch dropbox from origin.
Now while in this branch,
git push will do what I expect. It will push the
dropbox branch to the Dropbox repository.
The way I’ll uses these are:
dropboxbranch: local saves of my commits, where most of my work happens.
origin/dropboxbranch: local changes are pushed here to be saved on Dropbox.
masterbranch: I’ll merge
dropboxinto this when I add new files or have major changes.
origin/masterbranch: the local
masterbranch saved on Dropbox.
upstream/masterbranch: the local
masterbranch saved on Bitcasa.
In this case I’ve made changes to file named
target.rb in the
dropbox branch. Here’s how I’d sync everything up.
Switch to the main branch:
$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'upstream/master'.
Bring my working changes up to the branch
$ git merge dropbox master Updating 1d3f955..44d996e Fast-forward target.rb | 1 + 1 file changed, 1 insertion(+)
Save to Bitcasa:
$ git push upstream master ... To /Volumes/Bitcasa Drive/git/test/ 1d3f955..44d996e master -> master
Save to Dropbox:
$ git push origin master Total 0 (delta 0), reused 0 (delta 0) To /Users/jenn/Dropbox/git/test/ 1d3f955..44d996e master -> master
Switch back to the working branch:
$ git checkout dropbox Switched to branch 'dropbox' Your branch is up-to-date with 'origin/dropbox'.
The usual update for saving working changes to Dropbox:
$ git push Everything up-to-date
With the various backup services available and the number of ways to use Git, the permutations of someone’s “perfect” system are endless. This is the way I like to work. It mirrors a GitHub project workflow. Once I started thinking that way, it became easier to make everything work like that.
There are also a few hidden benefits.
The Dropbox repository folder can be shared with other people. Giving other team members write access to the folder is a quick way to share code. But since the Dropbox server doesn’t speak Git, there’s a chance of files being overwritten. If this were to happen the clean copy on Bitcasa could be used to restore the project.
It can also be shared via a URL, and be downloaded as a zip file from the Dropbox site. This way teammates can quickly grab the files with the commit history intact.
“It’s like living in the future, man!”
- More often than not. That’s learning for ya’! ↩
- This might be the source of people’s problem with Git and Dropbox. The default behavior for Git is to create hard links on the local drive. This would mean the Dropbox files are updated as frequently as the working files. It’s better to have independent copies and have it work like a remote repository. ↩