Error 

Setting Up Version Control on your Home Directory

13 Comments, 1,096 views
Posted August 1, 2009 at 01:08am in Linux with tags , ,

UPDATE: I just initialized a mercurial repository in my home dir as well to have a side by side comparison of the two. If you are interested in using mercurial please look at the bottom for a few notes on setting it up.

In Ubuntu 9.04 a new application was introduced called etckeeper. This application uses various version control systems to store versions of files within etc. Some machines that I work on I keep my home directory very clean, and I go out of my way to keep things organized and stored in version control. I have dropped the ball on being so organized when it comes to my home desktop, but tonight, that changed. This is how to use version control with your home directory. I am not going to cover indepth topics about using Git or any other version control, this guide simply explains how to maintain a local repository.

The first step is to install your preferred version control system. In this case I am going to use git, since a lot of people are familiar with it.

sudo apt-get install git

Now we need to initialize our repository and prevent other users from having access.

$ cd ~
$ git init
Initialized empty Git repository in /home/user/.git/
$ chmod 700 .git

We don’t need to put every file under version control so we need to create a list of everything in our home directory and then remove what we don’t want. To do this we are first going to list all non-hidden files directories first, and then list all hidden files directories first followed by leaving out the current and parent directories. This list gets put in a file called .gitignore, a file that git reads to determine what files it should ignore.

$ ls -1 --group-directories-first > .gitignore
$ ls -1 --group-directories-first -A | grep '^\.' >> .gitignore
$ cat .gitignore
Applications
bin
Desktop
...
.cache
.checkbox
.compiz
...
.bash_aliases
.bash_history
.bash_logout
...
.xsession-errors

Now you should go through and remove files and directories you would like to have maintained in version control. You can also temporarily comment out a file with a # so that it will get added and then uncomment the file so that in the future changes will be ignored.

After editing .gitignore you can run ‘git status’ to verify the files that are not ignored.

$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       .bash_aliases
#       .bash_history
#       .bash_logout
#       .bash_profile
#       .bashrc
#       .gitconfig
#       .gitignore
#       .hgrc
#       .nvidia-settings-rc
#       .profile
#       .screenrc
#       .ssh/
#       .subversion/
#       .vim/
#       .viminfo
#       .vimrc
nothing added to commit but untracked files present (use "git add" to track)

Some things you may want to leave out like in my case I don’t really want to have the auth information for subversion or ssh private keys stored in version control. For those specific things you can add lines like the following to your .gitignore file.

.ssh/id_*
.subversion/auth/

To test what files will be added and what will not be added you can do a dry run.

$ git add -n -A
add '.bash_aliases'
...
add '.screenrc'
add '.ssh/config'
add '.ssh/known_hosts'
add '.subversion/README.txt'
add '.subversion/config'
add '.subversion/servers'
add '.vim/colors/astronaut.vim'
...

Now we need to add the files to git and commit them.

$ git add -A
$ git commit -m "Initial commit of files in home directory"

Now if you make a change to .profile you can easily revert it

$ echo 'testing' >> .profile
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   .profile
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout .profile
$ git status
# On branch master
nothing to commit (working directory clean)

And you’re done.

Mercurial

I have not decided which DVCS I will be using so I initialized a hg repository along side the git repository so that I can see the differences first hand. The mercurial command is ‘hg’ and the ignore file is .hgignore so this guide can be easily adapted to using mercurial. One nice benefit is that BitBucket’s free plan comes with a private repository so you can easily setup a remote repository to store it all.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • email
  • Twitter

13 Responses to “Setting Up Version Control on your Home Directory”

  1. cantormath Says:
    August 1st, 2009 at 7:31 am

    Nice howto…Looks good.

  2. bartman Says:
    August 11th, 2009 at 9:08 pm

    I’d like to warn you and your readers that putting .git in $HOME is very dangerous.

    Imagine what happens when you run a git command in ~/foo. git will look in ~/foo for a .git directory, and if it’s not found there it will look in ~/ and work it’s way up to /. If you accidentally run ‘git clean’ in a directory that has no .git repository it will run git clean against your ~/ directory. This can be very very bad as it will blow away all untracked files you own.

    This actually happened to a friend who used a script that converted hg repos to git repos. He used some script to convert a hg repository to git. The script had a bug, and called ‘git clean’ with the wrong options. Because git could not find a .git it looks up until it found ~/.git and he ended up losing all his files except for those he tracked in .git.

    What I do is to keep all my dot-files in ~/etc and have symlinks in ~/ to files in ~/etc. I share this ~/etc directory between computers, and it works really well.

    To add a file into the repository I’d do…
    cd ~/etc
    mv ../.vimrc vimrc
    git add vimrc
    git commit -m”added vimrc”
    dot-files install

    The script is here: http://github.com/bartman/dot-files

    Good luck.

    -Bart

  3. Peter Manis Says:
    August 12th, 2009 at 1:29 am

    Bart does have a good point, and if you are interested in doing this you should consider what he is saying.

    A couple things to remember are that you need to be careful with the commands you use, mistakes happen, but like think of it like ‘rm -rf’ I have not used that on a directory I did not want to delete. Something else is that you should be keeping regular backups of your information anyway so the impact of doing a ‘git clean’ on the wrong directory will not hurt you as much.

  4. Vic Says:
    August 13th, 2009 at 3:06 pm

    What about hosting the repository remotely? That seems most useful so that you can share files from your home directory among multiple workstations. Thoughts on initializing the repository or cloning it into the current working directory?

  5. Peter Manis Says:
    August 13th, 2009 at 3:55 pm

    That was actually my motivation for trying Mercurial. I already had a remote git setup, but wanted something else. Github did not offer a private repository with their free account and Bitbucket did. So that let me kill two birds with one stone… really get to play with a remote Mercurial repository and have it hosted remotely.

  6. Peter Manis Says:
    August 13th, 2009 at 4:01 pm

    Something else I should mention about Bart’s comment. If you are using Mercurial you have to explicitly enable a plugin to do a purge (hg equiv to ‘git clean’). I’m sure there are use cases for purge, but I don’t know that it needs to be enabled at a machine level. Why not just enable it at a repository level if that repository would benefit from being able to flush files and directories.

    In Mercurial you can also explicitly disable an extension.

    “To explicitly disable an extension that is enabled in an hgrc of broader scope, prepend its path with “!”, as in “hgext.foo = !/ext/path” or “hgext.foo = !” when path is not supplied.”

  7. Vic Says:
    August 13th, 2009 at 5:43 pm

    Peter,

    Could you post a tutorial about setting it all up with BitBucket? Initializing everything locally and merging with the repo on BitBucket, all of that?

    Thanks!

  8. Peter Manis Says:
    August 13th, 2009 at 6:17 pm

    Sure thing.

    I won’t get to it until the weekend, but I will make a new post on doing that so keep an eye out over the weekend or Monday.

  9. remin raphael (remin) 's status on Tuesday, 18-Aug-09 01:41:29 UTC - Identi.ca Says:
    August 17th, 2009 at 9:41 pm

    [...] http://pyverted.com/linux/setting-up-version-control-on-your-home-directory/2009/08/ [...]

  10. throughnothing Says:
    August 18th, 2009 at 3:19 pm

    I have been using git to track my home dir for a while, and its great. One thing I would say that could make it a little bit easier rather than having a huge list of ignores, is to ignore everything, and then explicitly unignore things you want to track. This also has the advantage that if you install new programs to test them out after setting this up and they write all kinds of ~/.* goodness to your home dir, git will automatically have them ignored unless u explicitly decide to track it/them.

    So anyway, I start with something like this:

    # Ignore Everything
    /*
    /.*
    *.swp
    *.swo
    .svn
    *~

    Basically this ignores everything, and ensures that .swp files and the like get ignored always. Then I will add the stuff that I want to track like this:

    # Configs/Scripts
    !/.gnupg
    !/.mutt
    !/.irssi
    !/.bashrc
    !/.profile
    !/.config/

    Thanks for the article.

  11. Peter Manis Says:
    August 18th, 2009 at 5:13 pm

    The benefit of not ignoring everything is that when you run git status or hg status files that have been added that you might not have been aware of will show up. By ignoring everything by default you will miss things you might have wanted to track sooner.

  12. MasterPi Says:
    August 25th, 2009 at 10:23 pm

    Aside from the issue with ‘git clean’, there’s also a problem if you are using this method to sync between your computers, as I used to do. Git considers anything you put in .gitignore to be completely worthless to you, and so has no qualms about overwriting it without trying to merge if you pull from another repository that has had the file added. (Example: you haven’t tracked .bashrc on one computer but you decide you want to track it and add it on another computer, then you pull into the first computer and it doesn’t attempt to do a merge at all, it simply overwrites your local copy). The symlinking solution is much better; I now have a ~/Settings which contains files I want to track and an install script that puts symlinks where they belong.

  13. HomeBasedBusinessaholic Says:
    August 27th, 2009 at 6:35 pm

    There are a lot of data from the site and I love it very much, it has become one of the things in my bookmark, thank you. Best Regards, Reader.



Leave a Reply