[user]
	; Don't try to guess `user.name` and `user.email`.
	useConfigOnly = true

[include]
	path = ~/.gitconfig-user

[core]
	; If the `LESS` environment variable is unset, Git (naively) prepends
	; `LESS=FRX` to the shell expression given in `pager` (or it's
	; default). `X` disables sending termcap (alternate screen)
	; initialization and deinitialization strings to the terminal, which
	; disables mouse scrolling and makes long text scroll past previous
	; context.
	; pager = LESS=FR less
	pager = diff-highlight | LESS=FR less
	; TODO: E.g. `attributesFile` defaults to
	; `$XDG_CONFIG_HOME/git/attributes`. Maybe this is a better place to
	; put these?
	hooksPath      = ~/.githooks
	excludesFile   = ~/.gitignore
	attributesFile = ~/.gitattributes
	; Print paths verbatim (e.g. UTF-8).
	quotePath = false
	; Disable newline conversion (mangling). This relies on editors *also*
	; not doing any conversions or else you will get huge useless diffs.
	; Also be aware of text files copied verbatim from somewhere else such
	; as the internet. The Git default of having only LF in commits (autocrlf = false), but sometimes .
	; autocrlf = input
	; If we re-enable conversion (see above), reject on failed roundtrip.
	safecrlf = true

; [pager]
; 	; As suggested in `contrib/diff-highlight/README`, except as explained
; 	; in `core.pager` above.
; 	log  = diff-highlight | less -+X
; 	show = diff-highlight | less -+X
; 	diff = diff-highlight | less -+X

[interactive]
	; TODO: It is untested if this is needed or happens by virtue of
	; `core.pager`. Also untested if it has any ill effects.
	diffFilter = diff-highlight

[init]
	templateDir = ~/.gittemplate
	defaultBranch = master
	; defaultBranch = main

[remote]
	pushDefault = origin

[push]
	default = current ; This obviates `git push --set-upstream`.
	; In the past, `current` was commented out and we used `upstream`
	; instead, unsure why.
	; default = upstream
	recurseSubmodules = check
	autoSetupRemote = true ; Git 2.37

[branch]
	autoSetupMerge  = always
	autoSetupRebase = always

[fetch]
	prune     = true
	pruneTags = true

[rebase]
	autoSquash   = true
	autoStash    = true
	rebaseMerges = true
	updateRefs   = true
	missingCommitsCheck = error
	instructionFormat = %s%nexec GIT_COMMITTER_DATE='%ci' GIT_AUTHOR_DATE='%ai' git commit --amend --no-edit --reset-author

[pull]
	rebase = merges

[merge]
	ff = false
	autoStash = true
	conflictStyle = diff3
	; TODO: `zdiff3` removes edge common lines but is too new?
	; conflictStyle = zdiff3

[am]
	threeWay = true

[rerere]
	enabled = true

[diff]
	renames   = copies
	algorithm = histogram

[url "ssh://git@"]
	pushInsteadOf = https://

[protocol]
	allow = never

[protocol "file"]
	allow = always

[protocol "ssh"]
	allow = always

[protocol "https"]
	allow = always

[transfer]
	fsckObjects = true

[fsck]
	zeroPaddedFilemode = warn
	badTimezone        = warn

[receive "fsck"]
	zeroPaddedFilemode = warn
	badTimezone        = warn

[fetch "fsck"]
	zeroPaddedFilemode = warn
	badTimezone        = warn

[notes]
	rewriteRef = refs/notes/commits

[format]
	notes = true

[status]
	showStash = true
	submoduleSummary = true

[log]
	; abbrevCommit = true
	decorate = short

[log]
	date = relative

[blame]
	date = relative

[log]
	graphColors = \
	  BrightRed, \
	  BrightGreen, \
	  BrightYellow, \
	  BrightBlue, \
	  BrightMagenta, \
	  BrightCyan

[diff]
	wsErrorHighlight = all
	colorMoved       = zebra
	colorMovedWS     = ignore-space-change

[color "diff"]
	; TODO: Harmonize with `vimdiff`?
	; TODO: Use `dim` and remove `Bright`? Terminal support?
	commit                    = BrightYellow
	meta                      = BrightBlue
	frag                      =       Blue
	func                      =       Blue
	context                   = BrightWhite
	contextBold               = BrightWhite   reverse
	contextDimmed             =       White   reverse
	old                       = BrightRed
	oldBold                   = BrightRed     reverse
	oldDimmed                 =       Red     reverse
	new                       = BrightGreen
	newBold                   = BrightGreen   reverse
	newDimmed                 =       Green   reverse
	oldMoved                  = BrightMagenta
	oldMovedDimmed            = BrightMagenta
	oldMovedAlternative       =       Magenta
	oldMovedAlternativeDimmed =       Magenta
	newMoved                  = BrightCyan
	newMovedDimmed            = BrightCyan
	newMovedAlternative       =       Cyan
	newMovedAlternativeDimmed =       Cyan
	whitespace                = BrightRed     reverse

[color "diff-highlight"]
	; TODO: Harmonize with `vimdiff`?
	oldNormal    = BrightRed
	newNormal    = BrightGreen
	oldHighlight = BrightRed   Red
	newHighlight = BrightGreen Green

[blame]
	; coloring = repeatedLines
	coloring = highlightRecent

[color "blame"]
	; repeatedLines = White
	highlightRecent = \
	  245, 2  years ago, \
	  246, 1   year ago, \
	  247, 6 months ago, \
	  248, 3 months ago, \
	  249, 1 months ago, \
	  250, 2  weeks ago, \
	  251, 1  weeks ago, \
	  252, 5   days ago, \
	  253, 2   days ago, \
	  254, 1   days ago, \
	  255

[absorb]
	; https://github.com/tummychow/git-absorb
	maxStack = 100

; [instaweb]
; 	; TODO: There seems to be bugs with both `local` and `python` in
; 	; `git-instaweb`! Look at, fix, and sumbit patches for them.
; 	local = true
; 	httpd = python

[pretty]
	compact   = tformat:%C(BrightYellow)%h%C(auto) %C(BrightWhite)%s%C(auto)%d
	columnars = tformat:%C(BrightYellow)%h%x20%C(BrightMagenta)%>(13,trunc)%ar%x20%C(BrightBlue)%<(15,trunc)%aN%x20%C(BrightWhite)%s%C(auto)%d
	columnart = tformat:%C(BrightYellow)%h%x09%C(BrightMagenta)%>(1       )%ar%x09%C(BrightBlue)%<(1       )%aN%x09%C(BrightWhite)%s%C(auto)%d
	patch     =  format:%C(BrightYellow)commit %h%C(auto)%d%n%C(BrightYellow)Author: %aN <%aE>%n%C(BrightYellow)Date:   %ad%n%n%C(Yellow)%s%n

[alias]
	; All.
	; TODO: `eval` the supplied command (if any), so that one can use pipes
	; and other shell features? That would require one to type `git all git
	; <git-command>` (i.e. repeat `git` twice) for Git commands though.
	; Actually, borrow an idea from git aliases themselves? If the command
	; starts with `!` then strip it and do `eval "$@"`, otherwise do `git
	; "$@"`?
	all = "!f() { : ; \
	  [ -t 1 ] && tty=true; \
	  git config --get-colorbool color.all && color_all=always; \
	  git config --get-colorbool color.ui  && color_ui=always; \
	  find -L . -type d -name '*.git' -prune \
	  | sed 's#^\\./\\|/\\.git$##g' \
	  | LC_ALL=C sort \
	  | awk '{ \
	    for (parent in parents) \
	      if (index($0, parent \"/\") == 1) \
	        next; \
	    parents[$0]; \
	    print; \
	  }' \
	  | { \
	    if [ $# -eq 0 ]; \
	    then \
	      if [ \"$tty\" ]; \
	      then \
	        tree -n --fromfile; \
	      else \
	        cat; \
	      fi; \
	    else \
	      if [ $color_all ]; \
	      then \
	        get_color() { git -C \"$path\" config --get-color \"$@\"; }; \
	        color_reset=$(get_color '' reset); \
	        color_all_header=$(get_color color.all.header \"BrightWhite White\"); \
	      fi; \
	      while read -r path; \
	      do \
	        output=$(git -C \"$path\" -c color.ui=$color_ui \"$@\" 2>&1); \
	        [ \"$output\" ] || continue; \
	        printf '%s# %s%s\\n%s\\n\\n' \
	          \"$color_all_header\" \
	          \"$path\" \
	          \"$color_reset\" \
	          \"$output\"; \
	      done; \
	    fi; \
	  } \
	  | eval \"LESS=${LESS-FRX} $(git var GIT_PAGER)\"; \
	}; f"

	; Tree.
	; This could have been basically `git ls-files | tree --fromfile` but
	; `--fromfile` doesn't look at the filesystem at all and misses
	; permission bits for coloring. Instead, we use `tree`'s `-P` and `-I`
	; even though they can only match on file basenames, so this solution
	; is quite brittle. Also, `git ls-files` quotes "unusual" charactes,
	; even with `git -c core.quotePath=false`. The only way around that is
	; to pass `-z` but of course that uses null separators, which shell
	; command substitution doesn't handle. So to convert the nulls to
	; newlines we have to thread the return code out through extra file
	; descriptors as a string.. Unix is elegant, right? Yes, I know about
	; `-o pipefail`, that POSIX is too new for me :) It mostly works.
	; Actually, fuck it, it turns out `tree`'s `-P` and `-I` are not
	; anchored, even though they support `*` but no anchoring mechanism, so
	; we get even more false positives than expected, so we do without the
	; absolutely correct coloring for now.
	tree = "!f() { : git ls-files ; \
	  git config --get-colorbool color.tree && color_tree=always; \
	  files=\"$( \
	    ((( \
	      (git ls-files -z \"$@\"; echo $? >&3) | sed 's/\\x00/\\n/g' >&4 \
	    ) 3>&1) | exit $(cat)) 4>&1 \
	  )\" || return; \
	  printf '%s\\n' \"$files\" \
	  | tree -a -n ${color_tree+-C} --fromfile; \
	  return; \
	  dirs=\"$( \
	    printf '%s\\n' \"$files\" \
	    | sed -n 's#\\([^/]\\+\\)/.*#\\1#p' \
	    | sort -u \
	    | paste -sd '|' \
	  )\"; \
	  pattern=\"$( \
	    printf '%s\\n' \"$files\" \
	    | sed 's#/#\\n#g' \
	    | sort -u \
	    | paste -sd '|' \
	  )\"; \
	  ignore=\"$( \
	    find . \\! -name '.' -type d -prune \
	    | sed 's#^./##' \
	    | grep -Ev \"$dirs\" \
	    | paste -sd '|' \
	  )\"; \
	  tree -a -n ${color_tree+-C} \
	    --matchdirs \
	    --prune \
	    -P \"$pattern\" \
	    -I \"$ignore\"; \
	}; f"

	; Clone user repo
	; `git clone-user-repo */$user/$repo` =>
	; `git clone           */$user/$repo $user/repo`
	clone-user-repo ="!f() { : git clone ; \
	  url() { shift $(($#-1)); echo \"$1\"; }; \
	  url=\"$(url \"$@\")\"; \
	  url=\"${url%/}\"; \
	  repo=\"${url##*/}\"; \
	  user=\"${url%/*}\"; \
	  user=\"${user##*/}\"; \
	  git clone \"$@\" \"$user/$repo\"; \
	}; f"

	; Users.
	users = "!f() { : git log ; \
	  git log --pretty=full \"$@\" \
	  | sed -n 's/^\\(Author\\|Commit\\): \\(.*\\)/\\2/p' \
	  | LC_ALL=C sort -u; \
	}; f"

	; Browse.
	browse ="!f() { : ; \
	  [ $# != 0 ] || set -- $(git remote); \
	  for remote in \"$@\"; \
	  do \
	    url=\"$(git remote get-url \"$remote\")\"; \
	    printf '%s: %s\\n' \"$remote\" \"$url\"; \
	    { [ $(command -v xdg-open) ] && xdg-open \"$url\"; } || \
	    { [ $(command -v open)     ] && open     \"$url\"; } || \
	    { [ $(command -v start)    ] && start    \"$url\"; } || \
	    true; \
	  done; \
	}; f"

	; Refdiff.
	refdiff = "!f() { : git diff ; \
	  git config --get-colorbool color.diff && color_diff=always; \
	  git reflog --pretty='format:%h: %gs' \
	  | awk -F': ' '$2~/(commit|rebase).*\\((amend|finish)\\)/{print $1}' \
	  | while read -r ref; \
	  do \
	    git -c color.diff=$color_diff show --no-patch $ref; \
	    echo; \
	    git -c color.diff=$color_diff diff \"$@\" $ref HEAD; \
	    echo; \
	  done \
	  | eval \"LESS=${LESS-FRX} $(git var GIT_PAGER)\"; \
	}; f"

	; Reset user.
	reset-user = "!f() { : git filter-branch ; \
	  name=\"$1\";  shift; \
	  email=\"$1\"; shift; \
	  git filter-branch --env-filter \" \
	    GIT_AUTHOR_NAME=\\\"$name\\\"; \
	    GIT_AUTHOR_EMAIL=\\\"$email\\\"; \
	    GIT_COMMITTER_NAME=\\\"$name\\\"; \
	    GIT_COMMITTER_EMAIL=\\\"$email\\\"; \
	    GIT_COMMITTER_DATE=\\\"\\$GIT_AUTHOR_DATE\\\"; \
	  \" \"$@\" ; \
	}; f"

	; Reset date.
	reset-date = "!f() { : git filter-branch ; \
	  git filter-branch --env-filter ' \
	    sleep 1; \
	    date=\"$(date --iso-8601=s)\"; \
	    GIT_AUTHOR_DATE=\"$date\"; \
	    GIT_COMMITTER_DATE=\"$date\"; \
	  ' \"$@\" ; \
	}; f"

	; Log.
	; TODO: Add `--no-merges` and `--merges` (or `--first-parent`) aliases?
	; They fit well with the workflow of my personal projects.
	; TODO: If would be cool to add like a `=> ${u}` to the decoration to
	; also show the tracking branch if any.
	; TODO: Add `--shortstat` info?
	; <https://til.codeinthehole.com/posts/how-to-add-commit-sizes-to-git-log-output/>
	; TODO: Can we do nicer (Unicode) graphs?
	; - <https://github.com/rbong/vim-flog/issues/49>
	l = "!f() { : git log ; \
	  git config --get-colorbool color.diff && color_diff=always; \
	  git -c color.diff=$color_diff log --graph --pretty=columnart \"$@\" \
	  | sed -E 's/^([^\\t]+\\t[^\\t,]+)(,.+)? ago(.*\\t.*)$/\\1\\3/' \
	  | sed -E 's/^(.*) +(.*[0-9a-f]{7}.*\\t)/\\1\\t\\2/' \
	  | sed -E 's/ *$//' \
	  | column -t -o ' ' -s \"$(printf '\\t')\" \
	  | eval \"LESS=${LESS-FRX} $(git var GIT_PAGER)\"; \
	}; f"
	lb = log --topo-order --graph --pretty=compact --simplify-by-decoration ; `git-show-tree` from `git-extras` is similar.
	ls = log --topo-order --graph --pretty=compact
	ll = log --topo-order --graph --pretty=columnars
	lp = log --topo-order --patch --pretty=patch --find-copies-harder --irreversible-delete
	lpw  = lp --color-words='[_[:alnum:]]+|[^[:space:]]'
	lpww = lp --color-words='.'
	la    = l    --all
	lba   = lb   --all
	lsa   = ls   --all
	lla   = ll   --all
	lpa   = lp   --all
	lpwa  = lpw  --all
	lpwwa = lpww --all

	; Status.
	s  = status
	ss = status --short
	sb = status --short --branch
	sa  = s  --ignored
	ssa = ss --ignored
	sba = sb --ignored

	; Diff.
	d  = diff --find-copies-harder --irreversible-delete
	du = diff --find-copies-harder --irreversible-delete @{upstream}
	dp = diff --find-copies-harder --irreversible-delete @{push}
	dc  = d  --cached
	duc = du --cached
	dpc = dp --cached
	dw   = d   --color-words='[_[:alnum:]]+|[^[:space:]]'
	duw  = du  --color-words='[_[:alnum:]]+|[^[:space:]]'
	dpw  = dp  --color-words='[_[:alnum:]]+|[^[:space:]]'
	dcw  = dc  --color-words='[_[:alnum:]]+|[^[:space:]]'
	ducw = duc --color-words='[_[:alnum:]]+|[^[:space:]]'
	dpcw = dpc --color-words='[_[:alnum:]]+|[^[:space:]]'
	dww   = d   --color-words='.'
	duww  = du  --color-words='.'
	dpww  = dp  --color-words='.'
	dcww  = dc  --color-words='.'
	ducww = duc --color-words='.'
	dpcww = dpc --color-words='.'

	; Add.
	au = add -u
	aa = add -A

	; Commit.
	c  = commit
	ca = commit --amend

	; Rebase.
	ri = rebase -i --rebase-merges
	ro = rebase -i --rebase-merges --root
	rr = rebase --continue

	; Fetch.
	f = fetch

	; Push.
	p  = push
	pf = push --force-with-lease

	; Clean ignored files (requires either `-f`, `-i` or `-n`).
	x = clean -Xd

	; Contains.
	; contains = name-rev --name-only
	contains = tag --contains
	; contains = branch --contains
	; contains = describe --contains