Is it possible to write git alias functions with single quotes?

66 views Asked by At

I'm trying to write a git alias function with single quotes to rename and commit files that may have spaces in their names, but it does not work :

$ grep '^\s*mvv' ~/.gitconfig 
    mvv = '!f() { cd ${GIT_PREFIX:-.};git mv -v "$1" "$2";git commit -uno "$1" "$2" -m "Renamed $1 to $2"; }; f'
$ git mvv "9.1.3 Packet Tracer - Identify MAC and IP Addresses - ILM.pdf" 9.1.3_Packet_Tracer_-_Identify_MAC_and_IP_Addresses_-_ILM.pdf
fatal: bad alias.mvv string: unclosed quote
$ git config alias.mvv
'!f() { cd ${GIT_PREFIX:-.}

I also tried this :

$ grep '^\s*mvv' ~/.gitconfig 
    mvv = !sh -c '{ cd ${GIT_PREFIX:-.};git mv -v "$1" "$2";git commit -uno "$1" "$2" -m "Renamed $1 to $2"; }'
$ git mvv "9.1.3 Packet Tracer - Identify MAC and IP Addresses - ILM.pdf" 9.1.3_Packet_Tracer_-_Identify_MAC_and_IP_Addresses_-_ILM.pdf
sh -c '{ cd ${GIT_PREFIX:-.}: 1: Syntax error: Unterminated quoted string
$ git config alias.mvv
!sh -c '{ cd ${GIT_PREFIX:-.}
$

But when I run it, is says fatal: bad alias.mvv string: unclosed quote error.

I expect it to work.

3

There are 3 answers

0
phd On BEST ANSWER

The short answer seems to be "no, use double quotes". To avoid escaping internal quotes manually one can ask Git to do escaping:

git config alias.mvv '!f() { cd ${GIT_PREFIX:-.};git mv -v "$1" "$2";git commit -uno "$1" "$2" -m "Renamed $1 to $2"; }; f'

then see .git/config — Git escapes double quotes in the alias:

$ cat .git/config 
[alias]
        mvv = "!f() { cd ${GIT_PREFIX:-.};git mv -v \"$1\" \"$2\";git commit -uno \"$1\" \"$2\" -m \"Renamed $1 to $2\"; }; f"

PS. Only works in Unix/Linux or Linux-like environments (read git-bash); AFAIK Windows command interpreters don't like apostrophes (single quotes) in command line. Somebody with better knowledge please correct me if I'm wrong.

0
jthill On

git help config's rules in the syntax section for quoting in string-valued configs:

A line that defines a value can be continued to the next line by ending it with a \; the backslash and the end-of-line are stripped. Leading whitespaces after name =, the remainder of the line after the first comment character # or ;, and trailing whitespaces of the line are discarded unless they are enclosed in double quotes. Internal whitespaces within the value are retained verbatim.

Inside double quotes, double quote " and backslash \ characters must be escaped: use \" for " and \\ for \.

The following escape sequences (beside \" and \\) are recognized: \n for newline character (NL), \t for horizontal tabulation (HT, TAB) and \b for backspace (BS). Other char escape sequences (including octal escape sequences) are invalid.

There's nothing in there about singlequoting.

So:

mvv = '!f() { cd ${GIT_PREFIX:-.};git mv -v "$1" "$2";git commit -uno "$1" "$2" -m "Renamed $1 to $2"; }; f'

is just wrong.

mvv = "!f() { cd \"${GIT_PREFIX:-.}\"; git mv -v \"$1\" \"$2\"; git commit -uno \"$1\" \"$2\" -m \"Renamed $1 to $2\"; }"

is what you want. You don't want singlequotes in the value there, that'd stop the shell seeing the shell substitution syntax you've embedded, but you could certainly use them where you want that effect.

0
LeGEC On

When you start jumping through hoops to escape spaces and quotes (or if you struggle to write your script as a one liner ...):
creating a script named git-mvv and making it available from your PATH makes git mvv work like a regular git command:

# content of git-mvv
#!/bin/bash

set -e

cd ${GIT_PREFIX:-.}
git mv -v "$1" "$2"
git commit -uno "$1" "$2" -m "Renamed $1 to $2"

make that one executable and place it somewhere on your PATH (e.g: do you have $HOME/bin in your PATH ?)

now git mvv foo bar will work