@jaspermayone's dotfiles
at main 424 lines 12 kB view raw
1{ 2 lib, 3 config, 4 pkgs, 5 isDarwin, 6 ... 7}: 8with lib; 9{ 10 options.jsp.git = { 11 enable = mkEnableOption "Git configuration"; 12 }; 13 14 config = mkIf config.jsp.git.enable { 15 programs.git = { 16 enable = true; 17 lfs.enable = true; 18 19 # Conditional includes for different work contexts 20 includes = [ 21 { 22 path = pkgs.writeText "gitconfig-phishdir" '' 23 [user] 24 email = jasper.mayone@phish.directory 25 ''; 26 condition = "gitdir/i:~/dev/projects/phishdirectory/**"; 27 } 28 { 29 path = pkgs.writeText "gitconfig-singlefeather" '' 30 [user] 31 email = jasper.mayone@singlefeather.com 32 ''; 33 condition = "gitdir/i:~/dev/work/singlefeather/**"; 34 } 35 { 36 path = pkgs.writeText "gitconfig-mlh" '' 37 [user] 38 email = jasper.mayone@majorleaguehacking.com 39 ''; 40 condition = "gitdir/i:~/dev/work/mlh/eng/**"; 41 } 42 { 43 path = pkgs.writeText "gitconfig-patchwork" '' 44 [user] 45 email = jasper@patchworklabs.org 46 ''; 47 condition = "gitdir/i:~/dev/patchwork/**"; 48 } 49 { 50 path = pkgs.writeText "gitconfig-school" '' 51 [user] 52 email = mayonej@wit.edu 53 ''; 54 condition = "gitdir/i:~/dev/school/**"; 55 } 56 { 57 path = pkgs.writeText "gitconfig-personal" '' 58 [user] 59 email = me@jaspermayone.com 60 ''; 61 condition = "gitdir/i:~/dev/personal/**"; 62 } 63 ]; 64 65 # Global git ignore 66 ignores = [ 67 # Compiled source 68 "*.com" 69 "*.class" 70 "*.dll" 71 "*.exe" 72 "*.o" 73 "*.so" 74 75 # Packages 76 "*.7z" 77 "*.dmg" 78 "*.gz" 79 "*.iso" 80 "*.jar" 81 "*.rar" 82 "*.tar" 83 "*.zip" 84 85 # Logs 86 "*.log" 87 88 # OS generated files 89 ".DS_Store" 90 ".DS_Store?" 91 "*/.DS_Store" 92 "**/.DS_Store" 93 "._*" 94 ".Spotlight-V100" 95 ".Trashes" 96 "ehthumbs.db" 97 "Thumbs.db" 98 99 # Claude Code 100 ".llm-orc/*" 101 "CLAUDE.local.md" 102 ]; 103 104 settings = { 105 alias = { 106 # Quick shortcuts 107 co = "checkout"; 108 br = "branch"; 109 ci = "commit"; 110 st = "status"; 111 unstage = "reset HEAD --"; 112 last = "log -1 HEAD"; 113 pushfwl = "push --force-with-lease --force-if-includes"; 114 115 # View abbreviated SHA, description, and history graph of the latest 20 commits 116 l = "log --pretty=oneline -n 20 --graph --abbrev-commit"; 117 lg = "log --oneline --graph --decorate"; 118 119 # View the current working tree status using the short format 120 s = "status -s"; 121 122 # Show the diff between the latest commit and the current state 123 d = "!git diff-index --quiet HEAD -- || clear; git --no-pager diff --patch-with-stat"; 124 125 # `git di $number` shows the diff between the state `$number` revisions ago and the current state 126 di = "!d() { git diff --patch-with-stat HEAD~$1; }; git diff-index --quiet HEAD -- || clear; d"; 127 128 # Pull in remote changes for the current repository and all its submodules 129 p = "pull --recurse-submodules"; 130 131 # Clone a repository including all submodules 132 c = "clone --recursive"; 133 134 # Commit all changes 135 ca = "!git add ':(exclude,attr:builtin_objectmode=160000)' && git commit -av"; 136 137 # Switch to a branch, creating it if necessary 138 go = "!f() { git checkout -b \"$1\" 2> /dev/null || git checkout \"$1\"; }; f"; 139 140 # Show verbose output about tags, branches or remotes 141 tags = "tag -l"; 142 branches = "branch --all"; 143 remotes = "remote --verbose"; 144 145 # List aliases 146 aliases = "config --get-regexp alias"; 147 148 # Amend the currently staged files to the latest commit 149 amend = "commit --amend --reuse-message=HEAD"; 150 151 # Credit an author on the latest commit 152 credit = "!f() { git commit --amend --author \"$1 <$2>\" -C HEAD; }; f"; 153 154 # Interactive rebase with the given number of latest commits 155 reb = "!r() { git rebase -i HEAD~$1; }; r"; 156 157 # Remove the old tag with this name and tag the latest commit with it 158 retag = "!r() { git tag -d $1 && git push origin :refs/tags/$1 && git tag $1; }; r"; 159 160 # Find branches containing commit 161 fb = "!f() { git branch -a --contains $1; }; f"; 162 163 # Find tags containing commit 164 ft = "!f() { git describe --always --contains $1; }; f"; 165 166 # Find commits by source code 167 fc = "!f() { git log --pretty=format:'%C(yellow)%h %Cblue%ad %Creset%s%Cgreen [%cn] %Cred%d' --decorate --date=short -S$1; }; f"; 168 169 # Find commits by commit message 170 fm = "!f() { git log --pretty=format:'%C(yellow)%h %Cblue%ad %Creset%s%Cgreen [%cn] %Cred%d' --decorate --date=short --grep=$1; }; f"; 171 172 # Remove branches that have already been merged with main (a.k.a. 'delete merged') 173 dm = "!git branch --merged | grep -v '\\\\*' | xargs -n 1 git branch -d"; 174 175 # List contributors with number of commits 176 contributors = "shortlog --summary --numbered"; 177 178 # Show the user email for the current repository 179 whoami = "config user.email"; 180 }; 181 182 user = { 183 name = "Jasper Mayone"; 184 email = "me@jaspermayone.com"; 185 signingKey = "14D0D45A1DADAAFA"; 186 }; 187 188 init.defaultBranch = "main"; 189 190 apply.whitespace = "fix"; 191 192 core = { 193 editor = "code --wait"; 194 pager = "less"; 195 # Treat spaces before tabs and trailing whitespace as errors 196 whitespace = "space-before-tab,-indent-with-non-tab,trailing-space"; 197 # Make `git rebase` safer on macOS 198 trustctime = false; 199 # Prevent showing files with non-ASCII names as unversioned 200 precomposeunicode = false; 201 # Speed up commands involving untracked files 202 untrackedCache = true; 203 }; 204 205 color = { 206 ui = "auto"; 207 branch = { 208 current = "yellow reverse"; 209 local = "yellow"; 210 remote = "green"; 211 }; 212 }; 213 214 diff = { 215 algorithm = "histogram"; 216 tool = "windsurf"; 217 renames = "copies"; # Detect copies as well as renames 218 }; 219 220 "difftool \"windsurf\"".cmd = "windsurf --diff $LOCAL $REMOTE"; 221 222 # Binary file diff using hexdump 223 "diff \"bin\"".textconv = "hexdump -v -C"; 224 225 # Bun lockfile diff 226 "diff \"lockb\"" = { 227 textconv = "bun"; 228 binary = true; 229 }; 230 231 # Include summaries of merged commits in merge commit messages 232 merge.log = true; 233 234 pull.rebase = true; 235 236 push = { 237 default = "simple"; 238 followTags = true; 239 autoSetupRemote = true; 240 }; 241 242 rebase.autoStash = true; 243 244 status = { 245 submoduleSummary = true; 246 showUntrackedFiles = "all"; 247 }; 248 249 tag = { 250 sort = "version:refname"; 251 forceSignAnnotated = true; 252 gpgsign = true; 253 }; 254 255 versionsort = { 256 prereleaseSuffix = [ 257 "-pre" 258 ".pre" 259 "-beta" 260 ".beta" 261 "-rc" 262 ".rc" 263 ]; 264 }; 265 266 commit.gpgSign = true; 267 268 gpg = { 269 program = if isDarwin then "/opt/homebrew/bin/gpg" else "gpg"; 270 format = "openpgp"; 271 }; 272 273 help.autocorrect = 1; 274 275 # URL shorthands 276 "url \"git@github.com:\"" = { 277 insteadOf = "gh:"; 278 pushInsteadOf = "https://github.com/"; 279 }; 280 "url \"git://github.com/\"".insteadOf = "github:"; 281 "url \"git@gist.github.com:\"".insteadOf = "gst:"; 282 "url \"git://gist.github.com/\"".insteadOf = "gist:"; 283 284 sequence.editor = "code --wait"; 285 286 branch.sort = "-committerdate"; 287 column.ui = "auto"; 288 } // (if isDarwin then { 289 # macOS specific 290 credential = { 291 helper = "osxkeychain"; 292 }; 293 "credential \"https://dev.azure.com\"".useHttpPath = true; 294 } else { }); 295 }; 296 297 # Delta for better diffs 298 programs.delta = { 299 enable = true; 300 options = { 301 navigate = true; 302 light = false; 303 line-numbers = true; 304 }; 305 }; 306 307 # GitHub CLI 308 programs.gh = { 309 enable = true; 310 settings = { 311 git_protocol = "ssh"; 312 }; 313 }; 314 315 # Lazygit 316 programs.lazygit = { 317 enable = true; 318 settings = { 319 gui.theme = { 320 lightTheme = false; 321 activeBorderColor = [ 322 "blue" 323 "bold" 324 ]; 325 inactiveBorderColor = [ "black" ]; 326 selectedLineBgColor = [ "default" ]; 327 }; 328 }; 329 }; 330 331 # GitHub Dashboard 332 programs.gh-dash = { 333 enable = true; 334 settings = { 335 prSections = [ 336 { 337 title = "Mine"; 338 filters = "is:open author:@me updated:>={{ nowModify \"-3w\" }} sort:updated-desc archived:false"; 339 layout.author.hidden = true; 340 } 341 { 342 title = "Review"; 343 filters = "sort:updated-desc is:pr is:open review-requested:jaspermayone archived:false"; 344 } 345 { 346 title = "All"; 347 filters = "sort:updated-desc is:pr is:open user:@me archived:false"; 348 } 349 ]; 350 issuesSections = [ 351 { 352 title = "Assigned"; 353 filters = "is:issue state:open archived:false assignee:@me sort:updated-desc"; 354 } 355 { 356 title = "Created"; 357 filters = "author:@me is:open archived:false"; 358 } 359 { 360 title = "All"; 361 filters = "is:issue involves:@me archived:false sort:updated-desc is:open"; 362 } 363 ]; 364 defaults = { 365 view = "prs"; 366 refetchIntervalMinutes = 5; 367 layout.prs = { 368 repoName = { 369 grow = true; 370 width = 10; 371 hidden = false; 372 }; 373 base.hidden = true; 374 }; 375 preview = { 376 open = true; 377 width = 84; 378 }; 379 prsLimit = 20; 380 issuesLimit = 20; 381 }; 382 repoPaths = { 383 "jaspermayone/*" = "~/dev/personal/*"; 384 "phishdirectory/*" = "~/dev/projects/phishdirectory/*"; 385 }; 386 keybindings = { 387 universal = [ 388 { 389 key = "g"; 390 name = "lazygit"; 391 command = "cd {{.RepoPath}} && lazygit"; 392 } 393 ]; 394 prs = [ 395 { 396 key = "O"; 397 builtin = "checkout"; 398 } 399 { 400 key = "m"; 401 command = "gh pr merge --admin --repo {{.RepoName}} {{.PrNumber}}"; 402 } 403 { 404 key = "a"; 405 name = "lazygit add"; 406 command = "cd {{.RepoPath}} && git add -A && lazygit"; 407 } 408 { 409 key = "v"; 410 name = "approve"; 411 command = "gh pr review --repo {{.RepoName}} --approve --body \"$(gum input --prompt='Approval Comment: ')\" {{.PrNumber}}"; 412 } 413 ]; 414 }; 415 theme = { 416 ui = { 417 sectionsShowCount = true; 418 table.compact = false; 419 }; 420 }; 421 }; 422 }; 423 }; 424}