并行执行 "git submodule foreach"
Execute "git submodule foreach" in parallel
有没有办法并行执行 git submodule foreach
命令,类似于 --jobs 8
参数与 git submodule update
的工作方式?
例如,我们从事的一个项目涉及将近 200 个子组件(子模块),我们大量使用 foreach
命令对其进行操作。我想加快速度。
PS:在解决方案涉及脚本的情况下,我使用 Windows 并且大部分时间使用 git-bash.
我向您推荐一个基于解释语言多平台的解决方案,例如 Python。
进程启动器
首先你需要定义一个class来管理启动命令的进程。
class PFSProcess(object):
def __init__(self, submodule, path, cmd):
self.__submodule = submodule
self.__path = path
self.__cmd = cmd
self.__output = None
self.__p = None
def run(self):
self.__output = "\n\n" + self.__submodule + "\n"
self.__p = subprocess.Popen(self.__cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True,
cwd=os.path.join(self.__path, self.__submodule))
self.__output += self.__p.communicate()[0].decode('utf-8')
if self.__p.communicate()[1]:
self.__output += self.__p.communicate()[1].decode('utf-8')
print(self.__output)
多线程
下一步是生成多线程执行。 Python 在其核心中包含非常强大的库来处理线程。您可以使用它导入以下包:
import threading
在创建线程之前你需要创建一个worker,一个为每个线程调用的函数:
def worker(submodule_list, path, command):
for submodule in submodule_list:
PFSProcess(submodule, path, command).run()
如您所见,worker 收到了一个子模块列表。为了清楚起见并且因为它超出了我们的范围,我建议您查看 .gitmodules
从那里您可以生成读取文件的子模块列表。
<提示>
作为基本方向,您可以在每个子模块中找到以下行:
path = relative_path/project
为此,您可以使用此正则表达式:
'path ?= ?([A-za-z0-9-_]+)(\/[A-za-z0-9-_]+)*([A-za-z0-9-_])'
如果正则表达式匹配,您可以在同一行中使用以下内容获取相对路径:
' ([A-za-z0-9-_]+)(\/[A-za-z0-9-_]+)*([A-za-z0-9-_])'
注意,因为最后一个正则表达式 returns 是第一个位置带有 space 字符的相对路径。
提示>
然后将子模块列表分成与您想要的作业一样多的块:
num_jobs = 8
i = 0
for submodule in submodules:
submodule_list[i % num_jobs].append(submodule)
i += 1
最后将每个块(作业)分派给每个线程并等待所有线程完成:
for i in range(num_jobs):
t = threading.Thread(target=worker, args=(list_submodule_list[i], self.args.path, self.args.command,))
self.__threads.append(t)
t.start()
for i in range(num_jobs):
self.__threads[i].join()
显然我已经介绍了基本概念,但是您可以访问 GitHub.
中的 parallel_foreach_submodule (PFS) 项目来访问完整的实现
一个简单的、bash 唯一的解决方案是这样做(替换 <command with your command>
):
IFS=$'\n'
for DIR in $(git submodule foreach -q sh -c pwd); do
cd $DIR && <command> &
done
wait
作为通用命令(创建一个名为“git-foreach-parallel”的文件):
#!/bin/bash
if [ -z "" ]; then
echo "Missing Command" >&2
exit 1
fi
COMMAND="$@"
IFS=$'\n'
for DIR in $(git submodule foreach -q sh -c pwd); do
cd "$DIR" && $COMMAND &
done
wait
如果有人正在寻找一种纯粹的 bash 方法(不在 docker 容器或其他东西中安装 python),这对我有帮助
使用示例
bash git-submodule-foreach-parallel.sh "git fetch && git checkout master"
bash git-submodule-foreach-parallel.sh "git fetch && git pull"
bash git-submodule-foreach-parallel.sh "git fetch && git push"
COMMAND="git clean -dfx -e \"**/.idea\""
# Running command in parent repository
eval "$COMMAND"
# Running command in submodules
bash git-submodule-foreach-parallel.sh "$COMMAND"
git-submodule-foreach-parallel.sh(用法举例运行吧)
#!/bin/bash
if [ -z "" ]; then
echo "Missing Command" >&2
exit 1
fi
COMMAND="$@"
IFS=$'\n'
for DIR in $(git submodule foreach --recursive -q sh -c pwd); do
printf "\nStarted running command \"${COMMAND}\" in directory \"${DIR}\"\n" \
&& \
cd "$DIR" \
&& \
eval "$COMMAND" \
&& \
printf "Finished running command \"${COMMAND}\" in directory \"${DIR}\"\n" \
&
done
wait
有没有办法并行执行 git submodule foreach
命令,类似于 --jobs 8
参数与 git submodule update
的工作方式?
例如,我们从事的一个项目涉及将近 200 个子组件(子模块),我们大量使用 foreach
命令对其进行操作。我想加快速度。
PS:在解决方案涉及脚本的情况下,我使用 Windows 并且大部分时间使用 git-bash.
我向您推荐一个基于解释语言多平台的解决方案,例如 Python。
进程启动器
首先你需要定义一个class来管理启动命令的进程。
class PFSProcess(object):
def __init__(self, submodule, path, cmd):
self.__submodule = submodule
self.__path = path
self.__cmd = cmd
self.__output = None
self.__p = None
def run(self):
self.__output = "\n\n" + self.__submodule + "\n"
self.__p = subprocess.Popen(self.__cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True,
cwd=os.path.join(self.__path, self.__submodule))
self.__output += self.__p.communicate()[0].decode('utf-8')
if self.__p.communicate()[1]:
self.__output += self.__p.communicate()[1].decode('utf-8')
print(self.__output)
多线程
下一步是生成多线程执行。 Python 在其核心中包含非常强大的库来处理线程。您可以使用它导入以下包:
import threading
在创建线程之前你需要创建一个worker,一个为每个线程调用的函数:
def worker(submodule_list, path, command):
for submodule in submodule_list:
PFSProcess(submodule, path, command).run()
如您所见,worker 收到了一个子模块列表。为了清楚起见并且因为它超出了我们的范围,我建议您查看 .gitmodules
从那里您可以生成读取文件的子模块列表。
<提示>
作为基本方向,您可以在每个子模块中找到以下行:
path = relative_path/project
为此,您可以使用此正则表达式:
'path ?= ?([A-za-z0-9-_]+)(\/[A-za-z0-9-_]+)*([A-za-z0-9-_])'
如果正则表达式匹配,您可以在同一行中使用以下内容获取相对路径:
' ([A-za-z0-9-_]+)(\/[A-za-z0-9-_]+)*([A-za-z0-9-_])'
注意,因为最后一个正则表达式 returns 是第一个位置带有 space 字符的相对路径。
提示>
然后将子模块列表分成与您想要的作业一样多的块:
num_jobs = 8
i = 0
for submodule in submodules:
submodule_list[i % num_jobs].append(submodule)
i += 1
最后将每个块(作业)分派给每个线程并等待所有线程完成:
for i in range(num_jobs):
t = threading.Thread(target=worker, args=(list_submodule_list[i], self.args.path, self.args.command,))
self.__threads.append(t)
t.start()
for i in range(num_jobs):
self.__threads[i].join()
显然我已经介绍了基本概念,但是您可以访问 GitHub.
一个简单的、bash 唯一的解决方案是这样做(替换 <command with your command>
):
IFS=$'\n'
for DIR in $(git submodule foreach -q sh -c pwd); do
cd $DIR && <command> &
done
wait
作为通用命令(创建一个名为“git-foreach-parallel”的文件):
#!/bin/bash
if [ -z "" ]; then
echo "Missing Command" >&2
exit 1
fi
COMMAND="$@"
IFS=$'\n'
for DIR in $(git submodule foreach -q sh -c pwd); do
cd "$DIR" && $COMMAND &
done
wait
如果有人正在寻找一种纯粹的 bash 方法(不在 docker 容器或其他东西中安装 python),这对我有帮助
使用示例
bash git-submodule-foreach-parallel.sh "git fetch && git checkout master"
bash git-submodule-foreach-parallel.sh "git fetch && git pull"
bash git-submodule-foreach-parallel.sh "git fetch && git push"
COMMAND="git clean -dfx -e \"**/.idea\""
# Running command in parent repository
eval "$COMMAND"
# Running command in submodules
bash git-submodule-foreach-parallel.sh "$COMMAND"
git-submodule-foreach-parallel.sh(用法举例运行吧)
#!/bin/bash
if [ -z "" ]; then
echo "Missing Command" >&2
exit 1
fi
COMMAND="$@"
IFS=$'\n'
for DIR in $(git submodule foreach --recursive -q sh -c pwd); do
printf "\nStarted running command \"${COMMAND}\" in directory \"${DIR}\"\n" \
&& \
cd "$DIR" \
&& \
eval "$COMMAND" \
&& \
printf "Finished running command \"${COMMAND}\" in directory \"${DIR}\"\n" \
&
done
wait