在所有子目录上运行git pull

时间:2010-08-16 20:39:36

标签: git bash

如何在没有cd进入每个repo的根目录的情况下,从共享父目录更新多个git存储库?我有以下几个单独的git存储库(子模块):

/plugins/cms
/plugins/admin
/plugins/chart

我想一次更新所有内容,或者至少简化我当前的工作流程:

cd ~/plugins/admin
git pull origin master
cd ../chart
git pull

16 个答案:

答案 0 :(得分:256)

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

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/{} pull git拉出各个目录

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

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

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

答案 1 :(得分:149)

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

要并行执行:

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

答案 2 :(得分:42)

比leo的解决方案更低技术性:

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

这将更新工作目录中的所有Git存储库。无需明确列出他们的名字(" cms"," admin"," chart")。 " cd"命令仅影响子shell(使用括号生成)。

答案 3 :(得分:18)

我用这个:

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

Universal:更新当前目录下的所有git存储库。

答案 4 :(得分:13)

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

find

PowerShell的等价物是:

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

答案 5 :(得分:11)

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

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

运行git help submodule了解详情。

修改

在bash中执行此操作:

cd plugins
for f in cms admin chart
do 
  cd $f && git pull origin master && cd ..
done

答案 6 :(得分:11)

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

# 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'

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

mr run git tag STAGING_081220015是处理多个回购的极其有用的工具。由于mr文件夹位于您的主目录中,因此您可能也对vcsh感兴趣。与plugins一起,它提供了一个强大的机制来管理所有配置文件。请参阅Thomas Ferris Nicolaisen的blog post作为概述。

答案 7 :(得分:10)

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

ls | parallel git -C {} pull

答案 8 :(得分:4)

前5个答案中没有一个适合我,问题涉及目录。

这有效:

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

答案 9 :(得分:4)

gitfox是一个在所有子目录上执行命令的工具

npm install gitfox -g
g pull

答案 10 :(得分:2)

你可以试试这个

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

此外,您还可以添加一个&amp;&amp;&amp;这样的论点。

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

答案 11 :(得分:1)

2010年原始答案:

如果所有这些目录都是单独的git repo,您​​应该将它们引用为 submodules

这意味着您的“来源”将是远程回购“plugins”,其仅包含对子展位“cms”,“admin”,“chart”的引用

git pull后跟git submodule update可以实现您的目标。


2016年1月更新:

使用Git 2.8(2016年第一季度),您将能够使用git fetch --recurse-submodules -j2并行(!)获取子模块。
请参阅“How to speed up / parallelize downloads of git submodules using git clone --recursive?

答案 12 :(得分:1)

我的谦逊建筑

  • 显示当前路径(使用python,方便且正常工作,请参阅How to get full path of a file?
  • 直接查找.git子文件夹:在非git子文件夹中发出git命令的可能性很小
  • 删除了find
  • 的一些警告

如下:

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

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

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

答案 13 :(得分:0)

我用这个

for dir in $(find . -name ".git")
do cd ${dir%/*}
    echo $PWD
    git pull
    echo ""
    cd - > /dev/null
done

Github

答案 14 :(得分:0)

我将几个评论和答案的要点结合起来:

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

答案 15 :(得分:-1)

如果你有很多带有git存储库的子目录,你可以使用并行

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
'