git submodule foreach git checkout main
git submodule foreach git add --all
git submodule foreach git diff-index --quiet HEAD || git commit -m "%CommitMessage%"
git submodule foreach git push
При этом выполняется команда 1 для всех субмодулей, затем команда 2 для всех субмодулей и т. д.
Я хотел бы иметь только один foreach и выполнять все команды для подмодуля одновременно, а затем переходить к следующему подмодулю.
Есть ли способ заставить git submodule foreach вызывать метод или каким-либо образом вызывать несколько команд одновременно?
Я хочу сделать это в пакетном сценарии в Windows.
Тот факт, что они использовали %CommitMessage% и потенциально ||, не должен иметь абсолютно никакого значения. Вопрос ясен: «Есть ли способ заставить подмодуль git foreach вызывать метод или каким-либо образом вызывать несколько команд одновременно?». Пакетные файлы не имеют к этому никакого отношения и отвлекают внимание или, возможно, создают еще один вопрос после того, как на этот вопрос будет дан ответ.
@Compo, тот факт, что решение Unix, опубликованное ниже, не работает с пакетным файлом, подразумевает, что существуют особенности, специфичные для пакетных файлов, поскольку вызывающая оболочка и ее синтаксис имеют значение, когда дело доходит до передачи команды оболочки (POSIX) в git submodule foreach . Явное указание решений cmd.exe/пакетных файлов важно для команд git в целом, примеры команд которых часто пишутся для POSIX-совместимых оболочек, но особенно, когда у вас есть смесь синтаксисов оболочки, как в этом случае.
Как только у ОП появится ответ на «способ заставить подмодуль git foreach вызывать метод или каким-либо образом вызывать несколько команд одновременно». Тогда у них может возникнуть дополнительный вопрос о том, как это можно реализовать в среде командной строки или сценарии Windows. В каждой заявке должен быть только один вопрос, и этот вопрос ясен.
@Compo, я не думаю, что на этот вопрос стоит отвечать абстрактно, потому что он слишком тесно связан с синтаксисом оболочки, из которой может звонить пользователь. Говоря прагматично, учитывая ограниченное количество распространённых оболочек, здесь можно дать ответы на все из них, и во многом это уже произошло, учитывая, что есть ещё ответ Ларсков, ориентированный на Bash. Таким образом, теги batch-file и bash теперь уместны. Я пометил удаление вашего тега для рассмотрения модератором. Ничего личного, я просто думаю, что удаление было неправильным поступком.
Насколько я понимаю, @mklement0, вы слишком много ответили на вопрос или ответили на незаданный вопрос (по вполне обоснованному предположению). Поступая таким образом, вы теперь выступаете за тег, который не был актуален до тех пор, пока он не стал фактом. Теперь вы также включили опцию PowerShell. Означает ли это, что вы будете требовать добавления и ее тега. В вопросе уже есть полная квота тегов, и, по моему мнению, Windows должна адекватно охватывать cmd, powershell и перекомпилированные варианты bash. Во всяком случае, я бы посоветовал заменить тег «bash» на что-то более всеобъемлющее, например, на «интерфейс командной строки».
@Compo, да, я решил приготовить лимонад - после того, как другой ответчик пропустил аспект Windows - и завершить картину, предоставив в этом посте решения Bash, пакетных файлов и PowerShell. Изначально я использовал тег «Windows» в качестве временного промежутка, учитывая, что здесь важны именно оболочки. Однако с добавлением решения PowerShell «Windows» теперь, возможно, становится подходящим, учитывая, что теперь поддерживаются обе собственные оболочки Windows. Я рад оставить все как есть.





Предполагая, что среда Unix-подобна, вы можете запустить сценарий оболочки с помощью git submodule foreach:
git submodule foreach sh -e -c '
git checkout main
git add --all
git diff-index --quiet HEAD || git commit -m "message"
git push
'
Это не работает для меня. Вместо этого он запускает эти команды в родительском репо. Я также получаю сообщение об ошибке в кавычках: ''' is not recognized as an internal or external command, operable program or batch file.
Тогда вы что-то путаете. Вот пример того, как будет выглядеть запуск аналогичного скрипта в репозитории с подмодулями: asciinema.org/a/GU0qZkV3fd723w0KhpPc10QFi
Я скопировал и вставил то, что у вас было, прямо в свой пакетный скрипт.
И все же это явно работает, а это говорит о том, что в вашем окружении есть что-то особенное. Вы сказали «пакетный сценарий», но это предполагает, что вы работаете в оболочке Unix. Вы используете Windows?
Да, я использую Windows, а не Unix. Есть ли способ сделать то же самое в Windows?
Чтобы дополнить полезное решение larsks для Unix (которое также будет работать в Unix-подобных средах Windows, таких как Git Bash и WSL) решением для Windows из пакетного файла (см. следующий раздел о PowerShell):
Как и в других случаях, когда git поддерживает передачу команд оболочки, они оцениваются Git Bash, то есть реализацией Bash, которая поставляется в комплекте с git в Windows. Таким образом, вы должны использовать синтаксис оболочки Bash (совместимый с POSIX) даже в Windows.
Примечание. git submodule foreach определяет следующие переменные (среды) для предоставления информации о подмодуле, на который вы можете ссылаться в своей команде оболочки:
$name, $sm_path,
$displaypath, $sha1 и $toplevel; как уже отмечалось, из-за необходимости использования синтаксиса Bash в вашей команде оболочки вам необходимо ссылаться на эти переменные, как показано (например, как $name вместо стиля пакетного файла %name%).git submodule foreach "git checkout main && git add --all && git diff-index --quiet HEAD || git commit -m \"%CommitMessage%\" && git push"
Используйте "..." кавычки в одной строке (cmd.exe/пакетные файлы не поддерживают многострочные строки в кавычках, и программы ожидают только " , а не ', чтобы иметь синтаксическую функцию в командных строках своего процесса).
Ссылка на переменную пакетного стиля %CommitMessage% заранее расширяется на cmd.exe, \"...\" используется для правильного экранирования встроенного "..." вокруг развернутого результата.
Предостережение: если значение %CommitMessage% содержит cmd.exe метасимволы, такие как | и &, команда не будет работать, потому что cmd.exe считает их не заключенными в кавычки из-за непонимания того, что окружающие \" экранированы двойными кавычками; как вы сообщаете, set "CommitMessage=%info1% | %info2% | %info3%" вызвал проблему в вашем случае, и есть два варианта решения:
Либо: Если возможно, вручную ^-экранируйте метасимволы; например.:
set "CommitMessage=%info1% ^| %info2% ^| %info3%"
Или, как вы это сделали, используйте отложенное раскрытие переменной, что позволяет обойти проблему (но может привести к буквальному удалению символов !):
setlocal enableDelayedExpansion вверху командного файла.!...! вместо %...% для ссылки на вашу переменную, т.е. !CommitMessage!Объедините команды с помощью &&, чтобы последующие команды выполнялись только в том случае, если предыдущие были успешными.
Перспектива PowerShell (как на Windows, так и на Unix-подобных платформах):
PowerShell имеет гибкие строковые литералы, включая поддержку многострочных литералов.
Вариант here-string, использованный ниже, улучшает читаемость и устраняет необходимость экранирования встроенных кавычек.
# NOTE: In Windows PowerShell and PowerShell (Core) 7.2-,
# you must manually \-escape the embedded " chars.
# (... -m \"$CommitMessage\")
# $CommitMessage is expanded *by PowerShell*, up front.
git submodule foreach @"
git checkout main &&
git add --all &&
git diff-index --quiet HEAD || git commit -m "$CommitMessage" &&
git push
"@
Важный:
Как отмечено в комментариях к коду, версии Windows PowerShell и PowerShell (Core) до v7.2.x, к сожалению, требуют встроенных символов ". явно экранироваться \ при передаче аргументов во внешние программы, такие как git, что, к счастью, больше не требуется в PowerShell (Core) 7.3+
Поскольку PowerShell также использует символ $ для ссылок на переменные, вы должны `-экранировать любые символы $, которые вы хотите сохранить как таковые, как часть (совместимой с POSIX) команды оболочки, которая будет выполнена git; например, чтобы передать дословно $name для ссылки на имя подмодуля, используйте `$name
Однако это необходимо только в том случае, если "..." используются кавычки, то есть расширяемая строка, что, в свою очередь, необходимо только в том случае, если вам нужна интерполяция (расширение) строки PowerShell, например, для внедрения значения переменной PowerShell $CommitMessage, как показано выше.
Если интерполяция строк не требуется, используйте '...' кавычки, то есть дословную строку ('...'), в этом случае сквозные $ символы. не нужно бежать.
Unix-решение larsks можно использовать как есть в PowerShell (Core) 7.3+, но только из Unix-подобных сред (включая WSL, если там (тоже) установлен PowerShell (Core)), учитывая, что стандартная оболочка Unix, /bin/sh, называется явно.
sh для каждого подмодуля, но он удобен, потому что опция -e — прерывание в случае сбоя команды — позволяет указывать команды индивидуально, без необходимости связывать их с помощью &&.Хороший улов, проблема была в %CommitMessage%. Поскольку внутри него было |, мне нужно установить его так: set "CommitMessage=%info1% | %info2% | %info3%". Я не осознавал, что мне нужно использовать !CommitMessage! и делать setlocal EnableDelayedExpansion. Итак, последняя команда была git submodule foreach "git checkout main && git add --all && git diff-index --quiet HEAD || git commit -m \"!CommitMessage!\"" Примечание. Именно поэтому мне пришлось \" избегать кавычек. Спасибо за помощь! Я отмечаю ваш ответ как решение.
Рад это слышать, @Тайлер. Альтернативой переключению на отложенное раскрытие является использование ^-экранирования; пожалуйста, посмотрите мое обновление.
Как ни странно, если я вручную убегу с помощью ^, это будет нормально работать для подмодулей, но затем включу ^ в сообщение, когда я фиксирую основной.
@ Тайлер, это действительно любопытно. У меня в этом минимальном примере этого не происходит (запускается из cmd.exe, как отдельные команды): set "bar=a ^| b"echo "foo \"%bar%\" baz" - вы увидите, что в эхогенной строке нет ^
@Compo, учитывая, что решение требует синтаксиса, специфичного для пакетного файла, для передачи команд оболочки в
git submodule foreach, я думаю, что тег пакетного файла подходит, и я восстановил его.