Snapshots, history, and an infinite undo button — the professional way to keep track of your work.
status, log, and diff.gitignore that keeps junk and secrets outAnd why project_v2_final_FINAL is a disaster.
Q3_reserving\
├── reserve_model.xlsx
├── reserve_model_v2.xlsx
├── reserve_model_v2_JS_comments.xlsx
├── reserve_model_v3.xlsx
├── reserve_model_v3_final.xlsx
├── reserve_model_v3_final_FINAL.xlsx
├── reserve_model_v3_final_FINAL_fixed.xlsx
└── reserve_model_USE_THIS_ONE.xlsx
Folder-copy versioning answers none of these reliably.
e41c9a2 (HEAD -> main) Use 2025 lapse assumptions in projection
7b0d315 Fix off-by-one in policy-year calculation
c93a8f0 Add IBNR chain-ladder method
5f12e7b Load claims extract from data/raw
a0b3c11 Initial project structure
An audit trail for models: “show me the code that produced the Q3 numbers” becomes a one-line command.
.git\ folder inside your projectAnalogy: Git is like Word’s Track Changes engine; GitHub is like SharePoint for storing and sharing the tracked files.
A GitHub profile, Git for Windows, and your identity.
jane-doe-actuary, not xXdragonslayerXx)Keep your email private: Settings → Emails → tick Keep my email addresses private. GitHub gives you a …@users.noreply.github.com address to use in Git instead.
Work projects with company data belong in your employer’s private organization — never a personal public repo.
winget install --id Git.Git -e --source winget
…or download from git-scm.com. The installer has many screens; defaults are fine except:
| Default editor | Pick Notepad or VS Code — not Vim |
| Initial branch name | Override → main |
| PATH | Git from the command line and also from 3rd-party software |
| Line endings | Checkout Windows-style, commit Unix-style |
Then, in a new terminal (the installer changed your PATH):
PS> git --version
git version 2.51.0.windows.1
Git for Windows also installs Git Bash (a mini UNIX shell) and Git Credential Manager, which handles GitHub sign-in through your browser.
autocrlf = trueText files mark the end of each line with invisible characters:
| Windows | CR LF (\r\n) |
| Linux / macOS | LF (\n) |
Mix them and every line of a file looks “changed” in Git — even though nothing visibly did.
git config --global core.autocrlf true
CRLF — Windows-friendlyLF — portable for everyonegit config --global user.name "Jane Doe"
git config --global user.email "12345678+jane-doe-actuary@users.noreply.github.com"
git config --global init.defaultBranch main
git config --global core.autocrlf true
git config --global --list # check everything
Your name and email are stamped on every commit you make. Use the same email as your GitHub account (or its noreply address) so commits link to your profile.
--global settings live in C:\Users\Jane\.gitconfig — a plain text file. Open it with notepad ~\.gitconfig.
Working tree → staging area → commit history.
.git\Why a staging area? You edited three files, but only two belong together. Stage those two, commit them with one clear message, then deal with the third separately.
Like preparing a journal entry: you choose which adjustments go into this posting, review them, then post it with a description.
git init and git statusPS C:\actuarial_work\lapse_analytics> git init
Initialized empty Git repository in C:/actuarial_work/lapse_analytics/.git/
PS C:\actuarial_work\lapse_analytics> git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
.python-version
README.md
check_env.py
main.py
pyproject.toml
uv.lock
git status is your dashboard. Run it constantly — it always tells you what to do next. (Notice .venv is missing: uv’s .gitignore already excludes it.)
git add and git commitgit add pyproject.toml uv.lock .python-version
git commit -m "Set up uv project with pandas and numpy"
git add main.py check_env.py
git commit -m "Add environment check script"
git add . # stage everything that changed
git commit -m "Describe project in README"
| ✗ | stuff, fix, asdf, final |
| ✓ | Add chain-ladder IBNR method |
| ✓ | Fix policy-year off-by-one in lapse rates |
Make atomic commits: one logical change per commit. Write the message as a command: “Add…”, “Fix…”, “Remove…”.
log and diffPS> git log --oneline
3c1e2d4 (HEAD -> main) Describe project in README
9a7b6f0 Add environment check script
51d0e8a Set up uv project with pandas and numpy
PS> git diff
diff --git a/check_env.py b/check_env.py
@@ -12,3 +12,4 @@
df["px"] = 1 - df["qx"]
-print(df)
+df["mu"] = -np.log(df["px"]) # constant force
+print(df.round(5))
| Command | Shows |
|---|---|
git status | What’s changed / staged / untracked |
git diff | Unstaged line changes |
git diff --staged | What the next commit will contain |
git log --oneline | Compact history |
git show 9a7b6f0 | One commit in full |
Red - lines were removed; green + lines were added. Press q to exit long output.
| Situation | Command | Risk |
|---|---|---|
| Staged something by mistake | git restore --staged file | Safe — edits kept |
| Want to throw away edits to a file | git restore file | Uncommitted edits are lost |
| Typo in the last commit message (not pushed yet) | git commit --amend -m "…" | Rewrites last commit |
| A committed change was wrong | git revert <commit> | Safe — adds an “undo” commit |
| See an old version of a file | git show a0b3c11:main.py | Read-only |
Once something is committed, it is very hard to lose. Commit early, commit often.
.venv\uv.lock*.pkl.csv.env files. Once pushed, assume they’re compromisedPolicyholder and claims data is personal data. Committing it — especially to a public repo — can be a regulatory breach. Keep data out; commit the code that reads it.
.gitignore tuned for Python & Jupyter# Python / uv
__pycache__/
*.py[oc]
.venv/
build/
dist/
*.egg-info
# Jupyter
.ipynb_checkpoints/
# Data & derived artefacts
data/raw/
*.pkl
*.parquet
output/
# Secrets
.env
*.key
credentials*.json
# OS & Office clutter
Thumbs.db
desktop.ini
~$*
# starts a commentfolder/ ignores a whole directory* is a wildcard.gitignore itself.gitignore only affects untracked files. If you already committed something, remove it from tracking with git rm --cached file.
Check it works: git status --ignored
lapse_analytics → Private → don’t add a READMEgit remote add origin https://github.com/jane-doe-actuary/lapse_analytics.git
git push -u origin main # first time: a browser window opens so you can sign in
git push # every time after that
commit saves a snapshot locally. push copies your snapshots to GitHub. They are separate steps.
autocrlf, and default branchC:\actuarial_work\lapse_analytics (Module 4).gitignore for Python/Jupyter and prove it workscd C:\actuarial_work\lapse_analytics
git init # "Reinitialized…" is fine if uv already did it
notepad .gitignore # add the Jupyter / data / secrets sections
mkdir data\raw; Set-Content data\raw\claims.csv "id,amount`n1,1200"
Set-Content .env "API_KEY=not-a-real-key"
git status # claims.csv and .env must NOT appear
git status --ignored # …but they show up here
git add .gitignore
git commit -m "Ignore venv, data, notebook checkpoints and secrets"
git add pyproject.toml uv.lock .python-version
git commit -m "Set up uv project with pandas, numpy, openpyxl"
git add main.py check_env.py README.md
git commit -m "Add starter scripts and README"
git log --oneline
check_env.py: add a force-of-mortality column mu (see the diff slide)git status → git diff → read the red/green linesgit add check_env.py → git diff --stagedgit log --onelinegit restorewinget install --id Microsoft.VisualStudioCode -e
# new terminal, then:
code .
Open the Source Control panel (Ctrl+Shift+G) and click a changed file for a side-by-side diff.
git --version works; name, email, autocrlf are setinit, add, commit, and write a good messagestatus, log --oneline, and diff to inspect state.gitignore excludes .venv, data, pickles, and secretslapse_analytics project has at least 4 commitsPlain-text documents that render beautifully — and notebooks that mix code, results, and prose.