Как запустить несколько команд в подмодуле git foreach?

Что я пробовал

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.

@Compo, учитывая, что решение требует синтаксиса, специфичного для пакетного файла, для передачи команд оболочки в git submodule foreach, я думаю, что тег пакетного файла подходит, и я восстановил его.

mklement0 28.09.2023 16:13

Тот факт, что они использовали %CommitMessage% и потенциально ||, не должен иметь абсолютно никакого значения. Вопрос ясен: «Есть ли способ заставить подмодуль git foreach вызывать метод или каким-либо образом вызывать несколько команд одновременно?». Пакетные файлы не имеют к этому никакого отношения и отвлекают внимание или, возможно, создают еще один вопрос после того, как на этот вопрос будет дан ответ.

Compo 28.09.2023 16:55

@Compo, тот факт, что решение Unix, опубликованное ниже, не работает с пакетным файлом, подразумевает, что существуют особенности, специфичные для пакетных файлов, поскольку вызывающая оболочка и ее синтаксис имеют значение, когда дело доходит до передачи команды оболочки (POSIX) в git submodule foreach . Явное указание решений cmd.exe/пакетных файлов важно для команд git в целом, примеры команд которых часто пишутся для POSIX-совместимых оболочек, но особенно, когда у вас есть смесь синтаксисов оболочки, как в этом случае.

mklement0 28.09.2023 18:45

Как только у ОП появится ответ на «способ заставить подмодуль git foreach вызывать метод или каким-либо образом вызывать несколько команд одновременно». Тогда у них может возникнуть дополнительный вопрос о том, как это можно реализовать в среде командной строки или сценарии Windows. В каждой заявке должен быть только один вопрос, и этот вопрос ясен.

Compo 28.09.2023 18:57

@Compo, я не думаю, что на этот вопрос стоит отвечать абстрактно, потому что он слишком тесно связан с синтаксисом оболочки, из которой может звонить пользователь. Говоря прагматично, учитывая ограниченное количество распространённых оболочек, здесь можно дать ответы на все из них, и во многом это уже произошло, учитывая, что есть ещё ответ Ларсков, ориентированный на Bash. Таким образом, теги batch-file и bash теперь уместны. Я пометил удаление вашего тега для рассмотрения модератором. Ничего личного, я просто думаю, что удаление было неправильным поступком.

mklement0 28.09.2023 20:50

Насколько я понимаю, @mklement0, вы слишком много ответили на вопрос или ответили на незаданный вопрос (по вполне обоснованному предположению). Поступая таким образом, вы теперь выступаете за тег, который не был актуален до тех пор, пока он не стал фактом. Теперь вы также включили опцию PowerShell. Означает ли это, что вы будете требовать добавления и ее тега. В вопросе уже есть полная квота тегов, и, по моему мнению, Windows должна адекватно охватывать cmd, powershell и перекомпилированные варианты bash. Во всяком случае, я бы посоветовал заменить тег «bash» на что-то более всеобъемлющее, например, на «интерфейс командной строки».

Compo 29.09.2023 14:13

@Compo, да, я решил приготовить лимонад - после того, как другой ответчик пропустил аспект Windows - и завершить картину, предоставив в этом посте решения Bash, пакетных файлов и PowerShell. Изначально я использовал тег «Windows» в качестве временного промежутка, учитывая, что здесь важны именно оболочки. Однако с добавлением решения PowerShell «Windows» теперь, возможно, становится подходящим, учитывая, что теперь поддерживаются обе собственные оболочки Windows. Я рад оставить все как есть.

mklement0 29.09.2023 14:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Предполагая, что среда 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.

Tyler 22.09.2023 14:34

Тогда вы что-то путаете. Вот пример того, как будет выглядеть запуск аналогичного скрипта в репозитории с подмодулями: asciinema.org/a/GU0qZkV3fd723w0KhpPc10QFi

larsks 22.09.2023 14:40

Я скопировал и вставил то, что у вас было, прямо в свой пакетный скрипт.

Tyler 22.09.2023 14:42

И все же это явно работает, а это говорит о том, что в вашем окружении есть что-то особенное. Вы сказали «пакетный сценарий», но это предполагает, что вы работаете в оболочке Unix. Вы используете Windows?

larsks 22.09.2023 14:43

Да, я использую Windows, а не Unix. Есть ли способ сделать то же самое в Windows?

Tyler 22.09.2023 14:44
Ответ принят как подходящий

Чтобы дополнить полезное решение 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 help.
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!\"" Примечание. Именно поэтому мне пришлось \" избегать кавычек. Спасибо за помощь! Я отмечаю ваш ответ как решение.

Tyler 28.09.2023 19:32

Рад это слышать, @Тайлер. Альтернативой переключению на отложенное раскрытие является использование ^-экранирования; пожалуйста, посмотрите мое обновление.

mklement0 28.09.2023 20:52

Как ни странно, если я вручную убегу с помощью ^, это будет нормально работать для подмодулей, но затем включу ^ в сообщение, когда я фиксирую основной.

Tyler 28.09.2023 21:34

@ Тайлер, это действительно любопытно. У меня в этом минимальном примере этого не происходит (запускается из cmd.exe, как отдельные команды): set "bar=a ^| b"echo "foo \"%bar%\" baz" - вы увидите, что в эхогенной строке нет ^

mklement0 28.09.2023 21:49

Другие вопросы по теме