There's a hidden folder .git
in the project root directory (it gets created when you run git init
or otherwise initialize a repository), in which git stores all the "magical bits". It's not extremely magical - there's a HEAD
text file which says where the "head" is at (e.g. currently checked out branch or commit), there's refs
directory with more directories that have files corresponding to your local and remote branch names - each of these files being just a text file with commit SHA (like a dictionary, when you say "check out master branch!" git will go and look for the corresponding file, read what commit it is - and check out that commit).
Commits refer to "objects", conveniently in objects/
directory. That dir actually contains a bunch more directories with two-letter names - which are first two letters SHA hash - which together with the file name inside directory makes the full hash (of a commit, tree or blob). Inside that two-letter dir, there are actual "objects" (git magic!). Objects can be of of type "blob" or "tree", former corresponding to files and latter (loosely) to directories. Read about git objects in the docs - it's an easy read that also gives you some tools to look at individual objects.
So, if in .git/refs/heads/master
is a text file with contents a2789da8f918ef26c90e51d05de5723e5ad543a4
- that means master is at that commit. The "state" of your project for that commit is stored in .git/objects/a2/789da8f918ef26c90e51d05de5723e5ad543a4
- which is tree object for project directory, listing SHAs for all the files & directories in the project dir at that moment.
So, you can't really browse around and find actual files from different branches - git doesn't think about things in that way, it thinks about things as lists of files & dirs. When you change a file and commit it, it creates a new "object" for contents of that file, and new tree objects for parent directories (with updated SHA for your updated file) and writes a commit object (tree object listing all the files & folders in project dir). Or at least that's my understanding, more or less.
Hope that helps demystify it a bit!
2017-12-21 edit: updated my old answer per comment from @Herman. For what it's worth, this answer here might be a bit "too much information without enough context".
The shorter answer - git stores all the data in .git
directory in project root, it stores references to state of your project folder rather than separate copies of files.
For sake of posterity, if anyone stumbles upon this answer in the future - I highly recommend this course:
https://app.pluralsight.com/library/courses/how-git-works/table-of-contents
(you can find offers for free trial for pluralsight and get a lot of value out of your trial).