Skip to content

Git Essentials

Version control for code, notebooks, and configs. Git tracks every change so you can experiment freely, collaborate safely, and never lose work again.

Table of Contents

Installation / Setup

git --version                  # install from git-scm.com / apt / brew

One-time identity (needed for commits):

git config --global user.name  "Ada Lovelace"
git config --global user.email "ada@example.com"
git config --global init.defaultBranch main     # modern default
git config --global core.editor "code --wait"   # VS Code as editor
git config --global pull.rebase false           # or true — pick one workflow
git config --list                               # view config

Credentials: use an SSH key or a personal access token (never your password) — see the GitHub sheet.

Core Syntax

Repositories & the basics

git init                                # start a repo in this folder
git clone <url>                         # copy an existing repo
git status                              # what changed / what's staged
git add <file>                          # stage a file
git add .                               # stage everything (careful!)
git commit -m "message"                 # snapshot staged changes
git log --oneline                       # history, one line per commit

The three areas: working tree → (add) → staging area → (commit) → repository.

The daily loop

git status                # 1. what's going on
git diff                  # 2. unstaged changes (working tree)
git diff --staged         #    staged changes
git add model.py          # 3. stage what you want
git commit -m "Add MLP baseline"    # 4. snapshot
git push                  # 5. share with the remote
git pull                  # 6. fetch + merge remote changes

Branching

git branch                    # list branches (* = current)
git branch feature/eda        # create
git checkout feature/eda      # switch (older form)
git switch feature/eda        # switch (modern form)
git switch -c new-branch      # create + switch in one step
git branch -d feature/eda     # delete (merged); -D to force
git branch -a                 # include remote branches

Rule of thumb: never commit experiments straight to main — work on a branch, merge when stable.

Merge vs rebase

# Merge: combine histories, creates a merge commit
git switch main
git merge feature/eda

# Rebase: replay your commits on top of another branch (linear history)
git switch feature/eda
git rebase main

# Abort on trouble
git merge --abort
git rebase --abort
merge rebase
History branching (real) linear (cleaner)
Safety easy to undo rewrites your commits
Use when sharing a branch with others cleaning local commits before PR

Stash (put work aside)

git stash                    # save uncommitted changes, clean tree
git stash list
git stash pop                # restore most recent
git stash pop stash@{2}      # restore a specific one
git stash push -m "wip" -u   # include untracked files (-u)
git stash drop stash@{0}

Common Operations

Undo — reset vs revert (know the difference!)

# LOCAL, safe undo (files, staging, commits)
git restore <file>           # discard unstaged changes (was: checkout --)
git restore --staged <file>  # unstage (was: reset HEAD <file>)
git commit --amend -m "..."  # fix the LAST commit message/content

# Move HEAD — only for commits NOT pushed/shared
git reset --soft HEAD~1      # undo commit, keep changes staged
git reset HEAD~1             # undo commit, keep changes unstaged
git reset --hard HEAD~1      # undo commit AND discard changes (dangerous!)
git reset --hard origin/main # discard local, match remote

# SHARED history — never reset; revert creates an inverse commit
git revert HEAD              # new commit undoing the last one
git revert <commit-hash>     # safe on pushed branches

Golden rule: use reset before pushing, revert after pushing.

Tags & releases

git tag v1.0.0               # lightweight tag
git tag -a v1.0.0 -m "release 1.0"   # annotated (recommended)
git tag                     # list
git push origin v1.0.0      # push a tag
git checkout v1.0.0         # inspect code at a release

Remotes

git remote -v                        # show remotes
git remote add origin <url>          # add remote
git remote remove origin
git fetch origin                     # download remote changes (no merge)
git pull origin main                 # fetch + merge
git push origin main
git push -u origin my-branch         # -u: set upstream, then plain git push

fetch vs pull: pull = fetch + merge. Fetch first to inspect changes before merging.

History & diff

git log --oneline --graph --all      # visual history
git log --oneline -5                 # last 5 commits
git log --oneline -- model.py        # commits touching a file
git log -S "def train" --oneline     # when did this string appear?
git show <hash>                      # full diff of one commit
git diff main..feature               # differences between branches
git diff --stat                      # summary of changes
git blame model.py                   # who changed each line

cherry-pick (take specific commits)

git cherry-pick <commit-hash>        # apply one commit onto current branch
git cherry-pick a1b2c3d e4f5a6b      # several
# after conflict: fix files, git add ., git cherry-pick --continue

Useful for moving a hotfix from main to a release branch without merging everything.

Practical Examples

1. Start a new project the right way

mkdir project && cd project
git init
git switch -c main
echo ".venv/" > .gitignore
echo "# Project" > README.md
git add . && git commit -m "Initial commit"
git remote add origin https://github.com/you/project.git
git push -u origin main

2. Feature branch + PR flow (see github.md)

git switch -c feature/clean-data
# ... work ...
git add data_cleaning.py
git commit -m "Add missing-value handling"
git push -u origin feature/clean-data
# open a pull request on GitHub

3. Resolve a merge conflict

git merge feature/eda
# CONFLICT in model.py — edit the file:
#   <<<<<<< HEAD ... your version ... ======= ... theirs ... >>>>>>> feature/eda
git add model.py              # resolved
git commit                    # finish the merge

4. Recover "lost" work

git reflog                    # every move of HEAD — your safety net
git checkout <hash>           # inspect, then branch or cherry-pick from it
# reset --hard gone wrong? reflog finds the commit and restores it

Common Patterns

# Save a progress snapshot before risky experiments
git add -A && git commit -m "checkpoint before refactor"

# Only commit files matching a pattern
git add "*.py" "notebooks/*.ipynb"

# Skip large/generated junk: .gitignore essentials
#   .venv/  __pycache__/  *.pyc  .ipynb_checkpoints/  data/  *.log  .DS_Store

# Commit message style: imperative, short subject + body
git commit -m "Fix NaN handling in split" -m "Replace dropna with median fill"

# Nicely formatted short log
git log --pretty=format:"%h %s (%an)" --graph

Best Practices

  • Commit often, commit small — one logical change per commit, clear messages.
  • Check git status + git diff before every commit — never commit blind.
  • Never commit data, secrets, or .venv — .gitignore them.
  • Pull before you push and resolve conflicts locally.
  • Branch per feature/experiment; keep main deployable.
  • Don't reset --hard pushed commits — revert instead (respects collaborators).
  • Notebooks are hard to diff — use nbstripout or JupyterLab Git to keep outputs out.
  • Commit notebooks with outputs cleared unless a reviewer needs them.
  • Use git reflog before panicking — almost everything is recoverable.

Common Mistakes

Mistake Consequence Fix
git add . blindly Commits junk/secrets git status first; add specific files
Committing directly to main Messy, hard-to-review history Feature branches
reset --hard on shared history Destroys others' work git revert on pushed branches
No .gitignore Env/data files in history forever Add early; git rm --cached to untrack
Vague commit messages Useless history Describe the why
git pull when local commits exist Merge commit noise or conflicts pull --rebase if you prefer linear
Editing files during a merge Losing resolved work Resolve, add, then commit/continue

Troubleshooting

Symptom Cause Fix
Please tell me who you are No user.name/email git config --global user.name ...
Authentication failed Password/HTTPS without token SSH key or personal access token
Your branch is ahead by N commits Committed locally, not pushed git push
Conflict markers everywhere Unfinished merge/rebase Resolve, add, commit/--continue, or --abort
fatal: not a git repository Wrong directory cd into the repo; check .git
Accidental reset --hard Lost commits git reflog → git reset --hard <hash>
Permission denied (publickey) SSH key not set up ssh-keygen, add to GitHub (github.md)
Huge repo clone slow History bloat Shallow: git clone --depth 1

Official Documentation

Last Updated

2026-09-06 — Initial version.