Featured image of post A way to manage my git profiles

A way to manage my git profiles

Like a good Linux user, I keep my dotfiles on git repositories.

When I set up a new machine, I do

1
2
3
4
5
# (register ssh key on GitLab first)

git clone --recurse-submodules git@git.junyi.me:dot/linux_config.git
cd linux_config
make user

which includes my dotfiles for most things, which are common across all my machines, whether for work or personal use.

However, some things cannot be kept on public repos, and cannot be the same across all machines, such as git configs.

Git config structure

Previously I used to keep a single git config file in the linux_config repo, which contained my personal account info. Whenever I set up a new machine for work, I had to manually change the git config to use my work email and name.

Recently I learned there was a built-in way to manage multiple git profiles using the include and includeIf directives in git config.

So now my main git config looks like this:

config
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[diff]
    tool = vimdiff
[push]
    autoSetupRemote = true

[pull]
    rebase = true

[alias]
    b = branch
    c = commit -m
    ca = commit --amend -m
    ce = commit --allow-empty -m
    o = checkout
    acm = !git aa && git cm
    m = merge
    p = pull
    pr = pull --recurse-submodules
    pu = push
    s = status -s
    h = stash
    hp = stash pop
    hl = stash list
    sm = submodule
    smp = submodule update --remote --init --recursive
    a = "!f() { git ls-files -m -o --exclude-standard | fzf -m --preview 'git diff --color=always {} 2>/dev/null || cat {}' | xargs -r git add && git status -s; }; f"
    u = "!f() { git diff --cached --name-only | fzf -m --preview 'git diff --cached --color=always {}' | xargs -r git reset && git status -s; }; f"
    aa = !git add . && git status -s
    l = log --oneline --graph --all --decorate
    ll = log --graph --all --decorate
    d = diff

[include]
    path = ~/.config/git/profile.ini

Note that it’s including another file ~/.config/git/profile.ini. This file contains the actual profile info, and is on another private repo.

profile.ini
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[user]
    email = junyi.wang@company.com
    name = junyi.wang

[url "git@git.dtc.dish.corp:"]
    insteadOf = https://git.dtc.dish.corp/

# dedicated directory `~/git/` for my personal projects
[includeif "gitdir:~/git/"]
    path = home.ini
note

Apparently the gitconfig file syntax is not exactly .ini, but I chose to use .ini extension for decent enough syntax highlighting.

The profile.ini file contains my work profile by default, and includes another file home.ini for my personal profile, which is only applied when I’m in the ~/git/ directory.

home.ini
1
2
3
4
5
6
[user]
    email = junyi.wang.007@gmail.com
    name = junyi.wang

[url "git@git.junyi.me:"]
    insteadOf = https://git.junyi.me/

This way, git will automatically use the correct profile based on which directory I’m in.

Directory structure

The linux_config repo contains a Makefile which sets up the dotfiles and git config.

1
2
3
4
user:
    mkdir -p ~/.config/git/
    # ...
    stow -t ~/ home

The gitconfig file is at home/.config/git/config, which is symlinked to ~/.config/git/config by stow.

On the private repo side, the Makefile looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
GIT_DIR = ~/.config/git

.PHONY: work
.PHONY: home

dirs:
    mkdir -p $(SECRET_DIR)

work:
    make dirs
    stow -t ~ work

home:
    make dirs
    stow -t ~ home

Directory structure is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
.
├── Makefile
├── home
│   ├── .config
│   │   └── git
│   │       └── profile.ini
├── work
│   ├── .config
│   │   └── git
│   │       ├── home.ini -> ../../../home/.config/git/profile.ini
│   │       └── profile.ini

By symlinking home.ini from the home directory, the make work target automatically sets up gitconfig to reference the correct personal profile.

Built with Hugo
Theme Stack designed by Jimmy