在所有子目录上运行 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 ..
即可。
或使用pushd
和popd
或将这组命令放在一个子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 pull
、git 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/bin
或PATH
的其他位置。然后,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 st
、mr push
、mr log
、mr 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 && 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 $_; & git pull; & 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 [重复]的主要内容,如果未能解决你的问题,请参考以下文章