Mike San Román's homepage

Your git config is a map of where your workflow was breaking

October 03, 2025

I was reviewing my .gitconfig last week when I realized something. It's a fossil record.

Every alias marks a moment where I hit enough friction that automation became necessary.

What your aliases actually reveal

Look at any developer's .gitconfig and you can reverse-engineer their pain points:

→ Mistake recovery aliases exist because you make predictable errors → Flow protection aliases reduce interruptions to deep work → Mental overhead aliases automate what shouldn't require thinking → Integration aliases bridge tools that don't talk to each other

My .gitconfig has 15 custom aliases. Each one has a story.

Mistake recovery

[alias]
  undo = reset HEAD~
  p = add -p
[alias]
  undo = reset HEAD~
  p = add -p

I've committed prematurely hundreds of times. Usually when I'm in flow and my fingers move faster than my judgment.

The undo alias makes recovery instant. No breaking flow to remember exact syntax for git reset HEAD~.

The p alias for patch mode might be my most valuable shortcut. Lets me craft atomic commits from messy work-in-progress. Before this, my commit history was chaos. Now it's documentation.

Flow protection

[alias]
  s = status -sb
  d = diff --word-diff -w
[alias]
  s = status -sb
  d = diff --word-diff -w

Default git status breaks flow with unnecessary information. File paths, staging instructions, branch info: all formatted for maximum vertical space.

Short status is one line per file. Branch tracking included. Get oriented and get back to work.

Word diff solves a different problem. When editing blog posts, line-based diffs obscure what changed. Word-level diffs with whitespace ignored show the actual changes.

Mental overhead elimination

[alias]
  recent = branch --sort=-committerdate --format="%(committerdate:relative)%09%(refname:short)"
  task = "!sh -c \"git checkout -t origin/main -b task/$1\" -"
  fix = "!sh -c \"git checkout -t origin/main -b fix/$1\" -"
  spike = "!sh -c \"git checkout -t origin/main -b spike/$1\" -"
[alias]
  recent = branch --sort=-committerdate --format="%(committerdate:relative)%09%(refname:short)"
  task = "!sh -c \"git checkout -t origin/main -b task/$1\" -"
  fix = "!sh -c \"git checkout -t origin/main -b fix/$1\" -"
  spike = "!sh -c \"git checkout -t origin/main -b spike/$1\" -"

The recent alias emerged after I couldn't remember which branch I was working on yesterday for the third time in a week.

git branch and visual scanning works until you have 15 local branches. Now git recent shows branches sorted by last commit. Most recent work always at the top.

The branch creation aliases solve naming consistency. Before these, I created branches with random patterns. task/feature-name, feature/task-name, just feature-name.

Inconsistent naming creates cognitive debt. Every branch name requires mental energy.

Now: git task ABC-123 gives you task/ABC-123 branched from latest main. Pattern becomes automatic. Overhead disappears.

Integration bridges

[alias]
  open = "!gh repo view -w"
  pr = "!gh pr view -w"
[alias]
  open = "!gh repo view -w"
  pr = "!gh pr view -w"

These are my newest aliases. Both added this year.

I was manually navigating to GitHub in my browser dozens of times daily. Check terminal for repo name, switch to browser, type github.com, search, click through. Maybe 30 seconds.

Thirty seconds, fifty times per day. That's 25 minutes of pure context switching. Plus the browser rabbit holes that inevitably followed.

Now git open launches the current repository. git pr opens the current PR. Friction vanished.

Visual optimization

[core]
  pager = diff-so-fancy | less --tabs=4 -RFX

[color "diff-highlight"]
  oldNormal = red bold
  oldHighlight = red bold 52
  newNormal = green bold
  newHighlight = green bold 22
[core]
  pager = diff-so-fancy | less --tabs=4 -RFX

[color "diff-highlight"]
  oldNormal = red bold
  oldHighlight = red bold 52
  newNormal = green bold
  newHighlight = green bold 22

I spent years with default git diff colors. They worked. They were fine.

Then I configured diff-so-fancy and realized "fine" was costing me comprehension speed. Better visual hierarchy means faster scanning. Less time staring at diffs trying to understand what changed.

Rebase safety

[rebase]
  instructionFormat = %s [%an]
[rebase]
  instructionFormat = %s [%an]

Interactive rebases used to show just commit messages. Useful but incomplete.

Adding author names creates crucial context. When squashing commits or reordering history, knowing who wrote what matters. Especially in collaborative branches.

This made interactive rebasing feel safer. Less guesswork, more confidence.

My complete .gitconfig

Here's the full configuration:

[user]
  name = Mike San Román
  email = mike@msanroman.io

[alias]
  # Mistake recovery
  undo = reset HEAD~
  p = add -p

  # Flow protection
  co = checkout
  s = status -sb
  d = diff --word-diff -w

  # Mental overhead elimination
  recent = branch --sort=-committerdate --format="%(committerdate:relative)%09%(refname:short)"
  task = "!sh -c \"git checkout -t origin/main -b task/$1\" -"
  fix = "!sh -c \"git checkout -t origin/main -b fix/$1\" -"
  spike = "!sh -c \"git checkout -t origin/main -b spike/$1\" -"

  # Integration bridges
  open = "!gh repo view -w"
  pr = "!gh pr view -w"

  # Quick commits and status
  ci = commit
  sf = checkout --theirs shared/config/static.php
  cc = "grep '<<<< HEAD'"

[core]
  editor = cursor
  excludesfile = /Users/mike/.gitignore
  pager = diff-so-fancy | less --tabs=4 -RFX

[color]
  ui = true

[color "diff-highlight"]
  oldNormal = red bold
  oldHighlight = red bold 52
  newNormal = green bold
  newHighlight = green bold 22

[color "diff"]
  meta = 11
  frag = magenta bold
  commit = yellow bold
  old = red bold
  new = green bold
  whitespace = red reverse

[rebase]
  instructionFormat = %s [%an]

[pull]
  rebase = true

[init]
  defaultBranch = main
[user]
  name = Mike San Román
  email = mike@msanroman.io

[alias]
  # Mistake recovery
  undo = reset HEAD~
  p = add -p

  # Flow protection
  co = checkout
  s = status -sb
  d = diff --word-diff -w

  # Mental overhead elimination
  recent = branch --sort=-committerdate --format="%(committerdate:relative)%09%(refname:short)"
  task = "!sh -c \"git checkout -t origin/main -b task/$1\" -"
  fix = "!sh -c \"git checkout -t origin/main -b fix/$1\" -"
  spike = "!sh -c \"git checkout -t origin/main -b spike/$1\" -"

  # Integration bridges
  open = "!gh repo view -w"
  pr = "!gh pr view -w"

  # Quick commits and status
  ci = commit
  sf = checkout --theirs shared/config/static.php
  cc = "grep '<<<< HEAD'"

[core]
  editor = cursor
  excludesfile = /Users/mike/.gitignore
  pager = diff-so-fancy | less --tabs=4 -RFX

[color]
  ui = true

[color "diff-highlight"]
  oldNormal = red bold
  oldHighlight = red bold 52
  newNormal = green bold
  newHighlight = green bold 22

[color "diff"]
  meta = 11
  frag = magenta bold
  commit = yellow bold
  old = red bold
  new = green bold
  whitespace = red reverse

[rebase]
  instructionFormat = %s [%an]

[pull]
  rebase = true

[init]
  defaultBranch = main

How your config evolves

Five years ago, my aliases focused on typing reduction. st for status, co for checkout. Character count optimization.

Three years ago, they shifted to workflow standardization. Branch naming patterns, commit formatting, rebase configuration.

This year, they're about tool integration. GitHub CLI bridges, visual formatting, cross-tool automation.

The evolution reveals how my work has changed. Less time typing git commands. More time orchestrating tools.

Building your own diagnostic tool

Track git commands you type more than twice in a day. Not just for aliasing. For workflow diagnosis.

Repeatedly typing git log --oneline --graph --all? You're revealing that understanding branch history is harder than it should be.

Constantly running git fetch && git rebase origin/main? Keeping branches current requires manual intervention instead of automated process.

Your repeated commands document exactly where your workflow needs improvement.

The friction you're still tolerating

I realized I needed git open when I manually navigated to GitHub three times in ten minutes. The repetition made the friction visible. Once visible, it became intolerable.

Your unwritten aliases are your active pain points. The commands you type repeatedly. The sequences that break your flow. The mental overhead you've normalized.

Start with awareness

You don't need to overhaul your entire .gitconfig today.

Just start noticing. When you type the same git command twice in an hour, note it. When you manually navigate to GitHub for the third time, mark it.

Your workflow is trying to tell you where it's breaking. The friction is the signal.

Six months from now, you can look back at your config and see exactly how your work evolved. Not through abstract reflection, but through concrete evidence of what friction you chose to eliminate.