Git

Table of Contents
│ └── Stashing
│ ├── Merging vs. Rebasing

🔗1. Core Architecture & Configuration

Git is a content-addressed, distributed version control system modeled as an immutable directed acyclic graph (DAG) of snapshots.

🔗The Three Trees & State Transitions

Every major Git operation transforms one or more of the three managed file collections:

  • Working Tree: The local filesystem checkout where files are edited.
  • Index (Staging Area): A binary cache (.git/index) representing the exact content of the next commit.
  • Repository (HEAD): The immutable, committed history in the object database.
[Working Tree]  <---(git restore <file>)---  [Index]  <---(git restore --staged)---  [Repository (HEAD)]
      |                                         ^                                           ^
      +-------------(git add <file>)------------+                                           |
      |                                                                                     |
      +------------------------(git commit -a) / (git commit)-------------------------------+

🔗Essential Global Configuration (~/.gitconfig)

Apply these settings to enforce cryptographic integrity, accurate diffs, and automated conflict resolution:

[user]
    name = Your Name
    email = you@example.com
    signingkey = ~/.ssh/id_ed25519.pub

[core]
    editor = vim
    autocrlf = input      # Convert CRLF to LF on input (Linux/macOS)
    pager = less -FRX
    fsmonitor = true      # Enable filesystem event watcher integration
    untrackedCache = true

[init]
    defaultBranch = main

[pull]
    rebase = false        # Default to merge on pull; set to true for linear workflows

[push]
    default = simple
    autoSetupRemote = true
    followTags = true

[fetch]
    prune = true          # Delete tracking references for removed remote branches
    prunetags = true
    writeCommitGraph = true

[diff]
    algorithm = histogram # Accurate diff algorithm for code block movements

[merge]
    conflictstyle = zdiff3 # Show common ancestor (|||||||) in merge conflicts
    tool = vimdiff

[rerere]
    enabled = true        # Reuse Recorded Resolution for recurring conflicts
    autoupdate = true

[gpg]
    format = ssh          # Use SSH keys for signing

[commit]
    gpgsign = true

[tag]
    gpgsign = true

🔗High-Leverage Global Aliases

git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br "branch -vv"
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "restore --staged"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.branches "for-each-ref --sort=-committerdate refs/heads/ --format='%(refname:short) %(committerdate:relative) %(authorname)'"

🔗2. Object Model & Internals

Every piece of data in Git is stored in .git/objects/ as one of four immutable, content-addressed object types.

Object TypeDescriptionInternal Structure / Metadata Stored
blobRaw file bytes.Pure content. No filenames, modes, or timestamps.
treeDirectory listing.Array of entries containing file mode (100644, 100755, 040000), name, and object SHA-1/SHA-256 hash.
commitSnapshot reference.Root tree hash, parent commit hash(es), author/committer timestamps, commit message.
tagAnnotated reference.Hash of target object, tagger name/timestamp, tag message, GPG/SSH signature.
[Commit Object: a1b2c3] ---> [Root Tree: d4e5f6] ---> [Blob: g7h8i9] (README.md)
  |                                           |
  | (Parent)                                  +---> [Subtree: j0k1l2] (src/) ---> [Blob: m3n4o5] (main.py)
  v
[Commit Object: p6q7r8]

🔗Low-Level Object Inspection (cat-file & hash-object)

# Compute object hash from local file without writing to database
git hash-object <file>

# Compute hash and store the object in .git/objects/
git hash-object -w <file>

# Print object type (blob, tree, commit, tag)
git cat-file -t <hash>

# Print raw object content / metadata
git cat-file -p <hash>

# Print byte size of stored object
git cat-file -s <hash>

# List all files and tree entries in a specific commit
git ls-tree -r HEAD

# Verify database integrity and connectivity
git fsck --full

🔗3. Daily Operations & Navigation

🔗Staging, Committing & Inspecting State

# Interactively stage diff hunks (y = stage, n = skip, s = split, e = edit)
git add -p

# Commit staged changes with GPG/SSH signature
git commit -S -m "feat(module): descriptive subject"

# Stage all tracked modified files and commit simultaneously
git commit -a -m "message"

# Replace tip commit with new commit object (use --no-edit to keep message)
git commit --amend

# View working tree and staging area status (short two-column format)
git status -s

# Show diff between working tree and staging area (unstaged changes)
git diff

# Show diff between staging area and HEAD (staged changes)
git diff --staged

# Show line-by-line attribution and commit hash for a specific file range
git blame -L 20,40 src/main.py

🔗Branch & Reference Manipulation

A branch is a 41-byte text file in .git/refs/heads/ containing a 40-character commit hash.

# List local branches with upstream tracking and ahead/behind metrics
git branch -vv

# Create and switch to a new branch in a single atomic operation
git switch -c <branch-name>

# Switch to the previously checked-out branch (reads @{-1})
git switch -

# Explicitly detach HEAD to inspect a tag or commit directly
git switch --detach <hash-or-tag>

# Delete a branch (fails if unmerged); use -D to force deletion
git branch -d <branch-name>

# Rename current branch and update tracking upstream
git branch -m <old-name> <new-name>

🔗Stashing

Stashes are stored as 2-3 commit objects under refs/stash recording the index, working tree, and untracked files.

# Stash working tree and index changes with descriptive identifier
git stash push -m "WIP: login feature"

# Stash changes including untracked files
git stash -u

# Apply most recent stash and remove entry from stash list
git stash pop

# Apply a specific stash entry without deleting it from stash reflog
git stash apply stash@{2}

🔗4. History Manipulation & Integration

🔗Merging vs. Rebasing

  • Merge: Preserves divergent history by creating a new commit with multiple parents.
  • Rebase: Replays commits onto a new base commit, generating new commit objects with linear parentage. Never rebase commits pushed to shared remote branches.
# Perform a merge without fast-forwarding (creates merge commit for audit trail)
git merge --no-ff <branch>

# Rebase current branch onto target branch
git rebase main

# Rebase a range of commits, transplanting feature away from old-base onto new-base
git rebase --onto <new-base> <old-base> <feature-branch>

# Interactively rebase last N commits (pick, reword, edit, squash, fixup, drop, exec)
git rebase -i HEAD~4

# Apply specific commit(s) from another branch as new commit objects
git cherry-pick -x <hash>

🔗The Three Reset Modes (git reset)

git reset moves the current branch pointer (HEAD) backward in the graph.

               [Commit A] <--- [Commit B] <--- [Commit C] (HEAD -> main)
                                                   ^
                                         (git reset HEAD~1)
                                                   |
               +-----------------------------------+
               |
               v
 [Mode: --soft]  ---> Branch pointer moves to B. Index & Working Tree stay at C (changes staged).
 [Mode: --mixed] ---> Branch pointer & Index move to B. Working Tree stays at C (changes unstaged).
 [Mode: --hard]  ---> Branch pointer, Index & Working Tree move to B. (Uncommitted changes lost!)
# Undo last commit; leave changes staged in Index
git reset --soft HEAD~1

# Undo last commit; unstage changes into Working Tree (Default mode)
git reset --mixed HEAD~1

# Reset branch, Index, and Working Tree to target commit (OVERWRITES WORKING TREE)
git reset --hard HEAD~1

# Safely create an inverse commit that undoes the changes of target commit
git revert <hash>

🔗Advanced Conflict Resolution

When a three-way merge conflicts, Git populates the Index with stage numbers: Stage 1 (common ancestor), Stage 2 (ours/HEAD), and Stage 3 (theirs/incoming).

# List all unmerged (conflicted) files in the index with stage numbers
git ls-files -u

# Extract specific stage versions of a conflicted file for inspection
git show :1:file.py > ancestor.py
git show :2:file.py > ours.py
git show :3:file.py > theirs.py

# Accept only our branch version or incoming branch version during resolution
git checkout --ours file.py
git checkout --theirs file.py

🔗5. Distributed Workflows & Remotes

A remote is a named URL reference stored in .git/config. Communication relies on Refspecs formatted as +<src>:<dst>, which map remote references to local tracking branches in refs/remotes/<remote>/.

# Add a remote repository URL
git remote add origin git@github.com:user/repo.git

# Download objects and refs from remote; prune deleted tracking branches
git fetch --prune origin

# Push current branch and set upstream tracking reference in .git/config
git push -u origin <branch-name>

# Safely force-push: rejects push if remote branch was updated by another user
git push --force-with-lease origin <branch-name>

# Delete a branch on the remote server
git push origin --delete <branch-name>

# Push branch along with all reachable annotated tags
git push --follow-tags

🔗6. Emergency Recovery & Disaster Management

Because Git commits are immutable snapshots, "destructive" operations (reset, rebase, branch -d) merely move references away from commits. The unreferenced commit objects remain in .git/objects/ until garbage collection (git gc) prunes them (default grace period: 30 days for unreachable reflog entries; 2 weeks for unreachable objects).

[Incident Occurs] ---> 1. STOP! Do not run clean/gc.
                  ---> 2. Locate lost hash via `git reflog` or `git fsck --lost-found`.
                  ---> 3. Anchor object: `git branch recovery <hash>` or `git reset --hard <hash>`.

🔗Disaster Recovery Runbook

# 1. Inspect Reference Movements (The Reflog)
# Shows history of all HEAD movements, checkouts, resets, and rebases
git reflog --all

# 2. Recover from Accidental Hard Reset
# Move branch pointer back to the reflog position prior to the reset
git reset --hard HEAD@{1}

# 3. Undo a Problematic Merge or Rebase Instantly
# ORIG_HEAD records the pre-rebase / pre-merge tip of the branch
git reset --hard ORIG_HEAD

# 4. Recover a Deleted Branch
# Find the branch's last commit hash in reflog, then re-create reference
git branch <recovered-branch> <hash-from-reflog>

# 5. Recover Lost Commits from Detached HEAD
# Locate commit hashes generated in detached state, then anchor to a new branch
git branch saved-work <detached-hash>

# 6. Locate Unreachable Objects (When Reflog is Cleared/Expired)
# Scans object database for orphaned commits not reachable from any ref
git fsck --unreachable --no-reflogs

# Write orphaned blobs and commits into .git/lost-found/commit/ and /other/
git fsck --lost-found

🔗7. Advanced Administration & Tools

🔗Worktrees (git worktree)

Maintain multiple simultaneous working tree checkouts attached to a single shared .git object database.

# Create a new working tree directory checked out to a specific branch
git worktree add ../project-hotfix hotfix/1.1.1

# List active worktrees associated with the repository
git worktree list

# Remove worktree directory and prune tracking metadata
git worktree remove ../project-hotfix

🔗Automated Debugging (git bisect)

Perform binary searches through DAG history in $O(\log n)$ steps to isolate regression-introducing commits.

# Start bisect session and mark known bad/good boundaries
git bisect start
git bisect bad HEAD
git bisect good v1.0

# Automate binary search using an executable test script (exit 0 = good, non-zero = bad)
git bisect run ./test-regression.sh

# Terminate bisect session and restore original HEAD checkout
git bisect reset

🔗Large Scale History Rewriting (git filter-repo)

Requires Python tool: pip install git-filter-repo. Replaces legacy filter-branch.

# Purge a sensitive file or secret from every commit in repository history
git filter-repo --path secret.env --invert-paths

# Extract a specific subdirectory into an independent, isolated repository
git filter-repo --subdirectory-filter services/auth

🔗Monorepo & Performance Optimization

# Perform a partial clone: download trees/commits, defer blob fetches until access
git clone --filter=blob:none [https://github.com/org/repo.git](https://github.com/org/repo.git)

# Enable sparse checkout in high-speed cone mode (limits working tree files)
git sparse-checkout init --cone
git sparse-checkout set services/api

# Generate commit-graph and multi-pack index (MIDX) to accelerate DAG traversals
git commit-graph write --reachable
git multi-pack-index write

# Repack loose objects into a single optimized packfile with reachability bitmaps
git repack -a -d --write-bitmap-index

# Schedule automated background repository optimization tasks (Git 2.29+)
git maintenance start