Git Basics

Core Git operations for everyday use.

Status Fundamentals

# BASIC STATUS
git status                               # Full status output
git status --short                       # Compact: XY filename format
git status -sb                           # Short + branch info

# STATUS CODES (XY format)
# X = staging area, Y = working tree
# ?? = untracked
# M  = modified in staging
#  M = modified in working tree
# MM = modified in both
# A  = added to staging
# D  = deleted
# R  = renamed
# C  = copied
# U  = unmerged (conflict)

# FILTER BY PATH
git status -- docs/                      # Only docs/ changes
git status --porcelain                   # Machine-readable format

# PARSE STATUS WITH AWK
git status --porcelain | awk '{print $2}'  # Just filenames
git status --porcelain | awk '/^M/{print $2}'  # Only staged modified
git status --porcelain | awk '/^\?\?/{print $2}'  # Only untracked

# COUNT CHANGES
git status --porcelain | wc -l           # Total changed files
git status --porcelain | grep -c '^??'   # Count untracked
git status --porcelain | grep -c '^M'    # Count staged

# IGNORED FILES
git status --ignored                     # Show ignored files
git status --ignored --short             # Compact with ignored

Diff Operations

# BASIC DIFF
git diff                                 # Unstaged changes vs staging
git diff --staged                        # Staged changes vs last commit
git diff --cached                        # Same as --staged
git diff HEAD                            # All changes vs last commit

# DIFF STATISTICS
git diff --stat                          # Summary: files changed, +/-
git diff --stat --staged                 # Staged changes summary
git diff --numstat                       # Machine-readable: adds dels file
git diff --shortstat                     # Just totals

# DIFF SPECIFIC FILES
git diff -- path/to/file.txt            # Single file
git diff -- '*.adoc'                     # Glob pattern (quote it!)
git diff HEAD~3 -- docs/                 # Directory against 3 commits ago

# DIFF BETWEEN REFS
git diff main feature                    # Between branches
git diff main...feature                  # Changes since branches diverged
git diff v1.0..v2.0                      # Between tags
git diff HEAD~5 HEAD                     # Last 5 commits

# WORD-LEVEL DIFF
git diff --word-diff                     # Show word changes inline
git diff --word-diff=color               # Colored word diff
git diff --color-words                   # Compact colored words

# IGNORE WHITESPACE
git diff -w                              # Ignore all whitespace
git diff --ignore-space-change           # Ignore space amount changes
git diff --ignore-blank-lines            # Ignore blank line changes

# DIFF NAMES ONLY
git diff --name-only                     # Just filenames
git diff --name-status                   # Filenames with status (M/A/D)
git diff --name-only HEAD~5              # Changed files in last 5 commits

# DIFF FOR CODE REVIEW
git diff origin/main...HEAD              # What this branch adds
git diff origin/main --stat              # Summary vs remote main

Log Fundamentals

# BASIC LOG
git log                                  # Full log (q to quit)
git log --oneline                        # Hash + message
git log --oneline -10                    # Last 10 commits
git log -n 5                             # Last 5 commits (verbose)

# LOG WITH GRAPH
git log --oneline --graph                # ASCII branch graph
git log --oneline --graph --all          # All branches
git log --oneline --graph --decorate     # Show refs (branches, tags)

# LOG FORMATTING
git log --pretty=format:"%h %s"          # Custom: hash + subject
git log --pretty=format:"%h %an %ar %s"  # Hash, author, relative time, subject
git log --format="%H"                    # Full hashes only
git log --format="%ae"                   # Author emails only

# COMMON FORMATS
git log --pretty=fuller                  # Author + committer dates
git log --pretty=short                   # Just author + subject
git log --pretty=reference               # For changelog style

# LOG FILTERING
git log --author="Evan"                  # By author
git log --grep="fix"                     # By message content
git log --since="2 weeks ago"            # Time-based
git log --after="2024-01-01"             # After date
git log --until="yesterday"              # Before time

# LOG PATH FILTERING
git log -- path/to/file                  # Single file history
git log --follow -- file.txt             # Track renames
git log -- docs/                         # Directory history
git log -- '*.adoc'                      # By extension

# LOG FOR AUDIT
git log --stat                           # With file changes
git log -p                               # With full diff (patch)
git log -p -1                            # Last commit with diff
git log --name-only                      # Just changed filenames
git log --name-status                    # Filenames with M/A/D status

# USEFUL ALIASES
# git config --global alias.lg "log --oneline --graph --all --decorate"
# git config --global alias.last "log -1 HEAD --stat"
# git config --global alias.recent "log --oneline -15"

Add Strategies

# BASIC ADD
git add file.txt                         # Single file
git add dir/                             # Directory
git add .                                # Current directory (recursive)
git add -A                               # All changes (adds, mods, deletes)
git add --all                            # Same as -A

# ADD VS ADD -A VS ADD .
# git add .    = adds/modifies from current dir, doesn't stage deletes
# git add -A   = adds/modifies/deletes from entire repo
# PREFER: git add -A (most predictable)

# INTERACTIVE ADD
git add -p                               # Patch mode (hunk by hunk)
# y = stage this hunk
# n = skip this hunk
# s = split into smaller hunks
# e = edit hunk manually
# q = quit

# ADD WITH PATTERNS
git add '*.adoc'                         # All .adoc files (quote!)
git add docs/*.md                        # All .md in docs/
git add docs/**/*.adoc                   # Recursive .adoc in docs/

# ADD SPECIFIC CHANGES
git add -N file.txt                      # Intent to add (track, no content)
git add --ignore-removal .               # Adds and modifies only (no deletes)

# UNSTAGE (opposite of add)
git reset HEAD file.txt                  # Unstage file (keep changes)
git restore --staged file.txt            # Modern: unstage file
git reset                                # Unstage everything

# ADD IGNORED FILES (careful!)
git add -f ignored_file                  # Force add ignored file
# WHY: Temporarily track something in .gitignore

# DRY RUN
git add -n .                             # Show what would be added
git add --dry-run -A                     # Preview all changes

Commit Patterns

# BASIC COMMIT
git commit -m "message"                  # Quick commit
git commit                               # Opens editor for message

# COMMIT WITH BODY
git commit -m "subject" -m "body"        # Separate subject and body
# OR use heredoc (preferred for multi-line):
git commit -m "$(cat <<'EOF'
subject line here

Body paragraph explaining the change in detail.
Can span multiple lines.

- Bullet point 1
- Bullet point 2
EOF
)"

# ADD AND COMMIT
git commit -am "message"                 # Stage tracked + commit (-a)
# NOTE: -a only stages TRACKED files, not new ones
# PREFER: git add -A && git commit -m "message"

# AMEND COMMIT (unpushed only!)
git commit --amend                       # Edit last commit (message + files)
git commit --amend -m "new message"      # Just change message
git commit --amend --no-edit             # Add staged files, keep message

# EMPTY COMMIT (CI triggers, markers)
git commit --allow-empty -m "trigger CI"

# COMMIT CONVENTIONS (Conventional Commits)
# <type>(<scope>): <subject>
# Types: feat, fix, docs, style, refactor, test, chore
# Examples:
git commit -m "feat(auth): add OAuth2 login support"
git commit -m "fix(api): handle null response in parser"
git commit -m "docs(readme): update installation section"
git commit -m "refactor(db): extract connection pool logic"

# COMMIT MESSAGE BEST PRACTICES
# - Subject: imperative mood ("Add feature" not "Added feature")
# - Subject: 50 chars max, no period
# - Body: wrap at 72 chars
# - Body: explain WHAT and WHY, not HOW

# SIGN COMMITS (GPG)
git commit -S -m "signed commit"         # GPG sign
git commit -s -m "signed-off commit"     # Add Signed-off-by line

# FIX COMMIT (squash later)
git commit --fixup=<commit>              # Marks for fixup
git commit --squash=<commit>             # Marks for squash
# Then: git rebase -i --autosquash

Infrastructure Repository Workflows

# DOMUS-* REPO WORKFLOW
# Standard pattern for documentation repos

# 1. Start work (check status across repos)
for repo in domus-docs domus-infra-ops domus-captures; do
  echo "=== $repo ==="
  git -C ~/atelier/_bibliotheca/$repo status --short
done

# 2. Make changes, stage, verify
git add -A
git diff --staged --stat                 # Review what's staged

# 3. Commit with descriptive message
git commit -m "$(cat <<'EOF'
docs(runbook): Add Vault SSH CA troubleshooting section

- Add PTY allocation failure fix
- Document clock skew symptoms
- Add principal mismatch debugging
EOF
)"

# 4. Push (with SSH agent)
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push origin main

# MULTI-REPO PUSH (all domus-* repos)
for repo in domus-docs domus-infra-ops domus-captures domus-ise-linux; do
  echo "=== Pushing $repo ==="
  SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket \
    git -C ~/atelier/_bibliotheca/$repo push origin main
done

# ANTORA BUILD TRIGGER
# Spoke repo changes need aggregator push:
git -C ~/atelier/_bibliotheca/domus-docs commit --allow-empty \
  -m "chore: Trigger rebuild for $spoke_repo updates"
git -C ~/atelier/_bibliotheca/domus-docs push origin main

# CHECK ALL REPOS STATUS
for repo in ~/atelier/_bibliotheca/domus-*/; do
  name=$(basename "$repo")
  ahead=$(git -C "$repo" rev-list --count origin/main..HEAD 2>/dev/null)
  behind=$(git -C "$repo" rev-list --count HEAD..origin/main 2>/dev/null)
  dirty=$(git -C "$repo" status --porcelain | wc -l)
  echo "$name: +$ahead -$behind ~$dirty"
done

# BATCH OPERATION PATTERN
# Safe way to run commands across repos
for repo in domus-infra-ops domus-captures domus-ise-linux; do
  echo "=== $repo ==="
  git -C ~/atelier/_bibliotheca/$repo fetch --all
  git -C ~/atelier/_bibliotheca/$repo status --short
done

Advanced Status Techniques

# MACHINE-READABLE STATUS
git status --porcelain                   # Stable format for scripting
git status --porcelain=v2                # Even more detailed format

# PARSE FOR AUTOMATION
# Find all untracked files:
git status --porcelain | awk '/^\?\?/{print $2}'

# Find all modified (not staged):
git status --porcelain | awk '/^ M/{print $2}'

# Find all staged files:
git status --porcelain | awk '/^[MARCD]/{print $2}'

# CHECK IF DIRTY (for scripts)
if [ -n "$(git status --porcelain)" ]; then
  echo "Uncommitted changes exist"
fi

# CHECK IF AHEAD/BEHIND
git status -sb | head -1
# Output: ## main...origin/main [ahead 3, behind 1]

# PARSE AHEAD/BEHIND
git rev-list --left-right --count origin/main...HEAD
# Output: behind ahead

# BRANCH TRACKING STATUS
git branch -vv                           # Show tracking branches
git for-each-ref --format='%(refname:short) %(upstream:short) %(upstream:track)' refs/heads

# STASH STATUS
git stash list | wc -l                   # Count stashes

# WORKTREE STATUS
git worktree list                        # All worktrees

# SUBMODULE STATUS
git submodule status                     # Submodule state

Git Basics Gotchas

# WRONG: Using add . expecting all changes
git add .
# Only adds from current directory! Doesn't stage deletes!

# CORRECT: Use add -A for all changes
git add -A
# Stages adds, modifications, AND deletions from entire repo

# WRONG: Committing without checking staged content
git commit -m "quick fix"
# May include unintended changes!

# CORRECT: Review before commit
git diff --staged --stat
git commit -m "quick fix"

# WRONG: Amending pushed commits
git push origin main
git commit --amend
git push origin main
# ERROR: rejected (non-fast-forward)

# CORRECT: Never amend pushed commits (unless force-push OK)
git commit --amend
git push --force-with-lease origin main  # Only if you know what you're doing!

# WRONG: Committing secrets
git add .env
git commit -m "add config"
# SECRET NOW IN HISTORY FOREVER!

# CORRECT: Use .gitignore + pre-commit hooks
echo ".env" >> .gitignore
# Better: use git-filter-repo to remove if already committed

# WRONG: Assuming git diff shows all changes
git diff
# Only shows UNSTAGED changes!

# CORRECT: Know your diff targets
git diff                                 # Unstaged vs staging
git diff --staged                        # Staged vs last commit
git diff HEAD                            # All changes vs last commit

# WRONG: git log without limits
git log
# Scrolls forever in large repos!

# CORRECT: Always limit or use pager
git log --oneline -20
git log --since="1 week ago"

# WRONG: Expecting -m to handle newlines
git commit -m "line1\nline2"
# Creates literal \n in message!

# CORRECT: Use heredoc or multiple -m flags
git commit -m "line1" -m "line2"
# Or: git commit -m "$(cat <<'EOF' ... EOF)"

Quick Reference

# ESSENTIAL BASICS
git status -sb                           # Short status + branch
git diff --stat                          # Change summary
git log --oneline -10                    # Recent commits
git add -A                               # Stage everything
git commit -m "message"                  # Commit

# STATUS CODES (git status --porcelain)
# ?? = untracked    M  = staged modified
#  M = unstaged mod MM = both staged+unstaged
# A  = staged added  D = deleted
# R  = renamed       U = unmerged (conflict)

# DIFF TARGETS
git diff                                 # Working vs staging
git diff --staged                        # Staging vs commit
git diff HEAD                            # Working vs commit
git diff main...HEAD                     # Branch changes

# LOG FORMATS
git log --oneline --graph --all          # ASCII graph
git log --pretty=format:"%h %an %s"      # Custom format
git log -p -1                            # Last commit with diff
git log --name-only                      # Changed files list

# ADD PATTERNS
git add -A                               # All changes (preferred)
git add -p                               # Interactive hunks
git add '*.adoc'                         # By extension

# COMMIT PATTERNS
git commit -m "type(scope): message"     # Conventional
git commit --amend --no-edit             # Add to last (unpushed!)
git commit --allow-empty -m "trigger"    # CI trigger

See Also

  • Branches

  • Stash — save work before switching context

  • Config — aliases, .gitignore, settings