Using git and Dropbox

2016-04-06

Dropbox isn’t version control. If you use git to version control your files, and have co-authors that use Dropbox then here is a way to use the two systems together.

Make your shared Dropbox folder have a separate repository

I’d like my shared Dropbox folder to be a full fledged git repository, and version control all relevant files there via git. However, git repositories usually contain a special .git/ folder in the root. Storing this special .git/ folder in a shared dropbox folder is a recipe for disaster. A non-git aware collaborator will certainly wreak havoc on it. Further, doing most git operations (even if they are simply checking the status) will push notifications to all your collaborator saying that a few git files have changed.

This can be annoying (and disastrous). A better alternative is to set up your shared Dropbox folder to be a git repository, but store the git repository (the .git/ folder) in a separate (non-dropbox) directory.

$ mkdir -p $HOME/.separate-gitroots
$ cd ~/Dropbox/shared/foo
$ git init --separate-git-dir=$HOME/.separate-gitroots/foo.git
Initialized empty Git repository in /home/gautam/.separate-gitroots/foo.git

This creates the git repository in $HOME/.separate-gitroots/foo.git instead of in ./.git/ as is customary. Now ./.git will be a plain text file (not folder) that contains the location of the foo.git directory above.

Obviously ./.git will be truly useless to anyone else sharing your Dropbox folders, so I recommend excluding it from the list of synchronized files. The dropbox exclude command above does this using Dropbox’s Selective sync feature asking your collaborators not to modify this file.

Working on a local copy.

I set up a local copy, away from Dropbox, to work on. This way a collaborator who makes changes while I’m working will not overwrite mine, and I can tell the two changes apart easily. I also use a centralized remote (so I can share it with git-aware co-authors), but you can do without it (if you know what you’re doing.)

Setting up the repositories

Let’s assume you have a git server and created an empty repository on it at git@yourserver.com:foo. We first add this remote into Dropbox, and put your shared files in it:

$ cd ~/Dropbox/shared/foo
$ git remote add origin git@yourserver.com:foo
$ git add paper.tex ... # (or use git add -Av .)
$ git commit --author 'Coauthor <who@doesnt.use.git>'
[master a484503] Blah blah (commit subject)
 1 file changed, 10 insertions(++++++)
$ git push -u origin master
Branch master set up to track remote branch master from origin.
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 6.80 KiB | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
To yourserver.com/foo
   9996b2d..f9d5e30  master -> master

Now set up a local copy by cloning this repository into ~/foo. Type:

$ git clone git@yourserver.com:foo ~/foo
Cloning into 'foo'...
remote: Counting objects: 545, done.
remote: Compressing objects: 100% (542/542), done.
remote: Total 545 (delta 341), reused 0 (delta 0)
Receiving objects: 100% (545/545), 691.49 KiB | 0 bytes/s, done.
Resolving deltas: 100% (341/341), done.

or use your favorite GUI client. You should now have your work in the remote repository git@yourserver.com, one clone in Dropbox (for your coauthors to edit) and one local clone in ~/foo for you to edit. (Of course, if you had local files you were already working on in ~/foo, you could have done the git remote add in ~/foo, committed, pushed and then pulled in Dropbox instead.)

Committing changes

When a collaborator make changes in Dropbox, you have to commit and push it for them, and pull it into your local copy.

$ cd ~/Dropbox/shared/foo
$ git commit -a --author 'Coauthor <who@doesnt.use.git>'
[master a484503] Blah blah (commit subject)
 1 file changed, 10 insertions(++++++)
$ git push
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 6.80 KiB | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
To yourserver.com/foo
   9996b2d..f9d5e30  master -> master    
$ cd ~/foo
$ git pull
Updating 9996b2d..f9d5e30
Fast-forward
 paper.tex        |  141 +++---
 refs.bib         |    5 +-
 3 files changed, 140 insertions(+), 6 deletions(-)

After the first commit as your co-author, you can just use --author Coauthor without typing the whole email address every time. Also, if you have only one co-author who will commit in Dropbox, then you can use git config to set user.name and user.email in the Dropbox repository, and not use --author above.

When you make changes:

$ cd ~/foo
$ git commit -a && git push
[master a484503] Blah blah (commit subject)
 1 file changed, 10 insertions(++++++)
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 6.80 KiB | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
To yourserver.com/foo
   9996b2d..f9d5e30  master -> master    
$ cd ~/Dropbox/shared/foo
$ git pull
Updating 9996b2d..f9d5e30
Fast-forward
 paper.tex        |  141 +++---
 refs.bib         |    5 +-
 3 files changed, 140 insertions(+), 6 deletions(-)

When you and your co-author simultaneously made changes

No problem. Git handles it painlessly. (I’m omitting the console output of git below for brevity.)

$ cd ~/Dropbox/shared/foo
$ git commit -a --author Coauthor && git push
$ cd ~/foo
$ git commit -a
$ git pull --rebase

The last command may warn you about conflicts (if you and your co-author edited similar portions of the same file). Follow the instructions displayed by git. Once you’re done, push your changes and pull them into Dropbox as shown in the previous section.

Creating branches for a co-author

Often when when I’m editing my local copy my collaborator makes changes in Dropbox simultaneously. For simple changes you can merge them quickly as above. If there have been more elaborate changes, I usually create a branch and merge it as follows.

  1. Commit and push your collaborators changes to a new branch

    $ cd ~/Dropbox/shared/foo
    $ git checkout -b coauthor-b1
    $ git commit --author Coauthor -a
    $ git push --all
    
  2. Merge your co-authors changes in your local copy. (Or rebase it, if you know what you are doing.)

    $ cd ~/foo
    $ git commit -a
    $ git fetch origin coauthor-b1
    $ git merge coauthor-b1
    $ git push
    
  3. Pull them in the shared Dropbox folder.

    $ cd ~/Dropbox/shared/foo
    $ git checkout master
    $ git pull
    

๐Ÿ—ซ Comments

  • Ricardo Lima
    .git/ location

    Ricardo Lima (2017-12-20 07:56:17 EST)

    Hey Gautam,

    Nice post. Thank you.

    I do not understand this part “This creates the git repository in $HOME/foo/.dropbox.git instead of in ./.git/ as is customary. Now ./.git will be a plain text file (not folder) that contains the location of the true git repository.”

    How does the file $HOME/foo/.dropbox.git is created? With the commands above? Isn’t it created in $HOME/.separate-gitroots/shared.git? Also when you say “Now ./.git will be a plain text file (not folder) that contains the location of the true git repository.”, do you mean “… of the true .git directory?

    Best,

    Ricardo

  • Gautam Iyer
    Re: .git/ location

    Gautam Iyer (2017-12-20 12:29:41 EST)

    On 2017-12-20 at 07:56:17 EST, Ricardo Lima wrote

    How does the file $HOME/foo/.dropbox.git is created? With the commands above? Isn’t it created in $HOME/.separate-gitroots/shared.git?

    Apologies, this was a typo which I just fixed.

    Also when you say “Now ./.git will be a plain text file (not folder) that contains the location of the true git repository.”, do you mean “… of the true .git directory?

    Yes. If you do cat .git, you should see something like

    gitdir: /home/gautam/.separate-gitroots/foo.git
    

    I fixed it above as well, thanks for pointing it out.

    GI

  • SSJ
    Dropbox exclude

    SSJ (2019-02-25 15:56:00 EST)

    Hi, Any idea how to get $ dropbox exclude add .git to work with windows? I have the windows dropbox app installed but cant seem to get the dropbox command to work in command line or gitbash Thanks

  • Gautam Iyer
    Re: Dropbox exclude

    Gautam Iyer (2019-02-27 15:11:59 EST)

    Any idea how to get $ dropbox exclude add .git to work with windows?

    I don’t know how to do this on windows. But I’m guessing the windows Dropbox client has a way to exclude files. You just need to get it to exclude the file .git from being synced. But if you don’t, it’s not such a big deal – the file will be a plain text file which Dropbox can happily sync. Just ask your collaborators to avoid modifying / deleting this file.

  • Anonymous
    Re: Dropbox exclude

    Anonymous (2020-04-25 03:57:49 EDT)

    To answer SSJ, it appears that the windows version does not have an “equivalent” (in terms of Linux) command line version. The GUI however lets you untick “.git” (chanced on this blog, so this may be dated)

  • Pete
    Dropbox exclude

    Pete (2020-12-27 03:15:57 EST)

    If you save following line below as a snippet.ps1 file under windows and run it in powershell you might be able to exclude it from syncing.

    Set-Content -Path “C:\example_repository.git” -Stream com.dropbox.ignored -Value 1

  • Dr.Feng
    Re: Dropbox exclude

    Dr.Feng (2021-08-05 06:00:16 EDT)

    Pete’s solution works very well in windows. Actually the command comes from dropbox official help doc here: https://help.dropbox.com/files-folders/restore-delete/ignored-files

  • Gautam Iyer
    Dropbox Exclude

    Gautam Iyer (2021-08-06 09:45:02 EDT)

    Initially I recommended excluding the .git file from dropbox using dropbox exclude or the selective sync feature. As of today (Aug 2021), this doesn’t work for me on Linux. If I exclude a file, dropbox prevents a file with that name being created locally. It’s simpler to just tell your collaborators to not modify that file…

  • Dr.Feng
    Re: Dropbox Exclude

    Dr.Feng (2021-08-11 08:47:03 EDT)

    Hi, Prof. Iyer. Thank you for the update.

  • Aaron
    mix of git-savvy & git-naive coauthors

    Aaron (2022-06-16 11:29:25 EDT)

    This looks absolutely great, thanks for this guide! It seems to be the best out there.

    Have you ever tried this approach when most of your coauthors don’t use git, but one of them does? The issue seems to arise that the .git file specifically references my personal home directory when pointing to the separate git repo. Dereferencing it using $HOME in the .git file does not work. So I imagine that the other git user will run into an issue when they try to clone the repo, since their home dir is different.

    Is this something you have run into or have a solution for? Thanks in advance!

  • Gautam Iyer
    Re: mix of git-savvy & git-naive coauthors

    Gautam Iyer (2022-06-16 12:39:43 EDT)

    Have you ever tried this approach when most of your coauthors donโ€™t use git, but one of them does? The issue seems to arise that the .git file specifically references my personal home directory when pointing to the separate git repo.

    Ideally the best way to deal with this is to exclude the .git file from Dropbox, and let each git savvy co-author will have their own personal .git file pointing to their local git repository. Unfortunately, this stopped working: The last I tried, when I excluded a file from Dropbox, it deleted it from the disk ๐Ÿ™„.

    There is a way around this. Once your repository is setup, delete the .git file. Now run the command

    export GIT_DIR=$HOME/.separate-gitroots/foo.git
    

    before running your git commands in that directory. Alternately add --git-dir=$HOME/.separate-gitroots/foo.git as an option to all your git commands.

    GI

๐Ÿ“ฎ Leave a comment (Spammers beware: All comments are moderated)

Sorry. There was an error submitting your comment. Please try again, or contact me if the problem persists.
Sending comment; please wait.
Thanks. Your comment was successfully submitted. It will appear here shortly if it isn't spam.