Git installation and configuration¶
Installation¶
For ix distributions, Git should be in the standard repository.
The git-all package provides a complete Git working environment. Install it with:
$ sudo apt install git-all
To install only Git the git package suffices:
$ sudo apt install git
The bash autocompletion makes Git easier to use on the command line. The according package is called bash-completion. Install it with:
$ sudo apt install bash-completion
There are several different ways to install Git on a Mac. Probably the
easiest way to do is to install the Xcode Command Line Tools. For this you
only have to call up git in the terminal for the first time:
$ git --version
git-completion you can install with Homebrew:
Then you have to add the following line to the file ~/.bash_profile:
[[ -r "$(brew --prefix)/etc/profile.d/bash_completion.sh" ]] && . "$(brew --prefix)/etc/profile.d/bash_completion.sh"
Go to https://git-scm.com/download/win and start the download automatically. Further information can be found at https://gitforwindows.org/.
Configuration¶
Save the global configuration in ~/.config/git/¶
Git uses three levels of configuration files, which are applied in this order:
systemapplies to all users on your computer, but it’s unlikely you’ll ever use this.
globalapplies to all repositories of a single user and we will look at this in more detail here.
localapplies to a single repository and is only suitable for a few repository-specific options.
Git searches for a global configuration file in two places: ~/.config/git/config and ~/.gitconfig. The first location is the default location
for configuration files while the second is the legacy option.
Note
On Linux machines, ~/.config can sometimes be a different path set by
the environment variable XDG_CONFIG_HOME. This behaviour is part of the
X Desktop Group (XDG) specification. You
can get the other path with:
$ echo $XDG_CONFIG_HOME
If this does not result in anything, then your system will use
~/.config, otherwise it will use the path shown. For the sake of
simplicity, we will only refer to ~/.config from now on.
See also
Since you can set options at multiple levels, you may want to keep track of
where Git reads a particular value from. With git config --list [1] you can
list all the overridden options and values. You can combine this with
--show-scope [2] to see where Git is getting the value from:
$ git config --list --show-scope
system credential.helper=osxkeychain
global user.name=veit
global user.email=veit@cusy.io
…
You can also use --show-origin [3] to list the names of the configuration
files:
$ git config --list --show-origin
file:/opt/homebrew/etc/gitconfig credential.helper=osxkeychain
file:/Users/veit/.config/git/config user.name=veit
file:/Users/veit/.config/git/config user.email=veit@cusy.io
…
Note
You can find a comprehensive example of a configuration file in my dotfiles repository: .gitconfig.
Migrate from ~/.gitconfig to ~/.config/git/config¶
If you are currently using the old file name ~/.gitconfig, you can move
it to the ~/.config directory in just a few steps:
Make sure that the
~/.configdirectory exists.Move your existing configuration file to its place:
$ mv ~/.gitconfig ~/.config/git/config
Check whether Git can still read the configuration file by asking for your user name:
$ git config --global user.name Veit Schiele
You may then have to move other files, for example
~/.gitattributesand~/.gitignore. You can check whether these files are available with$ git config --global core.excludesFile ~/.gitignore $ git config --global core.attributesFile ~/.gitattributes
You must then move the files and delete the associated configuration entries:
$ mv ~/.gitignore_global ~/.config/git/ignore $ git config --global --unset core.excludesFile $ mv ~/.gitattributes ~/.config/git/attributes $ git config --global --unset core.attributesFile
Read and write configuration entries¶
As we have already seen above, configuration entries can be read with git config, for example:
$ git config --global user.name
Veit Schiele
… and to change it
$ git config --global user.name 'veit'
You can also edit the configuration file directly by calling git config with
the -e|--edit option:
$ git config --global -e
This opens the ~/.config/git/config file in your default editor:
[user]
name = veit
email = veit@cusy.io
Git saves its configuration in INI files.
The default editor for Git is defined in the GIT_EDITOR environment variable
or in Git’s core.editor option or in the VISUAL or EDITOR
environment variable. You can query the values with
$ echo $GIT_EDITOR
$ git config core.editor
$ echo $VISUAL
$ echo $EDITOR
Normally you always want to use the same editor and therefore the EDITOR
environment variable should be set. To do this, you can enter the following in
~/.bash_profile or ~/.zprofile, for example:
export EDITOR='C:\Program Files (x86)\Microsoft VS Code\code.exe --wait'
Note
On macOS, you must first start Visual Studio Code, then open the command palette with ⌘+⇧-p and finally execute the Install ‘code’ command in PATH.
or
export EDITOR='vim'
Basic configuration¶
Git commits have two mandatory fields that refer to employees: the author who
wrote the code change and the committer who submitted the code to the
repository. For most workflows, this is the same person. With the options
user.name and user.email you can configure information for the author and committer.
$ git config --global user.name "NAME"defines the name
NAMEassociated with your commit transactions.$ git config --global user.email "EMAIL-ADDRESS"defines the email address
EMAIL-ADDRESSthat will be linked to your commit transactions.
See also
Tip
Git hosts, such as GitHub or GitLab, link commits to your profile via the email address. If your configured email address does not match your profile, your commits will not be assigned. This makes it difficult for team members to determine that you have written a specific commit. Therefore, check your configured name and your e-mail address.
Alternative configuration file¶
You can use other configuration files for certain working directories, for example to distinguish between private and professional projects. You can use a local configuration in your repository or conditional includes at the end of your global configuration:
[includeIf "gitdir:~/private"]
path = ~/.config/git/config-private
This construct ensures that Git includes additional configurations or overwrites
existing ones when you work in ~/private.
Now create the file ~/.config/git/config-private and define your
alternative configuration there, for example:
[user]
email = kontakt@veit-schiele.de
[core]
sshCommand = ssh -i ~/.ssh/private_id_rsa
See also
Colouring¶
By default, Git uses your terminal’s ability to colour and format different
types of text. Such colouring allows you to analyse the output more quickly.
However, the default colours are suboptimal: for example, git status marks
changed files in red, a colour generally associated with errors; however,
changing files is not an error, but perfectly normal in any Git process. You can
use the color.* options to adjust the colours per command. I have been using
the cheat sheet colours
for a long time:
[color "branch"]
current = yellow reverse
local = yellow
remote = green
[color "status"]
added = yellow
changed = green
untracked = cyan
Note
Later we will look at delta, a tool to better visualise
differences. Its colouring would overwrite information from [colour
‘diff’] and therefore we have not added this section.
Correcting commands¶
If you make a mistake when entering a Git command, similar commands are listed by default and the programme is terminated:
$ git comit -m ':wrench: Update git config'
git: 'comit' is not a git command. See 'git --help'.
The most similar command is
commit
However, you can also configure Git with git config --global help.autoCorrect
immediate [4] so that the first hit is executed automatically:
$ git comit -m ':wrench: Update git config'
WARNING: You called a Git command named 'comit', which does not exist.
Continuing under the assumption that you meant 'commit'.
[main 48cafbf5f] :wrench: Update git config
However, Git only corrects automatically if a command has a sufficiently large match. If there are several potential matches, these are listed and the correction is cancelled:
$ git co -m ':wrench: Update git config'
git: 'co' is not a git command. See 'git --help'.
The most similar commands are
commit
clone
log
If the automatic correction of an command is too much for you, you can use the Prompt mode instead:
$ git config --global help.autoCorrect prompt
$ git comit -m ':wrench: Update git config'
WARNING: You called a Git command named 'comit', which does not exist.
Run 'commit' instead [y/N]? y
[main 48cafbf5f] :wrench: Update git config
Pagination¶
You can activate pagination by default for a command by setting the
corresponding option: pager.CMD = true. [5] For example, to switch
git status to pagination:
$ git config --global pager.status true
Manage login data¶
Since Git version 1.7.9, the access data to git repositories can be managed with gitcredentials. To use this, you can, for example, specify the following:
$ git config --global credential.helper Cache
This will keep your password in the cache for 15 minutes. If necessary, the timeout can be increased, for example with:
$ git config --global credential.helper 'cache --timeout=3600'
With Linux you have to select a so-called: Credential Store.
In most cases, you will opt for the Secret Service API, such as
libsecret from Git, which you can select with:
$ git config --global credential.credentialStore secretservice
With macOS you can use osxkeychain to store the login information.
osxkeychain requires Git version 1.7.10 or newer and can be installed in
the same directory as Git with:
$ git credential-osxkeychain
git: 'credential-osxkeychain' is not a git command. See 'git --help'.
$ curl -s -O http://github-media-downloads.s3.amazonaws.com/osx/git-credential-osxkeychain
$ chmod u+x git-credential-osxkeychain
$ sudo mv git-credential-osxkeychain /usr/bin/
Password:
git config --global credential.helper osxkeychain
This enters the following in the ~/.gitconfig file:
[credential]
helper = osxkeychain
Alternatively, you can also install the Git Credential Manager with
brew install --cask git-credential-manager
For Windows, Git Credential Manager (GCM) is available. It is integrated in Git for Windows and is installed by default. However, there is also a standalone Installer in Releases.
It is configured with
$ git credential-manager configure
Configuring component 'Git Credential Manager'...
Configuring component 'Azure Repos provider'...
This will add the [credential] section to your ~.gitconfig file:
[credential]
helper =
helper = C:/Program\\ Files/Git/mingw64/bin/git-credential-manager.exe
Now, when cloning a repository, a Git Credential Manager window opens and asks you to enter your credentials.
In addition, the ~/.gitconfig file is supplemented, for example by
the following two lines:
[credential "https://ce.cusy.io"]
provider = generic
The .gitignore file¶
In the .gitignore file you can exclude files from version management. A
typical .gitignore file can look like this:
/logs/*
!logs/.gitkeep
/tmp
*.swp
In doing so, Git uses Globbing patterns, among others:
Pattern |
Example |
Description |
|---|---|---|
**/logs
|
|
You can put two asterisks to prefix directories anywhere. |
**/logs/instance.log
|
|
You can put two asterisks to prefix files with their name in a parent directory. |
*.log
|
|
An asterisk is a placeholder for null or more characters. |
/logs
!/logs/.gitkeep
|
|
An exclamation mark in front of a pattern ignores it. If a file matches a pattern, but also a negating one that is defined later, it is not ignored. |
/instance.log
|
|
With a preceding slash, the pattern only matches files in the root directory of the repository. |
instance.log
|
|
Usually the pattern match files in any directory. |
instance?.log
|
|
A question mark fits exactly on a character. |
instance[0-9].log
|
|
Square brackets can be used to find a single character from a specific range. |
instance[01].log
|
|
Square brackets match a single character from a given set. |
instance[!01].log
|
|
An exclamation mark can be used to find any character from a specified set. |
logs
|
|
If no slash appended, the pattern fix both files and the contents of directories witch this name. |
logs/
|
|
Appending a slash indicates that the pattern is a directory. The entire contents of any directory in the repository that matches the name – including all its files and subdirectories – are ignored. |
var/**/instance.log
|
|
Two Asterisks match null or more directories. |
logs/instance*/error.log
|
|
Wildcards can also be used in directory names. |
logs/instance.log
|
|
Pattern, that specify a particular file in a directory are relative to the root of the repository. |
Git-commit empty folder¶
In the example above you can see that with /logs/* no content of the
logs directory should be versioned with Git, but an exception is defined
in the following line: !logs/.gitkeep allows the file .gitkeep to be
managed with Git. The logs directory is then also transferred to the Git
repository. This construction is necessary because empty folders cannot be
managed with Git.
Warning
However, this technique has several disadvantages:
Both
.gitignoreandlog/.gitkeepmust be edited.When renaming the directory, it is easy to forget to change the
.gitignorefile as well..gitkeepis a completely normal file for Git; however, the name suggests that the file would be treated specially by Git.
A better option is to create a .gitignore file with the following
content in an empty directory:
# ignore everything except .gitignore
*
!.gitignore
excludesfile¶
However, you can also exclude files centrally for all Git repositories. For this
purpose, you can set excludesfile in the ~/.config/git/config file:
[core]
# Use custom ignore file
excludesfile = ~/.config/git/ignore
…
Note
You can find helpful templates in my dotfiles repository or on the gitignore.io website.
Ignoring a file from the repository¶
If you want to ignore a file that has already been added to the repository in
the past, you need to delete the file from your repository and then add a
.gitignore rule for it. Using the --cached option on git rm means
that the file will be deleted from the repository but will remain in your
working directory as an ignored file.
$ echo *.log >> .gitignore
$ git rm --cached *.log
rm 'instance.log'
$ git commit -m "Remove log files"
Note
You can omit the --cached option if you want to remove the file from both
the repository and your local file system.
Commit an ignored file¶
It is possible to force the commit of an ignored file to the repository with the
-f (or --force) option on git add:
$ cat data/.gitignore
*
$ git add -f data/iris.csv
$ git commit -m "Force add iris.csv"
You might consider this if you have a general pattern (like *) defined, but
want to commit a specific file. However, a better solution is usually to define
an exception to the general rule:
$ echo '!iris.csv' >> data/.gitignore
$ cat data/.gitignore
*
!iris.csv
$ git add data/iris.csv
$ git commit -m "Add iris.csv"
This approach should be more obvious and less confusing for your team.
Troubleshooting .gitignore files¶
For complicated .gitignore patterns, or patterns that are spread across
multiple .gitignore files, it can be difficult to figure out why a
particular file is being ignored.
With git status --ignored=matching [6], an Ignored Files section is added
to the output, showing all ignored files and directories:
$ git status --ignored=matching
On branch main
Ignored Files:
(use "git add -f <file>...", to pre-mark the changes for committing
.DS_Store
docs/.DS_Store
docs/_build/doctrees/
docs/_build/html/
docs/clean-prep/.ipynb_checkpoints/
…
nothing to commit, working tree clean
You can use the git check-ignore command with the -v (or --verbose)
option to determine which pattern is causing a particular file to be ignored:
$ git check-ignore -v data/iris.csv
data/.gitignore:2:!iris.csv data/iris.csv
The output shows
FILE_CONTAINING_THE_PATTERN:LINE_NUMBER_OF_THE_PATTERN:PATTERN
FILE_NAME
You can pass multiple filenames to git check-ignore if you like, and the
names themselves don’t even have to match the files that exist in your
repository.
You can get a complete list of all ignored files with git ls-files --ignored
--exclude-standard --others [7]. With --exclude-standard the standard
ignored files are read and with --others the non-versioned files are
displayed instead of the versioned ones:
$ git ls-files --ignored --exclude-standard --others
.DS_Store
_build/doctrees/clean-prep/bulwark.doctree
_build/doctrees/clean-prep/dask-pipeline.doctree
_build/doctrees/clean-prep/deduplicate.doctree
…
Occasionally you may want to bypass the global ~/.gitignore file to see
which files Git always ignores, regardless of your configuration. You can do
this by switching to another exclude option, --exclude-per-directory,
which uses only the repository’s .gitignore files:
$ git ls-files --ignored --exclude-per-directory=.gitignore --others
docs/_build/doctrees/clean-prep/bulwark.doctree
docs/_build/doctrees/clean-prep/dask-pipeline.doctree
docs/_build/doctrees/clean-prep/deduplicate.doctree
…
Note that the .DS_Store file is no longer listed as ignored.
If you replace --others with --cached, git ls-files will list files
that would be ignored unless they have already been committed:
$ git ls-files --ignored --exclude-per-directory=.gitignore --cached
data/iris.csv
You may have such files because someone added them to a .gitignore file
before the relevant patterns, or because someone added them with git add
--force. Either way, if you no longer want to manage the file with Git, you
can remove it from Git management with the following one-liner, but don’t
delete it:
$ git ls-files --ignored --exclude-per-directory=.gitignore --cached | xargs -r git rm --cached
rm 'data/iris.csv'