Skip to content

paperlib/git-from-scratch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 

Repository files navigation

Understanding Git

Watch the video
Ever wanted to truly understand git? Watch this video ☝️

Consider this snippet from the always accurate xkcd on git:

How do you use git? No idea. Just memorize these shell commands and type them to sync up. If you get errors, save your work elsewhere, delete the project, and download a fresh copy.

if this has ever been you.. read on

Intro

Go in fear of Abstractions - Erza Pound

If intuitiveness, responsiveness, consistency, and efficiency are among the most common properties of good user interfaces, completeness rarely ever seems to make it to the top. And maybe understandbly so, since completeness and intuitiveness are in a direct fist fight with each other.

Limiting ourselves to such "surface level" intituitive (user interface) commands - like git add, git commmit and the likes - means then we will never truly understand (let alone master) git. The minute our surface level abstractions break appart, we are lost, just as in the above xkcd joke.


Ok so how hard would it be? To create a repo from scratch? Well, check this out:

mkdir git-from-scratch; cd git-from-scratch
mkdir -p .git/objects .git/refs .git/refs/heads
echo "ref: refs/heads/main" > .git/HEAD

That's it.

Sure we still need explaining what those references and objects are. But we can keep this short snippet as a cheat code to understanding git. The gist of it is that under objects we have trees which act as directories, containing list of blobs (litteraly zipped versions of your files) and commits, which are pointers to trees (with some additional metadata.)

Note

git has 3 of its main object types live under the objects directory

  • Trees: ie. directories, containing list of blobs

    additionaly trees may contain trees recursively like diretories

  • Blobs: litteraly compressed (zipped) versions of our files at a given point in time
  • Commits: eg. pointers to trees with some additional metadata (eg. author, commit message, etc.)

Main plumbing commands:
git hash-object, git update-index, and git write-tree and git commit-tree 📌

mkdir git-from-scratch
cd git-from-scratch
mkdir .git/objects .git/refs .git/refs/heads
echo ref: refs/heads/master > .git/HEAD
echo That Brief YouTube channel is indeed awesome | git hash-object --stdin -w # 57dbcd*
git update-index --add --cacheinfo 100644 57dbcdd7a5e501fd6518c9d170af2c94d481508f awesome.brief.txt
git cat-file -p 57dbcdd7a5e501fd6518c9d170af2c94d481508f > awesome.brief.txt
git write-tree
git commit-tree 32c4384a112bf311f54cfae69f67815b90141713 -m "awesome brief initial commit" # b0b55c*
echo cb6530cefb9b25fe50feb9792b78cf94cb23df6a > .git/refs/heads/master

Walkthrough

$ mkdir git-from-scratch
$ cd git-from-scratch
$ mkdir .git/objects .git/refs .git/refs/heads
$ echo ref: refs/heads/master > .git/HEAD
$ echo That Brief YouTube channel is indeed awesome | git hash-object --stdin -w
57dbcdd7a5e501fd6518c9d170af2c94d481508f
$ git cat-file -t 57dbcdd7a5e501fd6518c9d170af2c94d481508f
blob
$ git cat-file -p 57dbcdd7a5e501fd6518c9d170af2c94d481508f
That Brief YouTube channel is indeed awesome
# -- equivalent to "git add awesome.brief.txt" - TODO: partially true or fully? 📌
$ git update-index --add --cacheinfo 100644 57dbcdd7a5e501fd6518c9d170af2c94d481508f awesome.brief.txt
$ tree -a
.
└── .git
    ├── HEAD
    ├── index
    ├── objects
    │   └── 57
    │       └── dbcdd7a5e501fd6518c9d170af2c94d481508f
    └── refs
        └── heads

5 directories, 3 files
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   awesome.brief.txt

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    awesome.brief.txt
$ git cat-file -p 57dbcdd7a5e501fd6518c9d170af2c94d481508f > awesome.brief.txt
# -- write-tree does not write out the working directory content
# -- it writes out whatever is in the index.
$ git write-tree 📌
32c4384a112bf311f54cfae69f67815b90141713
$ tree -a
.
├── .git
│   ├── HEAD
│   ├── index
│   ├── objects
│   │   ├── 32
│   │   │   └── c4384a112bf311f54cfae69f67815b90141713
│   │   └── 57
│   │       └── dbcdd7a5e501fd6518c9d170af2c94d481508f
│   └── refs
│       └── heads
└── awesome.brief.txt

6 directories, 5 files
$ git cat-file -t 32c4384a112bf311f54cfae69f67815b90141713
tree
$ git cat-file -p 32c4384a112bf311f54cfae69f67815b90141713
100644 blob 57dbcdd7a5e501fd6518c9d170af2c94d481508f    awesome.brief.txt
# -- equivalent of "git commit awesome.brief.txt" 📌
$ git commit-tree 32c4384a112bf311f54cfae69f67815b90141713 -m "awesome brief initial commit" 
b0b55c79d5342ecd3a6521d7db771dac7fc63c4a
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   awesome.brief.txt

$ tree -a
.
├── .git
│   ├── HEAD
│   ├── index
│   ├── objects
│   │   ├── 32
│   │   │   └── c4384a112bf311f54cfae69f67815b90141713
│   │   ├── 57
│   │   │   └── dbcdd7a5e501fd6518c9d170af2c94d481508f
│   │   └── b0
│   │       └── b55c79d5342ecd3a6521d7db771dac7fc63c4a
│   └── refs
│       └── heads
└── awesome.brief.txt

7 directories, 6 files
$ git cat-file -t b0b55c79d5342ecd3a6521d7db771dac7fc63c4a
commit
$ git cat-file -p b0b55c79d5342ecd3a6521d7db771dac7fc63c4a
tree 32c4384a112bf311f54cfae69f67815b90141713
author stephane <anemail@acompany.com> 1672605219 +0000
committer stephane <anemail@acompany.com> 1672605219 +0000

awesome brief initial commit
$ echo b0b55c79d5342ecd3a6521d7db771dac7fc63c4a > .git/refs/heads/master
$ git status
On branch master
nothing to commit, working tree clean

References

Other excelent resources include:

Notes

$ git config --global alias.lol 'log --oneline --graph'

$ git init --template=/dev/null ./git-empty-git

$ git cat-file -t ff58d06f62f348cceb893dea4db8fdbe5173eeb8
tree
$ git cat-file -p ff58d06f62f348cceb893dea4db8fdbe5173eeb8
100644 blob 299d7ef205fff43cca0a761db9cd16deb29def7a    a.first-file.txt
$ git ls-files --stage
100644 299d7ef205fff43cca0a761db9cd16deb29def7a 0       a.first-file.txt

git detached-head-example

About

Git from Scratch: how to actually understand git!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages