Git from First PrinciplesPost 5 of 16 · 16 of 16 written

5. Daily commands, mapped onto the model

Git · 5 of 163 min readOct 2026

About fifteen commands cover nearly all daily work, and each one is just a read or a write on the objects, refs and areas from Parts 2–4.

Setup, once per machine

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"   # or nano, vim
git config --list --show-origin                  # every setting and the file it came from

Your name and email are written into every commit object, permanently. Use the email linked to your GitHub account, or its private noreply address, so your work is attributed to you.

Config has three levels, and the narrower one wins: system (the machine), global (~/.gitconfig, you), and local (.git/config, one repository). A work email in one repository is a local setting.

The commands, seen through the model

Command Reads Writes Remember
git init - A new .git database Safe to run; it never touches your files
git status Working tree, index, HEAD Nothing Run it before and after everything
git add <path> Working tree Blobs and the index -p stages hunk by hunk
git commit Index, HEAD Trees, a commit, moves the branch -v shows the diff while you write
git diff Two areas or commits Nothing See the three comparisons in Part 4
git log Commits Nothing Flags below
git show <rev> One object Nothing A commit and its diff against its parent
git restore <path> Index Working tree Discards unstaged edits
git restore --staged <path> HEAD Index Unstages; your edits stay on disk
git switch <branch> That branch’s commit HEAD, index, working tree Refuses if it would destroy edits
git switch -c <new> HEAD A new ref, HEAD Create and move in one step
git branch Refs Refs List, create, -d delete merged, -D force
git rm <path> - Index and working tree --cached stops tracking but keeps the file
git mv <a> <b> - Index and working tree Same as delete plus add; renames are detected later
git tag - A ref, and a tag object if annotated -a for annotated release tags

About git checkout. It used to do everything. In 2019 Git split it into switch (move between branches) and restore (restore files). All three remain supported, so tutorials still use checkout: git checkout <branch> is switch, git checkout -- <file> is restore, and git checkout -b <new> is switch -c.

Reading history with log

git log --oneline --graph --all       # the shape of the graph (your git lg alias)
git log --stat                        # which files each commit touched
git log -p -- src/train.py            # every change to one file, with diffs
git log --follow -- src/model.py      # the same, following renames
git log --author="Ulvi" --since="2 weeks ago"
git log -S "learning_rate"            # commits that added or removed this text
git log main..feature                 # what feature has that main lacks

.gitignore

.gitignore lists untracked files Git should never offer to add. It has no effect on files already tracked. To stop tracking one, run git rm --cached <path> and commit.

  • *.ckpt matches anywhere. /data/ matches only at the repository root. A trailing / matches folders only.
  • !keep.txt re-includes something an earlier rule excluded. **/ matches any depth.
  • Shared rules go in the committed .gitignore. Personal rules for one repository go in .git/info/exclude. Rules for all your repositories (editor and OS junk) go in a global file set by core.excludesFile.
  • git check-ignore -v <path> tells you which rule, in which file, matched.

A starting point for Python and ML projects:

# Python
__pycache__/
*.py[cod]
.venv/
*.egg-info/

# Notebooks
.ipynb_checkpoints/

# Secrets: never commit these
.env
*.pem

# Data and model artifacts: version them with DVC or LFS instead (Part 10)
data/
models/
checkpoints/
*.ckpt
*.pt
*.safetensors

# Experiment tracker output
wandb/
mlruns/
outputs/

# OS and editor
.DS_Store
.idea/

What makes a good commit

One commit should hold one logical change that you could describe in one sentence. That makes history readable, reverts surgical and bisect precise (Part 12).

Write the subject line in the imperative, about 50 characters: “Add stratified split to data loader”. After a blank line, the body explains why, because the diff already shows what. Part 9 covers conventions.

Check yourself

  • Which single command shows exactly what your next commit will contain?
  • You added data/ to .gitignore, yet Git still reports changes to data/raw.csv. Why, and what is the fix?
  • In model terms, what is the difference between git restore f and git restore --staged f?