How do I specify a Git merge driver path in .git/config with spaces?

Viewed 1057

I want to specify that the custom merge driver that I'm using is in the root directory of my repository, named mergebans.py. I've tried the following for paths...

  • ./mergebans
  • ../mergebans
  • ./mergebans.py
  • ../mergebans.py
  • /home/steam/.config/SCP Secret Laboratory
  • /home/steam/.config/SCP\ Secret\ Laboratory

Spaces in Git driver causing

$ git merge master
../mergebans.py .merge_file_h3Bq8r .merge_file_2sLmCK .merge_file_H38i62 7: 1: ../mergebans.py .merge_file_h3Bq8r .merge_file_2sLmCK .merge_file_H38i62 7: ../mergebans.py: not found
../mergebans.py .merge_file_knuMAl .merge_file_Pg9f5D .merge_file_Gb0JzW 7: 1: ../mergebans.py .merge_file_knuMAl .merge_file_Pg9f5D .merge_file_Gb0JzW 7: ../mergebans.py: not found

$ git merge master
../mergebans.py .merge_file_TBZ2ia .merge_file_dHaTFA .merge_file_7wEJ20 7: 1: ../mergebans.py .merge_file_TBZ2ia .merge_file_dHaTFA .merge_file_7wEJ20 7: ../mergebans.py: not found
../mergebans.py .merge_file_pzgQqr .merge_file_rvHXOR .merge_file_TYk5ci 7: 1: ../mergebans.py .merge_file_pzgQqr .merge_file_rvHXOR .merge_file_TYk5ci 7: ../mergebans.py: not found

$ git merge master
/home/steam/.config/SCP Secret Laboratory/mergebans .merge_file_sDGMpM .merge_file_GiChes .merge_file_2JJM27 7: 1: /home/steam/.config/SCP Secret Laboratory/mergebans .merge_file_sDGMpM .merge_file_GiChes .merge_file_2JJM27 7: /home/steam/.config/SCP: not found
/home/steam/.config/SCP Secret Laboratory/mergebans .merge_file_OacBRN .merge_file_4qUpGt .merge_file_ElPev9 7: 1: /home/steam/.config/SCP Secret Laboratory/mergebans .merge_file_OacBRN .merge_file_4qUpGt .merge_file_ElPev9 7: /home/steam/.config/SCP: not found

$ git merge master
fatal: bad config line 21 in file .git/config

How do I fix my .git/config to locate the mergebans.py file properly?

1 Answers

The string you define on the driver line—whatever its text is—is passed to your shell, whatever that is (if Unix-ish system, probably sh or bash) and it is up to your shell to handle the string. So the first trick is getting the string itself set.

Here, just putting in the spaces works OK:

[merge "netbeans"]
    driver = this has spaces

We can test this with git config --get:

$ git config --get merge.netbeans.driver
this has spaces
$ git config --get merge.netbeans.driver | hexdump -C
00000000  74 68 69 73 20 68 61 73  20 73 70 61 63 65 73 0a  |this has spaces.|
00000010

A shell, however, will treat this as three "words"; we want the three words to be a single word in shell terms. Here backslashes would work, but git config parsing eats one level of backslashes, so we need to double the backslashes:

[merge "netbeans"]
    driver = this\\ has\\ spaces

which gives:

$ git config --get merge.netbeans.driver
this\ has\ spaces

(I'll leave hexdump or other character viewing to the reader this time).

Alternatively, we can put the whole string in double quotes or single quotes. Experimentation with git config --get shows that git config does not itself eat single quotes:

[merge "netbeans"]
    driver = 'this has spaces'

$ git config --get merge.netbeans.driver
'this has spaces'

but it does eat double quotes:

[merge "netbeans"]
    driver = "this has spaces"
$ git config --get merge.netbeans.driver
this has spaces

The solution for the latter is to quote the double quotes, e.g., using backslash:

[merge "netbeans"]
    driver = \"this has spaces\"
$ git config --get merge.netbeans.driver
"this has spaces"

(which shows why we had to double the backslashes earlier).

Which, if any, of these is suitable for your shell depends on your shell. I tend to prefer the double quotes in most cases, but here the single quotes are easiest to write, and would work for my shell, so I would use:

    driver = '/home/steam/...'

(except that I would avoid putting spaces in my path names in the first place, so as not to have to do any of this...).

Finally, though you probably do want to do it for this particular case, it's rarely very good to hard-code full path names like this when the shell searches $PATH for you. If there is a program X that other programs P and Q should have access to, X should be on $PATH when P and Q run. For instance, Git's own internal plumbing programs live in git --exec-path, so when you run git command, the git front end inserts its own --exec-path path at the front of $PATH, then just runs git-command which locates the first executable named git-command in $PATH. This means you can write your own Git programs—including plumbing ones like merge strategies or merge drivers—and then Git plus the shell can find them for you. For instance, if you write a git-frob command, place it somewhere in your $PATH, and then run git frob, you will find that Git runs your own git-frob command (with $PATH augmented to point to the git-core code so that git-frob can source git-sh-setup easily).

Related