Reputation: 3689
I want to create a sh
script that configures all my git aliases. Some of the aliases have pipes (|
) and doublequotes ("
). The output I want to see in my ~/.gitconfig
file is:
[alias]
assume = update-index --assume-unchanged
unassume = update-index --no-assume-unchanged
assumed = "!git ls-files -v | grep ^h | cut -c 3-"
However, running the following three commands yields an incorrect assumed
entry:
# setup git aliases per: http://blog.apiaxle.com/post/handy-git-tips-to-stop-you-getting-fired/
git config --global alias.assume "update-index --assume-unchanged"
git config --global alias.unassume "update-index --no-assume-unchanged"
git config --global alias.assumed '"!git ls-files -v | grep ^h | cut -c 3-"'
The third alias (assumed
) has undesired backslashes:
assumed = \"!git ls-files -v | grep ^h | cut -c 3-\"
What is the correct syntax to configure the alias via command line?
Upvotes: 10
Views: 3597
Reputation: 3096
Escaping can be strange when you introduce subshells (using "!..."
) as alias values inside the git config aliases. The problem is compounded when you want to write safe shell scripts that should quote things. The problem is compounded more when you want lazy/delayed execution of commands (which
involves representing evaluating/expanding strings to strings, then interpreting those strings e.g. eval
, subshell, or otherwise). Here is an example, albeit slightly contrived, just to demonstrate that it is not straightforward.
\\"
will not work, because the first backslash acts as an escape character for the second backslash. This leaves a remaining "
which actually is bad syntax because it closes the whole alias in INI format (it is the same as just trying to write "
.\\\"
to achieve a single "
literal in the subshell.\\>
to achieve a ">
" character, but only when surrounded by literal quotes in the subshell, otherwise >
works. (> is a special char to the shell interpreter: the redirect operator, so depending on context e.g. eval echo "\>"
, echo \>
, and eval echo \\\>
vs. a syntax error: eval echo \>
)\"$cmd\"
, whereby the quotation marks will be passed to the shell by git, then the shell will swallow them as part of the normal "lexical word splitting"..config/git
[alias]
escaping-characters-example = "!effect() { \
local timestamp=$(date +'%Y-%m-%dT%H-%M-%S'); \
local branch=${1-feat/NOISSUE/${timestamp}}; \
local path=${2-${timestamp}}; \
local base=${3-origin/main}; \
local cmd='git worktree add -b \"${branch}\" \"${path}\" \"${base}\"'; \
echo \\\"Fully surround me quotes ==\\> $cmd\\\"; \
echo \"After arrow quoted ==> \\\"$cmd\\\"\"; \
echo \"Suitable for lazy eval ==> $cmd\"; \
printf \"Print unexpanded cmd to pass to eval: \" && echo $cmd; \
printf \"Eval (expanded value; eval already applied split words lexically; quotes have been swallowed) ==> \" && eval echo $cmd; \
}; effect"
Usage
$ git escaping-characters-example
"Fully surround me quotes ==> git worktree add -b "${branch}" "${path}" "${base}""
After arrow quoted ==> "git worktree add -b "${branch}" "${path}" "${base}""
Suitable for lazy eval ==> git worktree add -b "${branch}" "${path}" "${base}"
Print unexpanded cmd to pass to eval: git worktree add -b "${branch}" "${path}" "${base}"
Eval (expanded value; eval already applied split words lexically; quotes have been swallowed) ==> git worktree add -b feat/NOISSUE/2024-04-03T09-30-22 2024-04-03T09-30-22 origin/main
All this could be in the Git docs as a usage example or something. Because everybody uses whatever shell they want (and shells are also configurable), it gets complicated really fast. I am not a contributor there and I was just having fun.
Upvotes: 0
Reputation: 14354
You don't need double quotes in .gitconfig.
So the command is:
git config --global alias.assumed '!git ls-files -v | grep ^h | cut -c 3-'
Upvotes: 12