关于bash:运行git覆盖所有子目录

Run git pull over all subdirectories

本问题已经有最佳答案,请猛点这里访问。

如果没有cd进入每个repo的根目录,我如何从共享父目录更新多个git存储库?我有以下所有独立的Git存储库(而不是子模块):

1
2
3
/plugins/cms
/plugins/admin
/plugins/chart

我想一次更新它们,或者至少简化我当前的工作流程:

1
2
3
4
cd ~/plugins/admin
git pull origin master
cd ../chart
git pull

等。


在这种情况下,从父目录plugins运行以下命令:

1
find . -type d -depth 1 -exec git --git-dir={}/.git --work-tree=$PWD/{} pull origin master \;

澄清:

  • find .搜索当前目录
  • -type d查找目录,而不是文件
  • 一个子目录的最大深度为-depth 1
  • -exec {} \;为每个查找运行一个自定义命令
  • git --git-dir={}/.git --work-tree=$PWD/{} pullgit拉单目录

为了使用find,我建议在-exec之后使用echo进行预览,例如:

1
find . -type d -depth 1 -exec echo git --git-dir={}/.git --work-tree=$PWD/{} status \;

注:如果-depth 1选项不可用,请尝试-mindepth 1 -maxdepth 1


1
ls | xargs -I{} git -C {} pull

要并行执行此操作:

1
ls | xargs -P10 -I{} git -C {} pull


比Leo的解决方案技术含量低一点:

1
for i in */.git; do ( echo $i; cd $i/..; git pull; ); done

这将更新工作目录中的所有Git存储库。无需明确列出其名称("CMS"、"Admin"、"Chart")。"cd"命令只影响子shell(使用括号生成)。


我用这个:

1
find . -name".git" -type d | sed 's/\/.git//' |  xargs -P10 -I{} git -C {} pull

通用:更新当前目录下的所有Git存储库。


实际上,如果您不知道子文件夹是否有git repo,最好是让find为您获取repo:

1
find . -type d -name .git -exec git --git-dir={} --work-tree=$PWD/{}/.. pull origin master \;

PowerShell等价物为:

1
Get-ChildItem -Recurse -Directory -Hidden  -Filter .git | ForEach-Object { & git --git-dir="$($_.FullName)" --work-tree="$(Split-Path $_.FullName -Parent)" pull origin master }


mr实用程序(A.K.A.,myrepos)为这个问题提供了一个出色的解决方案。使用您最喜欢的包管理器安装它,或者直接从Github获取mr脚本并将其放入$HOME/binPATH上的其他位置。然后,cd到这些repos共享的父plugins文件夹,创建一个基本.mrconfig文件,其内容类似于以下内容(根据需要调整URL):

1
2
3
4
5
6
7
8
9
# File: .mrconfig
[cms]
checkout = git clone 'https://<username>@github.com/<username>/cms' 'cms'

[admin]
checkout = git clone 'https://<username>@github.com/<username>/admin' 'admin'

[chart]
checkout = git clone 'https://<username>@github.com/<username>/chart' 'chart'

之后,您可以从顶层的plugins文件夹运行mr up,以从每个存储库中提取更新。(请注意,如果目标工作副本还不存在,这也将执行初始克隆。)可以执行的其他命令包括mr stmr pushmr logmr diff等。运行mr help查看可能的情况。有一个mr run命令作为传递,允许您访问不由mr本身直接支持的vcs命令(例如mr run git tag STAGING_081220015)。您甚至可以创建自己的自定义命令,执行针对所有回购的任意位shell脚本!

mr是处理多个回购的非常有用的工具。由于plugins文件夹在您的主目录中,您可能也对vcsh感兴趣。与mr一起,它为管理所有配置文件提供了强大的机制。参见托马斯·费里斯·尼古拉森的这篇博文。


只要cms、admin和chart都是存储库的一部分,这种情况就应该自动发生。

一个可能的问题是每个插件都是一个子模块。

运行git help submodule了解更多信息。

编辑

在bash中这样做:

1
2
3
4
5
cd plugins
for f in cms admin chart
do
  cd $f && git pull origin master && cd ..
done


最紧凑的方法,假设所有子目录都是git repos:

1
ls | parallel git -C {} pull

前5个答案对我来说都不管用,这个问题涉及目录。

这起作用了:

1
for d in *; do pushd $d && git pull && popd; done


gitfox是在所有子报告上执行命令的工具。

1
2
npm install gitfox -g
g pull


你可以试试这个

1
find . -type d -name .git -exec sh -c"cd "{}"/../ && pwd && git pull" \;

此外,还可以通过添加一个类似的参数来添加自定义输出。

1
find . -type d -name .git -exec sh -c"cd "{}"/../ && pwd && git pull && git status" \;


我卑微的构造

  • 显示当前路径(使用python,方便且只起作用,请参见如何获取文件的完整路径?)
  • 直接查找.git子文件夹:在非git子文件夹中发出git命令的几率很低
  • 消除一些关于find的警告

如下:

1
2
3
4
5
find . \
    -maxdepth 2 -type d \
    -name".git" \
    -execdir python -c 'import os; print(os.path.abspath("."))' \; \
    -execdir git pull \;

当然,您可以向find添加其他带有附加-execdir选项的git命令,显示分支,例如:

1
2
3
4
5
6
find . \
    -maxdepth 2 -type d \
    -name".git" \
    -execdir python -c 'import os; print(os.path.abspath("."))' \; \
    -execdir git branch \;
    -execdir git pull \;


2010年原始答案:

如果所有这些目录都是单独的git repo,那么应该将它们作为子模块引用。

这意味着您的"来源"将是远程报告"EDOCX1"(1),其中只包含对子报告"EDOCX1"(2)、"EDOCX1"(3)、"EDOCX1"(4)的引用。

一个git pull,再加上一个git submodule update,就能达到你想要的效果。

2016年1月更新:

使用git 2.8(2016年第1季度),您将能够并行获取子模块!!)与git fetch --recurse-submodules -j2一起。请参见"如何使用Git克隆加速/并行下载Git子模块--递归?"


我用这个

1
2
3
4
5
6
7
for dir in $(find . -name".git")
do cd ${dir%/*}
    echo $PWD
    git pull
    echo""
    cd - > /dev/null
done

github


我综合了几点评论和答案:

1
find . -maxdepth 1 -type d -name .git -execdir git pull \;

如果有很多带有Git存储库的子目录,则可以使用Parallel

1
2
3
4
5
6
7
8
ls | parallel -I{} -j100 '
  if [ -d {}/.git ]; then
    echo Pulling {}
    git -C {} pull > /dev/null && echo"pulled" || echo"error :("
  else
     echo {} is not a .git directory
  fi
'