Loading...
Loading...
Commands, structure, and workflows - everything you need to use Git effectively
When you run git init, Git creates a hidden .git/ folder. This single directory holds your entire project history. Here is what is inside:
.git/ ├── HEAD Points to current branch (e.g., refs/heads/main) ├── config Repository-level settings (remotes, user info) ├── description Used by GitWeb (rarely needed) ├── index The staging area (binary file) │ ├── objects/ All content stored as SHA-1 hashed objects │ ├── pack/ Packed objects (compressed for efficiency) │ └── info/ Additional object info │ ├── refs/ Pointers to commits │ ├── heads/ Local branches (main, feature/auth, ...) │ ├── tags/ Tag references (v1.0.0, v2.0.0, ...) │ └── remotes/ Remote-tracking branches (origin/main, ...) │ ├── hooks/ Scripts that run on events (pre-commit, post-merge, ...) ├── info/ Global excludes (like .gitignore but not committed) └── logs/ History of ref changes (powers git reflog)
Git stores everything as objects identified by SHA-1 hashes. There are four types of objects, and they link together to form your project history:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Commit │────►│ Tree │────►│ Blob │
│ a1b2c3 │ │ d4e5f6 │ │ g7h8i9 │
│ │ │ │ │ │
│ author │ │ app.py ──────► │ (file │
│ message │ │ src/ ────┐ │ contents)│
│ parent ──┼─┐ │ │ └──────────┘
└──────────┘ │ └──────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Commit │ │ Tree │────►│ Blob │
│ (parent) │ │ (src/) │ │ utils.py │
└──────────┘ └──────────┘ └──────────┘
Object Types:
─────────────────────────────────────────────────
Blob File contents (no filename, just data)
Tree Directory listing (filenames → blob/tree hashes)
Commit Snapshot pointer + metadata (author, message, parent)
Tag Named pointer to a commit (annotated tags only)Every object is immutable. When you change a file, Git creates a new blob with a new hash. If two files have the same content, they share a single blob. Git deduplicates automatically.
Git manages your files across three “trees.” Understanding how data moves between them is the key to understanding every Git command:
Working Directory Staging Area (Index) Repository (HEAD)
───────────────── ──────────────────── ──────────────────
Your actual files Snapshot of next commit Last committed snapshot
on disk (binary .git/index) (.git/objects/)
│ │ │
│──── git add ───────────►│ │
│ │──── git commit ────────►│
│ │ │
│◄─── git restore ────────│ │
│ │◄─── git reset ──────────│
│ │ │
│◄────────────── git checkout / git restore ────────│
│ │ │
What each command does to the three trees:
────────────────────────────────────────────────────────────
git add <file> Working ──► Index
git commit Index ──► HEAD
git restore <file> Index ──► Working (discard changes)
git restore --staged HEAD ──► Index (unstage)
git reset --soft Move HEAD only
git reset --mixed HEAD ──► Index (unstage)
git reset --hard HEAD ──► Index ──► Working (discard all)HEAD is a pointer that tells Git which commit you are currently on. It usually points to a branch, which in turn points to a commit:
Normal state (HEAD → branch → commit):
HEAD
│
▼
main ──► commit C
│
▼
commit B
│
▼
commit A
Detached HEAD (HEAD → commit directly):
HEAD ──────► commit C main ──► commit D
│ │
▼ ▼
commit B commit C
│
▼
commit A
⚠ Any new commits you make here will be "orphaned"
when you switch branches. Use git switch -c <name>
to save them to a new branch.
Ref types:
─────────────────────────────────────────────
refs/heads/main Local branch "main"
refs/heads/feature/auth Local branch "feature/auth"
refs/remotes/origin/main Remote-tracking branch
refs/tags/v1.0.0 Tag reference
HEAD Current position (usually → branch)Every file in your working directory is in one of four states. Git commands move files between these states:
┌──────────────────────────────────────┐
│ File State Lifecycle │
└──────────────────────────────────────┘
┌───────────┐ git add ┌────────┐ git commit ┌───────────┐
│ Untracked │───────────►│ Staged │─────────────►│ Committed │
└───────────┘ └────────┘ └───────────┘
▲ │
│ edit file
│ │
│ ▼
git add ┌──────────┐
│ │ Modified │
└────────────────┘──────────┘
State │ Meaning │ Shown by git status
──────────────┼───────────────────────────────────┼────────────────────
Untracked │ New file, Git doesn't know it │ red, "Untracked files"
Modified │ Changed since last commit │ red, "Changes not staged"
Staged │ Marked for next commit │ green, "Changes to be committed"
Committed │ Safely stored in repository │ not shown (clean)Git commits form a Directed Acyclic Graph (DAG). Each commit points to its parent(s), creating a history that branches and merges but never loops:
Linear history:
A ── B ── C ── D (main)
Branching:
A ── B ── C ── D (main)
\
E ── F (feature)
After merge:
A ── B ── C ── D ── G (main) G has TWO parents: D and F
\ /
E ── F (feature)
After rebase (linear again):
A ── B ── C ── D ── E' ── F' (main)
E', F' = replayed commits (new hashes, same changes)
Reading the graph:
─────────────────────────────────────────────
← (left) Older commits (parents)
→ (right) Newer commits (children)
\ or / Branch point or merge point
* A commit node
View it yourself:
$ git log --oneline --graph --all