41

Via Github I use the same set of "dot files" on several different computers and servers. On the Macs and Linux boxes under my direct control I have Sublime Text 2 installed and set up as my git merge and commit editor of choice. However, on remote (i.e., not under my direct control) servers I would select to use vim.

I would rather not create and maintain a second .gitconfig for those remote servers. Is there a way to do something like this:

[core]
    if [[ $IS_REMOTE -eq 1 ]]; then
        editor = "vim"
    else
        editor = "subl -n -w"
    fi

where I've somehow set $IS_REMOTE based on the hostname?

Mark Nichols
  • 1,407
  • 2
  • 19
  • 25
  • Why not just use a script file as "editor" value in which you check that? (Because no, git config is not conditional) – Nevik Rehnel Feb 07 '13 at 15:35
  • Conditional include gitconfig starts to be possible with Git 2.13. See [my answer](http://stackoverflow.com/a/43621480/6309) – VonC Apr 25 '17 at 21:49

7 Answers7

25

You can conditionally include another Git config file based on your Git directory or branch in Git 2.13 and later.

Put your default configuration in file ~/.gitconfig as usual. At the end, conditionally include another configuration file:

[user]
    email = john@personal.com
    name = John McGehee

# All work Git repositories are in a subdirectory of ~/work.
# All other Git repositories are outside ~/work.
[includeIf "gitdir:~/work/"]
    path = .gitconfig.work

Then, in ~/.gitconfig.work add or override configuration values you want when using a repository located in ~/work or any subdirectory thereof:

[user]
    email = john@work.com

You can observe the difference by changing to a Git directory under ~/work, and running:

git config user.email

Try the same command in a Git directory that is not under ~/work.

John McGehee
  • 9,117
  • 9
  • 42
  • 50
  • 8
    Note that the `[includeIf]` section must come *below* any sections, (e.g. `[user]`), whose values you want to override. (This might be obvious to everyone but me, however, since it tripped me up, I thought I'd share.) – mefryar Sep 13 '21 at 21:57
21

No, Git config does not support checks or conditional statements. But your underlying shell probably does, so you can use something like:

[core]
    editor = "if [[ $IS_REMOTE -eq 1 ]]; then ED='vim'; else ED='subl -n -w'; fi; $ED"


If you need to do something more complicated than that, you could just throw the shell code into a script, of course, like

[core]
    editor = "my_edi_script.sh"

with my_edit_script.sh containing something like:

#!/bin/bash
if [[ $IS_REMOTE -eq 1 ]]; then
    ED="vim"
else
    ED="subl -n -w"
fi

$ED some argument or other

Edit: The my_edit_script.sh would have to be in the $PATH, of course :)

Nevik Rehnel
  • 49,633
  • 6
  • 60
  • 50
  • In addition to the editor setting, the merge tool and diff tool settings will also change for the remote machines. I think the solution in the end is to have two .gitconfig files. – Mark Nichols Feb 08 '13 at 04:40
  • Tried both of your methods, but they didn't work for the credential.helper setting. I got errors like: "git: 'credential-my_credential_script.sh' is not a git command." – metakermit Jul 31 '14 at 10:56
  • ```[alias]NEWLINEHEREb = "!if [ -z $1 ]; then git branch -av; else git branch $1 $2 $3 $4; fi"``` is there some way to make this work without the syntax error showing up? – Unknow0059 Jan 11 '21 at 04:53
  • I tried your solution, the first one works, the second one ('my_edit_script.sh') failed, with messages like: `command not found: ED` – ChrisZZ Oct 15 '21 at 03:42
  • @ChrisZZ in the script, the last line should be `$ED`, which means invoke the command – Honghao Z Feb 20 '22 at 09:24
  • correction: the last line should be `$ED "$@" # invoke the editor` – Honghao Z Feb 20 '22 at 09:39
14

The [include] section learned by git-config in v1.7.9 gets you most of the way there.

While it doesn't let you write runtime conditionals, it does give you a framework for refactoring your ~/.gitconfig into several parts: the shared section, and the env-specific sections. After that, you can symlink something like ~/.gitconfig.local to the relevant env-specific config file, and include ~/.gitconfig.local from ~/.gitconfig.

The symlinking part can be scripted and done automatically as part of your dotfiles' init script.

From the command line, that include path can be added via:

git config --global include.path '~/.gitconfig.local'

I use the quotes above specifically to prevent the shell from expanding ~ to an absolute path.

That adds the following section to your ~/.gitconfig:

[include]
    path = ~/.gitconfig.local

Here's a snippet from the git-scm book showing the general format:

[include]
    path = /path/to/foo.inc ; include by absolute path
    path = foo ; expand "foo" relative to the current file
    path = ~/foo ; expand "foo" in your $HOME directory
Anton Backer
  • 335
  • 3
  • 8
2

I don't think you can do this, but instead of maintaining your .gitconfig file, how about maintaining a script that generates your .gitconfig file? That way you can do whatever you want, based not only on variables but also on the output of commands and whatever...

like:

#!/bin/sh
if [ "$#" -eq 0 ]
then
    IS_REMOTE=
else
    case "$1" in
        remote)
            IS_REMOTE=1
            ;;
        local)
            IS_REMOTE=
            ;;
        *)
            echo "value $1 not supported" >&2
            ;;
    esac
fi

# config for both remote and local
git config --global color.ui true
git config --global alias.top '!pwd -L'

# config for remote
if [ "$IS_REMOTE" ]
then
    git config --global core.editor vim
    ...
else
    git config --global core.editor 'subl -n -w'
    ...
fi

So, if you call the script without parameters, or with the 'local' parameter, it will generate some configuration to your .gitconfig file, while if you pass the 'remote' parameter to it, it will generate some others.

Carlos Campderrós
  • 22,354
  • 11
  • 51
  • 57
  • While I am attracted to the idea of using a scrip to generate the .gitconfig file, for as often as I'd have to make updates to two .gitconfig variations, I think it's more work that I am willing to put forth. – Mark Nichols Feb 08 '13 at 04:39
  • This would work technically, but it's not the right approach. The answers above are much simpler and neater. – sferencik Jul 05 '18 at 09:05
2

Since Git v2.31 you could also set environment variables in your .bashrc or whatever, e.g. on WSL2 I use the following to configure git to used the cached git https credentials from Windows:

export GIT_CONFIG_COUNT=2 \
GIT_CONFIG_KEY_0="credential.helper" GIT_CONFIG_VALUE_0="/mnt/c/Program\ Files/Git/mingw64/libexec/git-core/git-credential-manager-core.exe" \
GIT_CONFIG_KEY_1="credential.https://dev.azure.com.usehttppath" GIT_CONFIG_VALUE_1="true"

Credit to VonC for pointing this out https://stackoverflow.com/a/65963666/9189668

1

Since it isn't possible to test an environment variable and programmatically alter the .gitconfig, and since scripting the creation of two .gitconfig files feels like more work than I really want to put forth, I'm just going to create two .gitconfig files. On those machines where I can setup Sublime Text 2 as my editor, and have control over the merge tool and diff tool, I'll use the "primary" gitconfig as the target of my symbolic link. On those machines where I don't have ST2 as an option, I'll use the "secondary" gitconfig file.

Mark Nichols
  • 1,407
  • 2
  • 19
  • 25
  • You can split out common config in a 3rd file, and include it in the others: http://stackoverflow.com/questions/4030540/can-i-load-one-gitconfig-file-from-another – chtenb Apr 18 '16 at 07:17
  • 2
    This shouldn't be marked as the best answer. It just shows your preference, which is influenced by your giving up on the actual objective. If someone still wants to do this, the best answer is one of the above. – sferencik Jul 05 '18 at 09:09
1

not exactly an answer to your question but interesting for related usecases: since git 1.8.5 you are allowed to use urlmatch syntax

see http://git-scm.com/docs/git-config for details

config entries regarding remotes are the only one that can be defined conditionally like [http "https://localhost" ] sslVerify = false

^ will switch of ssl verification for localhost "remotes" only

childno͡.de
  • 4,679
  • 4
  • 31
  • 57