Git Config Files
An intro to hidden files and configuration files
Most development tools and platforms today support some level of configuration as code - meaning that the state of the tool can be created from some level of code - usually a hidden file or folder in the root of the repository.
You probably noticed the .github folder in the root of this repository. It holds configuration data for GitHub Classroom (classroom), GitHub Actions (workflows) and I even created my own scope called template I used to copy the state of the template repository to this one.
There's also a folder called .git next to .github You can't see it in the explorer on VS Code. but you can see it if you run ls -a in the terminal. .git contains alle the control files to the git repositories, an it's not likely that you will need to mess around with any of these files (of course there are always exceptions - so we will hack at least one of the files in there later).
But this is why VC Code shows you .github but not .git: Hidden files are for you, as a developer - only .git specifically - is not.
Most often configuration files are written in either yaml or json. But git uses it's own format - salled git config files. Git uses the git config files to store tuples; that is pairs of keys and values. much like environment variables in a Linux shell.
Here's an excerpt of the global .gitconfig file on my computer
[core]
editor = nano
[push]
default = current
[alias]
undo-commit = reset --soft HEAD^
addremove = add -A .
circelci = !open https://app.circleci.com/pipelines/github/lakruzz
hub = !gh repo view --web
recommit = commit -C HEAD --amend
co = checkout
tree = log --graph --full-history --all --color --date=short --pretty=format:\"%Cred%x09%h %Creset%ad%Cblue%d %Creset %s %C(bold)(%an)%Creset\"
root = rev-parse --show-toplevel
backward = checkout HEAD^1
forward = !git checkout $(git log --all --ancestry-path ^HEAD --format=format:%H | tail -n 1)
[github]
user = Lakruzz
[ghi]
token = !security find-internet-password -a lakruzz -s github.com -l 'ghi token' -w
[user]
email = lakruzz@inc-inc.dk
name = Lars Kruse
[semver]
prefix = v
initial = 0.0.0
[init]
defaultBranch = master
Some of the settings I put there myself, some of them are added by plug-ins or extensions I've installed. Some of the settings simply changes the default behaviour of git - if I remove them git still works - only differently. I use the git config to tweak git to my personal liking.
You can see your own global git config file by running:
Git Config is an in-line editor and reader
Git has a subcommand called config. It's an in-line editor/reader. The syntax for using it is:
usage: git config [<options>]
Config file location
--global use global config file
--system use system config file
--local use repository config file
--worktree use per-worktree config file
-f, --file <file> use given config file
--blob <blob-id> read config from given blob object
Action
--get get value: name [value-pattern]
--get-all get all values: key [value-pattern]
--get-regexp get values for regexp: name-regex [value-pattern]
--get-urlmatch get value specific for the URL: section[.var] URL
--replace-all replace all matching variables: name value [value-pattern]
--add add a new variable: name value
--unset remove a variable: name [value-pattern]
--unset-all remove all matches: name [value-pattern]
--rename-section rename section: old-name new-name
--remove-section remove a section: name
-l, --list list all
--fixed-value use string equality when comparing values to 'value-pattern'
-e, --edit open an editor
--get-color find the color configured: slot [default]
--get-colorbool find the color setting: slot [stdout-is-tty]
Type
-t, --type <type> value is given this type
--bool value is "true" or "false"
--int value is decimal number
--bool-or-int value is --bool or --int
--bool-or-str value is --bool or string
--path value is a path (file or directory name)
--expiry-date value is an expiry date
Other
-z, --null terminate values with NUL byte
--name-only show variable names only
--includes respect include directives on lookup
--show-origin show origin of config (file, standard input, blob, command line)
--show-scope show scope of config (worktree, local, global, system, command)
--default <value> with --get, use default value when missing entry
Reading values out of gitconfig
You can use the --get switch to git config read out values from everything that git knows from it's config files. Like this:
git config --get user.name
git config actually has three predefined scopes (files) it reads from: --local, --global and --system. When you use the --get switch and don't specify a scope it it read from all scopes and returns the first value match it finds.
You can also use git config to set a value - rather than read it; you simply use the --add switch instead.
If you don't specify a scope it goes to --local if you want it int --global og --system you must say it.
Try this
git root
git config --global --add alias.root "rev-parse --show-toplevel"
git root
...You've just made an alias!
Run the following commands - one at a time
git config --get user.name
git config --get user.email
git config --list
git config --list --show-origin
git config --list --show-scope
git config --local --get user.email
git config --global --get user.email
git config --system --get user.email
git config --local --list
git config --global --list
git config --system --list
You can use a fourth level --file
Run these commands one at a time:
git config --get template.repo
git config --file $(git rev-parse --show-toplevel)/.github/template/gitconfig template.repo
Dive into Command Substitution
git rev-parse --show-toplevel is a command that returns a string - and in the example above we uset the output from the command as a string - which we concatenate with another string to build the qualified path to the config file.
It's supported in bash - and the concept goes by the name Command Substitution
Here's what the man page for bash has to say:
Command substitution allows the output of a command to replace the command name. >There are two forms:
or
Consequently these two commands does the same job:
git config --file $(git rev-parse --show-toplevel)/.github/template/gitconfig template.repo
git config --file `git rev-parse --show-toplevel`/.github/template/gitconfig template.repo
You can even include config files in other files
You can include more files in any of the others using the key include.path. Dig this!
git config --get template.repo
git config --add include.path ../.github/template/gitconfig
git config --get template.repo
git config --list --show-origin
Dublets are allowed - but not supported - what a mess!
You can add the same key more than once - this can easily lead to undesired situation.
Let's add a a misspelled alias and then add the correct one, and then see what happens:
git config --add --global alias.co cheeckout
git co
git config --add --global alias.co checkout
git co
OK! That went well - except that they are both still three - the bad alias wasn't replaced a new one was merely inserted.
Run:
git config --show-scope --get-regexp alias.co
It's like a stack it read everyting and the last value put in the stack counts.
git config --add --global alias.co chestnut
git co
git config --show-scope --get-regexp alias.co
...you see?
These files aren't wildly complicated and often the easiest way to sort issues is simply to open the files in an editor.
Fix it by running:
git config --edit --global
Or let's recreate the faulty situation and fix it using --unset and --unset-all
git config --add --global alias.co cheeckout
git config --add --global alias.co checkout
git config --add --global alias.co chestnut
git config --global --unset alias.co
git config --global --unset-all alias.co
Let's run one last test, to learn the read order of the scopes.
git config --add --file .gitconfig alias.scopetest '!echo file'
git config --add --global alias.scopetest '!echo global'
git config --add --local alias.scopetest '!echo local'
sudo git config --add --system alias.scopetest '!echo system'
git config --add --local include.path ../.gitconfig
git config --show-scope --get-regexp alias.scopetest
That was fun! - let's read and then delete them in the order they are read.
git scopetest
rm .gitconfig
git config --local --unset include.path
git scopetest
git config --local --unset alias.scopetest
git scopetest
git config --global --unset alias.scopetest
git scopetest
sudo git config --system --unset alias.scopetest
git scopetest
ENOUGH - lets use it.
Except! Did you notice the ! ?
Aliases are expected default to contain git commands - so the command git is implicitly prefixed to aliases - unless the value starts with an exclamation mark ! - then its a bash command.
Dig this!
[alias]
root = rev-parse --show-toplevel
scopetest = !echo file
root = !git rev-parse --show-toplevel
Git Config Files
An intro to hidden files and configuration files
.) are hiddenMost development tools and platforms today support some level of configuration as code - meaning that the state of the tool can be created from some level of code - usually a hidden file or folder in the root of the repository.
You probably noticed the
.githubfolder in the root of this repository. It holds configuration data for GitHub Classroom (classroom), GitHub Actions (workflows) and I even created my own scope calledtemplateI used to copy the state of the template repository to this one.There's also a folder called
.gitnext to.githubYou can't see it in the explorer on VS Code. but you can see it if you runls -ain the terminal..gitcontains alle the control files to the git repositories, an it's not likely that you will need to mess around with any of these files (of course there are always exceptions - so we will hack at least one of the files in there later).But this is why VC Code shows you
.githubbut not.git: Hidden files are for you, as a developer - only.gitspecifically - is not.Most often configuration files are written in either
yamlorjson. But git uses it's own format - salled git config files. Git uses the git config files to store tuples; that is pairs of keys and values. much like environment variables in a Linux shell.Here's an excerpt of the global
.gitconfigfile on my computerSome of the settings I put there myself, some of them are added by plug-ins or extensions I've installed. Some of the settings simply changes the default behaviour of git - if I remove them git still works - only differently. I use the git config to tweak git to my personal liking.
You can see your own global git config file by running:
cat ~/.gitconfigGit Config is an in-line editor and reader
Git has a subcommand called
config. It's an in-line editor/reader. The syntax for using it is:usage: git config [<options>]Reading values out of gitconfig
--local,--globaland--systemread from respectively?You can use the
--getswitch togit configread out values from everything that git knows from it's config files. Like this:git configactually has three predefined scopes (files) it reads from:--local,--globaland--system. When you use the--getswitch and don't specify a scope it it read from all scopes and returns the first value match it finds.You can also use
git configto set a value - rather than read it; you simply use the--addswitch instead.If you don't specify a scope it goes to
--localif you want it int--globalog--systemyou must say it.Try this
...You've just made an alias!
Run the following commands - one at a time
You can use a fourth level
--file--filedo?$(git rev-parse --show-toplevel)do?Run these commands one at a time:
Dive into Command Substitution
git rev-parse --show-toplevelis a command that returns a string - and in the example above we uset the output from the command as a string - which we concatenate with another string to build the qualified path to the config file.It's supported in bash - and the concept goes by the name Command Substitution
Here's what the man page for bash has to say:
Consequently these two commands does the same job:
You can even include config files in other files
You can include more files in any of the others using the key
include.path. Dig this!Dublets are allowed - but not supported - what a mess!
--global! Why?You can add the same key more than once - this can easily lead to undesired situation.
Let's add a a misspelled alias and then add the correct one, and then see what happens:
OK! That went well - except that they are both still three - the bad alias wasn't replaced a new one was merely inserted.
Run:
It's like a stack it read everyting and the last value put in the stack counts.
...you see?
These files aren't wildly complicated and often the easiest way to sort issues is simply to open the files in an editor.
Fix it by running:
Or let's recreate the faulty situation and fix it using
--unsetand--unset-allLet's run one last test, to learn the read order of the scopes.
That was fun! - let's read and then delete them in the order they are read.
ENOUGH - lets use it.
Except! Did you notice the
!?Aliases are expected default to contain git commands - so the command
gitis implicitly prefixed to aliases - unless the value starts with an exclamation mark!- then its a bash command.Dig this!