fuse-based filesystem for working with source trees stored in git repositories
Switch branches/tags
Clone or download
Pull request Compare This branch is 35 commits ahead of wereHamster:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
Makefile
README
README.md
main.c

README.md

Git as a filesystem: gitfs

After mounting your git repository, but before unmounting it :), you can browse it in parallel on several terminals, or file browsers, going to the mount point, be it /mnt/fuse.

Then, gitfs will accept any path /mnt/fuse/commit-ish/tree/blob to refer to the file tree/blob as it was when commit-ish was committed.

The commit-ish part of the path can take any of two forms:

  • Naked it refers to one revision, or commit.
  • Prefixed with an underline character, '_', it refers to a range of revisions, or commits.

The concept of revision is explained in man gitrevisions.

The special path /mnt/fuse/ contains a dir listing with HEAD, all the branches, and all the tags in the repo, plus a special dir named '_'.

Under each /mnt/fuse/commit-ish/, in adition to the the commit tree, the current dir '.', and its file system parent '..', there is also one entry for each of the git parents of the commit, as a '^' if it has only one, or as '^1', '^2', and so on, if it has more than one.

Special dir /mnt/fuse/_ contains again a dir listing with HEAD, all the branches, and all the tags in the repo. But here /mnt/fuse/_/commit-ish/ points to /mnt/fuse/_commit-ish/, which is a dir listing with a link to each of the commits that are reachable from commit-ish, that is, to all of its ancestry.

The gitfs filesystem reports two extended attributes:

  • user.sha1: the sha1 of the tree or blob object;
  • user.commit: the sha1 of the commit where the tree or blob object is.

The gitfs filesystem is read-only, and the date of any object in a commit tree is the date of the commit. If you need a writable filesystem, please use a unionfs filesystem on top of the gitfs mount point.

Easy navigation

Path /mnt/fuse/_commit-ish/commit-ish2/tree/blob is treated as if it were /mnt/fuse/commit-ish2/tree/blob; that is, the prefixed commit-ish is ignored if anything follows it. This way, after a cd /mnt/fuse/_commit-ish, you can issue a ls -lat to see all of its ancestry, and then go to any of its ancestors with a simple cd.

Also, to allow an easy navigation, a path as /mnt/fuse/master/~3/^2/tree/glob is treated as if it were /mnt/fuse/master~3^2/tree/glob, so you can go, for example, from /mnt/fuse/HEAD to its git grandparent just doing twice cd ^, or once cd ^^ (or cd ^/^ or cd ~2 or ...).

In the commit-ish section of path /mnt/fuse/commit-ish/tree/glob, every ':' char is converted to char '/' when interfacing with git. This way we can use any refname, for example, path /mnt/fuse/origin:master/ refers to git origin/master remote ref.

Preparing the system

To make gitfs, first compile git, and then compile gitfs. But, before any compiling, we have to install some packets, and join user to groups staff and fuse. Below is how I did it in a standard Debian Wheezy.

user@PCBox:~$ su -
root@PCBox:~# apt-get install fuse libfuse-dev attr libattr1-dev \
                              libcurl4-gnutls-dev libexpat1-dev gettext zlib1g-dev libssl-dev
root@PCBox:~# adduser user staff
root@PCBox:~# adduser user fuse
root@PCBox:~# exit

You may need to reboot, or as root do: chown root:fuse /dev/fuse. Also, you may need to restart the shell session, doing su user, for user to be on groups staff and fuse; of course, after the reboot, this will also be set.

Compiling git

Now we can compile git. Just get the sources, and do a make.

user@PCBox:~$ cd /usr/local/src/
user@PCBox:/usr/local/src$ wget https://github.com/git/git/archive/v1.8.4.tar.gz
user@PCBox:/usr/local/src$ tar -zxf v1.8.4.tar.gz
user@PCBox:/usr/local/src$ cd git-1.8.4/
user@PCBox:/usr/local/src/git-1.8.4$ make prefix=/usr/local all
user@PCBox:/usr/local/src/git-1.8.4$ cd

You may want to install the just compiled git, although it is not needed. Should you wanted to install it, please do make prefix=/usr/local install.

Compiling gitfs

Just get the sources, and do a make.

user@PCBox:~$ cd /usr/local/src/
user@PCBox:/usr/local/src$ wget https://github.com/ramoncasares/gitfs/archive/v0.3.tar.gz
user@PCBox:/usr/local/src$ tar -zxf v0.3.tar.gz
user@PCBox:/usr/local/src$ cd gitfs-0.3/
user@PCBox:/usr/local/src/gitfs-0.3$ make
user@PCBox:/usr/local/src/gitfs-0.3$ cd

The gitfs executable is: /usr/local/src/gitfs-0.3/gitfs.

Mounting a git repo as a filesystem

This is optional, but to be able to mount git as an ordinary user, you need to add yourself to group fuse (already done), and prepare a mount point. We will prepare /mnt/fuse to mount fuse filesystems.

user@PCBox:~$ su -
root@PCBox:~# cd /mnt
root@PCBox:/mnt# mkdir fuse
root@PCBox:/mnt# chown root:fuse fuse
root@PCBox:/mnt# chmod 775 fuse
root@PCBox:/mnt# exit

Now we will clone the gitfs repo from the GitHub. This is completelly optional, but illustrates how to clone the repo, and we will use it to show the use of gitfs. We will put the repo in dir ~/git/gitfs/.

user@PCBox:~$ mkdir git
user@PCBox:~$ cd git/
user@PCBox:~/git$ git clone https://github.com/ramoncasares/gitfs.git
user@PCBox:~/git$ cd

To mount the just cloned git repo, in the just created mount point, you have to go to the dir where your repo is, and call the gitfs executable from there.

Example session

user@PCBox:~$ cd git/gitfs/
user@PCBox:~/git/gitfs$ /usr/local/src/gitfs-0.3/gitfs /mnt/fuse -f &
user@PCBox:~/git/gitfs$ cd /mnt/fuse
user@PCBox:/mnt/fuse$ ls -la
total 4
dr-xr-xr-x+  2 user user    0 sep 22 08:58 _
dr-xr-xr-x+  2 user user    0 sep 22 08:58 .
drwxr-xr-x  15 root root 4096 sep  8 12:25 ..
dr-xr-xr-x+  2 user user    0 sep 13 12:40 github:HEAD
dr-xr-xr-x+  2 user user    0 sep 13 12:40 github:master
dr-xr-xr-x+  2 user user    0 jul 20  2009 github:original
dr-xr-xr-x+  2 user user    0 sep  4  2009 github:temp
dr-xr-xr-x+  2 user user    0 sep 20 14:02 HEAD
dr-xr-xr-x+  2 user user    0 sep 20 14:02 master
dr-xr-xr-x+  2 user user    0 sep 13 12:40 origin:master
dr-xr-xr-x+  2 user user    0 sep 13 12:40 qratos:master
dr-xr-xr-x+  2 user user    0 ago 31 10:39 v0.1
dr-xr-xr-x+  2 user user    0 ago 31 11:39 v0.1.1
dr-xr-xr-x+  2 user user    0 sep  5 20:44 v0.2
dr-xr-xr-x+  2 user user    0 sep 22 10:05 v0.3
user@PCBox:/mnt/fuse$ ls -lat _v0.1..v0.2
total 0
dr-xr-xr-x+ 2 user user 0 sep 22 08:58 .
dr-xr-xr-x+ 2 user user 0 sep 22 08:58 ..
dr-xr-xr-x+ 2 user user 0 sep  5 20:44 1dd9f966f524862cad0332bc9f8311ccad594858
dr-xr-xr-x+ 2 user user 0 sep  5 20:43 35ab19d4ca6582cf0771fe885003185340a16f79
dr-xr-xr-x+ 2 user user 0 sep  5 19:38 ca9d9200d0fb21111a98c39239a800c61fb52549
dr-xr-xr-x+ 2 user user 0 sep  5 19:35 e9cff5696b8e8faa6db81b0429fab8ea3bed8634
dr-xr-xr-x+ 2 user user 0 sep  5 19:30 51f6f469c05ad8e22f9acda41ca5eef4c02834da
dr-xr-xr-x+ 2 user user 0 sep  5 10:15 13c89550710450ebb12b4596379d4bbac38f20e3
dr-xr-xr-x+ 2 user user 0 sep  5 10:15 300b4ed1ed50dfa6b33680e3d67c95a482889af4
dr-xr-xr-x+ 2 user user 0 sep  1 08:25 2bc1070e20affa7f7abdeeb1dab870b66c2c00b2
dr-xr-xr-x+ 2 user user 0 ago 31 13:50 9b8c9aa7a6c46190065869c0b21a977c9f55d62f
dr-xr-xr-x+ 2 user user 0 ago 31 11:39 06ddc7ed0703abc10bba1feaac24ed1e2a976009
dr-xr-xr-x+ 2 user user 0 ago 31 11:16 34b0cf85cef42d6e25a10b5c6419cfe836746586
dr-xr-xr-x+ 2 user user 0 ago 31 11:04 be7dc5afdf2ddc02ca16233e074e7a355660612e
dr-xr-xr-x+ 2 user user 0 ago 31 11:02 2cb26610bd5b384a23a3ac0b52cf37c53193ea5b
user@PCBox:/mnt/fuse$ cd v0.1
user@PCBox:/mnt/fuse/v0.1$ ls -la
total 0
dr-xr-xr-x+ 2 user user    0 ago 29 20:10 ^
dr-xr-xr-x+ 2 user user    0 ago 31 10:39 .
dr-xr-xr-x+ 2 user user    0 sep 22 08:58 ..
-r--r--r--+ 1 user user 9093 ago 31 10:39 main.c
-r--r--r--+ 1 user user  430 ago 31 10:39 Makefile
-r--r--r--+ 1 user user 5192 ago 31 10:39 README
user@PCBox:/mnt/fuse/v0.1$ cd ^
user@PCBox:/mnt/fuse/v0.1/^$ ls
total 0
^  main.c  Makefile  README
user@PCBox:/mnt/fuse/v0.1/^$ head -6 README
Making gitfs
============

To compile gitfs, first get git and gitfs sources,
then compile git, and finally compile gitfs.

user@PCBox:/mnt/fuse/v0.1/^$ getfattr -d README
# file: README
user.commit="d45be49c223d47c4da8ba7f487b3e7c6ccd8298f"
user.sha1="53e4aff7e0b447202fc3b8c5bd9dbbbfe6c44af3"

user@PCBox:/mnt/fuse/v0.1/^$ getfattr -d .
# file: .
user.commit="d45be49c223d47c4da8ba7f487b3e7c6ccd8298f"
user.sha1="73f8c00cd7d5acc7797be8a127f5be935fbe3728"

user@PCBox:/mnt/fuse/v0.1/^$ cd
user@PCBox:~$ fusermount -u /mnt/fuse

Aknowledgements

This is a fork of wereHamster-gitfs, by Tomas "wereHamster" Carnecky. Branch original of Tomas' repo contains gitfs sources by Mitchell Blank Jr, the inspiration for our gitfs.