This is an old revision of the document!
Description
Current Implementation
SVN Implementation
Hg Implementation
Git Implementation
Git's repository format is very simple. There are various files:
- commits which have a commit message, a pointer (sha1 hash) to a tree, and pointers to parents of the commit
- trees which have lists of blobs with pathnames with modes and pointers to other trees (directories)
- blobs which have file contents
- [signed] tags which have a tag description and a pointer to a commit.
A branch is just a pointer to a commit, and since each commit points at its parents, you get the entire history from a single sha1 name. Each file is named by its sha1 hash, so it's easy to verify file contents for corruption using git-fsck-objects.
git-fsck-objects has other uses, too. If you were doing some complicated operation and realized you reverted an important change, or you crashed and fsck left one of your branch files empty, you can run git-fsck-objects to find what objects in your repository are unreferenced, use git-show on the commits to see which one is right, and then create the branch again. I've used this when I made a mistake in a rebase operation and realized it several commits down the road – I recovered my old branch and just replayed my new commits on top of it.
As is, this file store would be a very inefficient mechanism – no compression of files that are very similar but have different hashes. This is where packs come in. Generally, when a repository has many megabytes of unpacked files, a git-repack is done. This packs a bunch of files together into a larger compressed file. The packing results in good compression – Mozilla conversions have apparently gone from a 3GB CVS repository to a 300MB git repository. Compare that to a 12GB fsfs subversion repository for that same conversion. Even with a packed repository, git operations remain fast, and the user doesn't need any knowledge of them.