在所有子目录上运行 git pull [重复]

Posted

技术标签:

【中文标题】在所有子目录上运行 git pull [重复]【英文标题】:Run git pull over all subdirectories [duplicate] 【发布时间】:2011-03-30 15:42:15 【问题描述】:

如何在没有cd'ing 的情况下从它们的共享父目录更新多个 git 存储库到每个 repo 的根目录?我有以下都是单独的 git 存储库(not 子模块):

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

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

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

等等

【问题讨论】:

find -name .git -execdir git pull \; 有什么问题? git do pull怎么样 answered hg mercurial 的相同问题。 find . -name .git -print -execdir git pull \; 可以。 -print 将回显当前目录。 另请参阅,使用 Git 2.30(2020 年第四季度),[新的 git for-each-repo 命令] (***.com/a/65766304/6309) 【参考方案1】:

这应该会自动发生,只要 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

【讨论】:

不,对不起,您误会了。这些目录中的每一个都是一个单独的 git 存储库。 /plugins 不是存储库 啊。我的错。一分钟后会给你 bash 解决方案。 你去。如果要返回父目录,之后再运行一个cd ..即可。 或使用pushdpopd 或将这组命令放在一个子shell 中(当子shell 退出时,您将留在原始目录中)。 (cd dir; for ... done) 出于好奇 - 为什么不使用 ssh 密钥?【参考方案2】:

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?”

【讨论】:

另见***.com/questions/1979167/git-submodule-update和***.com/questions/1030169/…:git submodule foreach git pull也可以感兴趣。 注意:澄清一下,'plugins',目前不是一个 git 仓库,应该作为子模块的父 git 仓库。【参考方案3】:

从父目录运行以下命令,在本例中为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,我建议在-exec 之后使用echo 进行预览,例如:

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

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

【讨论】:

find: 警告:您在非选项参数 -type 之后指定了 -depth 选项,但选项不是位置性的(-depth 影响在它之前指定的测试以及在它之后指定的测试)。请在其他参数之前指定选项。 我使用find . -maxdepth 1 -type d -print -execdir git --git-dir=/.git --work-tree=$PWD/ pull origin master \;在拉取之前输出文件夹的名称,以消除警告并仅对子文件夹运行拉取。 fetch origin master:master 替换'pull origin master' 告诉git 用origin 的master 分支显式更新你的'master' 分支。此不会进行合并,如果您这样做,任何对 master 的提交都将丢失。 从 git 1.8.5 开始,可以用 -C 选项替换 --git-dir 和 --work-tree,参见this question。 -- 我正在使用find . -mindepth 1 -maxdepth 1 -type d -print -exec git -C pull \; @Rystraum 提到的@ZsoltSzilagy,您可以使用-maxdepth 1 而不是-depth 1【参考方案4】:

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

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

这将更新您工作目录中的所有 Git 存储库。无需明确列出它们的名称(“cms”、“admin”、“chart”)。 “cd”命令只影响子shell(使用括号生成)。

【讨论】:

正是我想要的 这个的优点是显示它正在处理哪个存储库,当出现问题时有用(缺少分支,不可用的远程......) 这很好用。我添加了一个 crontab -e 文件,每 5 分钟运行一次,它似乎完全符合我的期望。 我喜欢这个解决方案,因为它只提取 git repo 的子目录,谢谢! 交替使用git -C: for i in */.git; do git -C $i pull; done【参考方案5】:
ls | xargs -I git -C  pull

并行执行:

ls | xargs -P10 -I git -C  pull

【讨论】:

不错!我在我的 .gitconfig 中把它作为别名:all = "!f() ls | xargs -I git -C $1; ; f" 现在我可以做git all pullgit all "checkout master" 等。 清理了一下,将递归搜索所有目录以仅 git repos,并去除颜色以防你有 ls 别名 ls -R --directory --color=never */.git | sed 's/\/.git//' | xargs -P10 -I git -C pull 我将一些答案拼凑在一起,为 macOS 上的 git 创建了这个,它过滤包含 .git 文件夹的文件夹,并允许您运行任意命令,例如 git all fetch --prune: git config --global alias.all '!f() ls -R -d */.git | sed 's,\/.git,,' | xargs -P10 -I git -C $1; ; f' @AWrightIV 实际上,ls -R -d */.git 正在返回当前文件夹中包含.git 目录的目录的过滤列表。这样,当我运行 git all fetch 之类的东西时,它只会针对具有 .git 文件夹的子文件夹执行。这是对原始问题的回答,但它试图通过不假设所有子目录都是 git repos 来提高效率。 对 borisdiakur 命令的轻微改进,以避免在 . 上运行并打印出它在每个时刻运行的目录:git config --global alias.all '!f() ls -R -d */.git | xargs -I bash -c "echo && git -C /../ $1"; ; f'【参考方案6】:

你可以试试这个

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

另外,您可以通过添加一个更多的 && 参数来添加您的自定义输出。

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

【讨论】:

【参考方案7】:

如果你有很多带有 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
'

【讨论】:

伟大的。我做了一些修改以适应我的风格。 pastebin【参考方案8】:

mr 实用程序(又名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'

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

mr 是一个非常有用的处理多个 repos 的工具。由于plugins 文件夹位于您的主目录中,您可能还对vcsh 感兴趣。与mr 一起,它提供了一种强大的机制来管理所有您的配置文件。请参阅 Thomas Ferris Nicolaisen 的 blog post 了解概览。

【讨论】:

【参考方案9】:

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

ls | parallel git -C  pull

【讨论】:

【参考方案10】:

我用这个:

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

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

【讨论】:

您可以使用--git-dir 而不是-C 直接传入.git 路径,无需替换sed! find . -name ".git" -type d | xargs -P10 -I git --git-dir= pull【参考方案11】:

我用这个

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

Github

【讨论】:

【参考方案12】:

前 5 个答案都不适合我,而且问题涉及目录。

这行得通:

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

【讨论】:

对于 Windows,请在此处查看我的答案:***.com/a/51016478/207661。和上面的很相似。 接受的答案曾经对我有用,但它在去年的某个时候退出了。我终于决定寻找另一种解决方案并找到您的答案。感谢分享。效果很好。 无需push和pup,只需使用git的-C选项即可。 另一种选择是使用子shell:for d in *; do (cd $d &amp;&amp; git pull --ff-only); done 这比-C 具有优势,因为这种方法普遍适用于没有此类选项的程序。请注意,--ff-only 在自动更新的情况下最好使用;如果使用原生 vim 包管理,我会使用它来更新 vim 插件。【参考方案13】:

其实,如果你不知道子文件夹有没有git repo,最好让find为你获取repos:

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

PowerShell 等效项是:

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

【讨论】:

这适用于我的 macOS。 确保你所有的 git repos 都在 master 上,然后再按照所写的方式执行。否则你可能会无意中将 master 合并到你当前的分支中。 感谢您的 powershell 版本,仍然适用于 PS 7.10 对于 PS 2.0 这工作:gci | where $_.Attributes -match'Directory' | foreach write-host $_.fullname; push-location $_; &amp; git pull; &amp; cd .. 注意 - 我找不到 hidden 参数,但 Force 似乎可以工作,就像在 Get-ChildItem -Path "C:\Repos" -Recurse -Directory -Force -Filter ".git" -Depth 1 中一样【参考方案14】:

gitfox 是一个在所有 subrepos 上执行命令的工具

npm install gitfox -g
g pull

【讨论】:

g 是什么?不是每个人都有和你一样的别名 @LưuVĩnhPhúc gitfox 出于某种原因将自己安装在别名“g”下(尽管帮助消息显示“gitfox”)。就我个人而言,我不认为这是一个足够重要的命令来要求这样的捷径但是啊。不过,它可以完成这项工作。 @LưuVĩnhPhúc 检查源代码库的使用情况github.com/eqfox/gitfox【参考方案15】:

我综合了几个cmets和答案的点:

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

【讨论】:

【参考方案16】:

我的卑微结构

显示当前路径(使用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 \;

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

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

【讨论】:

不知道为什么这个答案有净票数。这是最有帮助的,imo,因为我可以达到更大的最大深度,而不是继续访问非 git 存储库。我用它在我的“开发者”存储库中的所有存储库上运行 git gc。 我也喜欢这个答案,因为它易于阅读并且很容易添加多个命令。

以上是关于在所有子目录上运行 git pull [重复]的主要内容,如果未能解决你的问题,请参考以下文章

批量拉取所有子目录 git pull --all

批量拉取所有子目录 git pull --all

在所有子目录中的文件中查找和替换文本[重复]

如何防止root运行git pull?

Git存储库中的Git存储库[重复]

git submodule 怎么用