Posted on 2 minutes read

Git can change configuration depending on the directory you're in. By using this feature, you can create a directory structure with context-aware Git configurations.

Using includeIf in ~/.gitconfig:

[include]
    path = "~/.config/git/main.gitconfig"
[includeIf "gitdir:~/work/companyA/**"]
    path = "~/.config/git/companyA.gitconfig"
[includeIf "gitdir:~/work/companyB/**"]
    path = "~/.config/git/companyB.gitconfig"

Here we everything under ~/work/companyA/ will get the git configuration from ~/.config/git/companyA.gitconfig, and similarly for companyB.

Identity

Now we can set our special configuration in its own file for companyA:

[user]
  name = Hugues
  email = h@companyA.com
  signingkey = ~/.ssh/keys/compA

[commit]
   gpgsign = true

[gpg]
   format = ssh

[gpg "ssh"]
  allowedSignersFile = ~/.ssh/git_allowed_signers


# git clone compA:repo
[url "ssh://git@compA.com/"]
        insteadOf = compA:
        pushInsteadOf = compA:

This allows us to easily have separate identities depending on the directory you're in. We also get commits signed with the SSH key that we use to access the repository. Finally, we make an alias for the company URL, making it simpler to clone new repos or to modify the URL everywhere if the repository ever changes URL.

Global preferences

We usually want to retain certain configurations and aliases no matter the directory.

[core]
        excludesfile = "~/.config/git/main.gitignore"

[commit]
        template = "~/.config/git/main.commit.template"

[init]
        defaultBranch = main

[pull]
        ff = true
        commit = true

[push]
        default = simple

[merge]
        ff = false
        commit = no

[color]
        diff = auto
        status = auto
        branch = auto

[color "status"]
        added = green
        changed = red
        untracked = yellow
        branch = magenta

[alias]
        ci = commit
        co = checkout
        sw = switch
        st = status -sb
        br = branch -vv
        cl = clone --recursive
        push-force = push --force-with-lease
        publish = "!git push -u origin `git symbolic-ref HEAD | sed -e 's#^refs/heads/##'`"
        serve = !git daemon --base-path=. --export-all --enable=receive-pack --reuseaddr --informative-errors --verbose
        env = !env

Here we set up a global gitignore. In it, there are IDE configuration paths and a line local-untracked, which allows having a local scratchpad in every git project that won't end up in source revision.

We choose the main default branch name, and there are preferred default behaviors for push, pull, and merge.

Commit template

It will appear every time you use the git commit command. It is a good place to remind you what you should write and it can be overridden for a specific company if they have a different policy.

Here we use good practices from the internet:


# Title No more than 50 chars. ##### stop here: #
# Title: Summary, imperative, start upper case, don't end with a period
# Remember blank line between title and body.

# Body: Explain *what* and *why* (not *how*). Include issue ID.
# Wrap at 72 chars. ################################## which is here: #


# At the end: Include Co-authored-by for all contributors.
# Include at least one empty line before it. Format:
# Co-authored-by: name <user@users.noreply.com>
#
# Template inspired by:
# How to Write a Git Commit Message:
# https://chris.beams.io/posts/git-commit/

Happy versionning!