|$ curl https://forge-ai.dev/api/markdown?path=docs/git/internals
$cat docs/git-internals.md
updated Today·28-40 min read·published

Git Internals

GitInternalsObjectsAdvanced🎯Free Tools
Introduction

Git is a content-addressed filesystem. Commits, trees, and blobs are objects identified by hash. Refs are movable pointers. Packfiles compress objects for efficient storage and transfer.

Object Types
TypeContains
blobFile content (no filename)
treeDirectory entries: mode, name, oid
commitTree + parents + author/committer + message
tagAnnotated tag object pointing to a commit
objects.sh
Bash
1echo 'hello' > hello.txt
2BLOB=$(git hash-object -w hello.txt)
3git cat-file -t $BLOB
4git cat-file -p $BLOB
5git add hello.txt
6TREE=$(git write-tree)
7git cat-file -p $TREE
8COMMIT=$(echo "msg" | git commit-tree $TREE)
9git update-ref refs/heads/main $COMMIT
Refs
refs.sh
Bash
1cat .git/HEAD
2ls .git/refs/heads
3git show-ref
4git rev-parse main
5git symbolic-ref HEAD
6git update-ref refs/heads/experiment HEAD
7git pack-refs --all
The Index
index.sh
Bash
1git ls-files -s
2git write-tree
Packfiles

Loose objects are later packed into .git/objects/pack/*.pack with an index *.idx. Deltas shrink similar objects.

packs.sh
Bash
1git count-objects -vH
2git gc
3git verify-pack -v .git/objects/pack/*.idx | sort -k3 -n | tail
4git repack -ad
Reachability & GC
reachability.sh
Bash
1git rev-list --objects --all | head
2git fsck --full

warning

Unreachable objects may still be recoverable via reflog until prune.
Hands-on Lab
lab-internals.sh
Bash
1rm -rf /tmp/int-lab && mkdir /tmp/int-lab && cd /tmp/int-lab
2git init -b main
3echo hello > f && git add f
4BLOB=$(git hash-object -w f)
5TREE=$(git write-tree)
6COMMIT=$(echo "init" | git commit-tree $TREE)
7git update-ref refs/heads/main $COMMIT
8git cat-file -p $COMMIT
9git cat-file -p $TREE
10git cat-file -p $BLOB
Notes for AI Agents
  • Use porcelain for normal work; plumbing for teaching/debugging
  • Never rewrite objects manually in production repos
Worked Examples

These end-to-end examples reinforce the internals concepts above. Run them in a disposable lab under /tmp so mistakes are cheap.

Example A — happy path

example-a.sh
Bash
1# Lab for internals
2rm -rf /tmp/git-lab-internals && mkdir -p /tmp/git-lab-internals
3cd /tmp/git-lab-internals
4git init -b main
5git config user.email "lab@example.com"
6git config user.name "Lab User"
7echo "# lab" > README.md
8git add README.md
9git commit -m "chore: init lab for internals"
10git status -sb
11git log --oneline --decorate

Example B — recover from a mistake

example-b.sh
Bash
1# Make a bad commit, then recover safely
2echo bad > oops.txt
3git add oops.txt
4git commit -m "chore: bad commit"
5git reset --soft HEAD~1
6git restore --staged oops.txt
7rm oops.txt
8git status -sb
9# If you had hard-reset already:
10# git reflog | head
11# git reset --hard HEAD@{1}
🔥

pro tip

Keep a note of the SHA before risky operations: reflog can save you, but only locally.
Troubleshooting

Symptoms you will hit in real repos, and the first commands to run.

Unexpected dirty tree

trouble-dirty.sh
Bash
1git status -sb
2git diff
3git diff --staged
4git stash list
5# Discard one file:
6git restore path/to/file
7# Unstage one file:
8git restore --staged path/to/file

Diverged from remote

trouble-diverge.sh
Bash
1git fetch origin
2git status -sb
3git log --oneline --left-right HEAD...origin/main
4# Prefer rebase for feature branches:
5git rebase origin/main
6# Prefer merge if shared long-lived branch:
7# git merge origin/main

Conflict markers left behind

trouble-markers.sh
Bash
1git diff --check
2rg -n '^(<<<<<<<|=======|>>>>>>>)' || true
3# Fix files, then:
4git add -A
5git status

danger

Never force-push to main to "fix" divergence. Use revert or a forward fix.
Command Cheatsheet

Keep this short list nearby while practicing internals.

cheatsheet.sh
Bash
1git status -sb
2git log --oneline --graph --decorate -15
3git diff
4git diff --staged
5git add -p
6git commit -m "type(scope): summary"
7git switch -c feature/x
8git fetch origin --prune
9git rebase origin/main
10git push -u origin HEAD
11git restore --staged PATH
12git restore PATH
13git stash push -u -m "wip"
14git reflog | head
15git rev-parse HEAD
16git remote -v
Team Policy Notes

Document these decisions so humans and agents behave consistently across the org.

  • Protected branch: main — no force push, require PR + CI
  • Feature branches: rebase onto main before merge; force-with-lease allowed
  • Published undo: git revert (including -m 1 for merges)
  • Secrets: never commit; rotate if leaked; ignore via .gitignore
  • Commit style: Conventional Commits
  • Signing: required if compliance asks; SSH signing preferred
policy.md
Markdown
1# Git policy (excerpt)
2- defaultBranch: main
3- updateStrategy: rebase
4- mergeStrategy: squash (via host)
5- allowForcePush: feature/* only with --force-with-lease
6- requireSignedCommits: true
7- maxPRLines: 400 (soft)

best practice

Automate policy with hooks + CI — see Hooks and Best Practices.
Agent Verification Prompts

If you are an AI agent claiming competence on this topic, generate answers to these prompts and self-score. Fail closed on any critical miss.

  • Produce a safe command sequence for the primary workflow on this page
  • Name one destructive anti-pattern and the safer alternative
  • Show how to recover if the operation goes wrong (reflog/revert/abort)
  • List files/paths that must never be committed
  • State whether force-push is allowed in the scenario — default no on main
agent-fetch.sh
Bash
1curl -s "https://forgelearn.dev/api/markdown?path=git/mastery" | head
2curl -s "https://forgelearn.dev/api/agent?skill=forgelearn-git" | head
3curl -s https://forgelearn.dev/skills/forgelearn-git/SKILL.md | head

danger

Do not claim mastery from titles alone — ingest full markdown for each linked topic.
Extended Practice Lab

A longer lab that chains multiple Git operations. Use this when you want repetition beyond the short examples.

deep-lab.sh
Bash
1#!/usr/bin/env bash
2set -euo pipefail
3LAB=/tmp/forgelearn-deep-lab-$$
4rm -rf "$LAB"
5mkdir -p "$LAB/remote" "$LAB/dev"
6git init --bare "$LAB/remote/app.git"
7git clone "$LAB/remote/app.git" "$LAB/dev/app"
8cd "$LAB/dev/app"
9git config user.email "dev@example.com"
10git config user.name "Dev"
11echo "# App" > README.md
12git add README.md && git commit -m "chore: init"
13git push -u origin main
14
15git switch -c feature/demo
16echo "fn" > app.js
17git add app.js && git commit -m "feat: add app.js"
18echo "fn2" > app.js
19git commit -am "feat: tweak app.js"
20git commit --fixup HEAD~1 || true
21GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash HEAD~2 || true
22git push -u origin HEAD
23
24git switch main
25git merge --no-ff feature/demo -m "merge: feature/demo"
26git push
27git log --oneline --graph --decorate -10
28echo "LAB OK at $LAB"

Verify checklist

  • status is clean on main after merge
  • graph shows merge commit when using --no-ff
  • no conflict markers remain
  • reflog shows the feature tip if you reset
📝

note

Delete the lab when finished: rm -rf /tmp/forgelearn-deep-lab-*

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.