Git config alias escaping

Я пытаюсь написать псевдоним git, который удаляет из сообщений фиксации строку "[ci skip]" (помещается в конце сообщения), но у меня проблема с экранированием. Псевдоним принимает все commit из переданного как аргумент HEAD.

Если я запустил следующую команду:

git filter-branch -f --msg-filter "sed -e \"s/\[ci skip\]$//g\"" master..HEAD

работает так, как ожидалось. В любом случае, если я создаю следующий псевдоним:

unwip = !sh -c 'git filter-branch -f --msg-filter \"sed -e \\\"s/\[ci skip\]$//g\\\"\" $0..HEAD'

и я запускаю git unwip master, он жалуется на плохую конфигурацию, но я ожидаю, что он будет вести себя как предыдущие комбаты. Как я могу это исправить?

Ответ 1

EDIT Это решение не работает во всех случаях. Здесь - это правильное решение, которое работает во всех случаях.

Я использую bash в качестве командной строки, и для меня работал следующий псевдоним:

unwip = "!f() { git filter-branch --msg-filter 'sed -e "s/[ci skip/]$/g"' $1..HEAD ; }; f"

Единственным недостатком является то, что вы указываете интерпретатор и всегда используете sh. В моем случае я полагаюсь на пользовательскую оболочку. Хотя я не верю, что это будет проблемой в любой из основных оболочек, поскольку мы делаем только базовые вещи.

Ответ 2

Общее решение

Получение псевдонима git для корректного прохождения парсера может быть потрясающим набором шума \\\\", поэтому я создал два псевдонима:

# Quote / unquote a sh command, converting it to / from a git alias string
quote-string = "!read -r l; printf \\\"!; printf %s \"$l\" | sed 's/\\([\\\"]\\)/\\\\\\1/g'; printf \" #\\\"\\n\" #"
quote-string-undo = "!read -r l; printf %s \"$l\" | sed 's/\\\\\\([\\\"]\\)/\\1/g'; printf \"\\n\" #"

Это позволяет вам конвертировать все, что вы можете ввести, в sh + например:

$ echo '\"'

\"

В строку с кавычками, подходящую для псевдонима:

$ git quote-string
echo '\"'

"!echo '\\\"' #"

Чтобы процитировать многострочную строку, я написал более длинный script, который я предлагаю вам запустить как:

git quote-string | sponge

Ответ на конкретную проблему OP

Используя git quote-string в команде OP, я получаю:

"!git filter-branch -f --msg-filter \"sed -e \\\"s/\\[ci skip\\]$//g\\\"\" master..HEAD #"

Итак, чтобы использовать предпочтительное имя псевдонима OP, под [alias] в ~/.gitconfig, добавьте:

unwip = "!git filter-branch -f --msg-filter \"sed -e \\\"s/\\[ci skip\\]$//g\\\"\" master..HEAD #"

Отладка

Иногда приятно видеть, что происходит под капотом. Попробуйте этот псевдоним:

debug  = "!set -x; GIT_TRACE=2 GIT_CURL_VERBOSE=2 GIT_TRACE_PERFORMANCE=2 GIT_TRACE_PACK_ACCESS=2 GIT_TRACE_PACKET=2 GIT_TRACE_PACKFILE=2 GIT_TRACE_SETUP=2 GIT_TRACE_SHALLOW=2 git"

Просто вставьте debug между git и тем, что обычно будет следовать, например, для вопроса OP:

git debug unwip


+ git использует /bin/sh для выполнения псевдонимов, начинающихся с ! *. Чтобы обойти это, создайте командную строку, например: bash -c 'echo \\\"', а затем передайте ее на git quote-string.

* См. заголовок "Отладка" для подтверждения