如果没有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 |
等。
- find -name .git -execdir git pull \;出了什么问题?
- 那么git do pull呢?
- 同样的问题也回答了hg mercurial。
- find . -name .git -print -execdir git pull \;正常。-print将回响当前的dir。
在这种情况下,从父目录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。
- 感谢@batandwa对-d用法的评论。
- find:警告:您已经在非选项参数-type后面指定了-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,请参见本问题。--我用的是find . -mindepth 1 -maxdepth 1 -type d -print -exec git -C {} pull \;。
- 不幸的是,它不能工作:"find:warning:您已经在非选项参数类型之后指定了-depth选项,但是选项不是位置性的(depth会影响前面指定的测试以及后面指定的测试)。请在其他参数之前指定选项。find:路径必须在表达式之前:1用法:find[-h][-l][-p][-olevel][-d help tree search stat rates opt exec][path…][expression]"
- @zsoltszilagy如@rystraum所述,您可以使用-maxdepth 1而不是-depth 1。
- 请注意,当为裸存储库使用此解决方案时,您必须省略--work tree并只保留--git dir,即find . -type d -depth 1 -exec echo git --git-dir={}/ remote update \;。
- 我用这个来避免隐藏文件夹find . -not -path '*/\.*' -mindepth 1 -maxdepth 1 -type d -print -exec git -C {} pull \;。
- 我们能使每个git pull并行运行吗?
- 我发现这行的所有空格都很敏感。
1
| ls | xargs -I{} git -C {} pull |
要并行执行此操作:
1
| 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,就会去掉颜色。
- 下面是git config命令,将其作为别名添加:git config--global alias.all'!f()ls xargs-i git-c 1;f'
- 我把一些答案拼凑在一起,在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'。
- @CourtneyFaulkner这看起来像是假定在运行命令的地方有一个.git目录。我说的对吗?似乎不同于原始问题,其中只有子目录包含.git dirs。
- @实际上,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'。
- @borisdiakur是否有一个在所有目录中并行运行拉的技巧?
比Leo的解决方案技术含量低一点:
1
| for i in */.git; do ( echo $i; cd $i/..; git pull; ); done |
这将更新工作目录中的所有Git存储库。无需明确列出其名称("CMS"、"Admin"、"Chart")。"cd"命令只影响子shell(使用括号生成)。
- 正是我要找的
- 它的优点是显示它所处理的存储库,在出现问题时可以使用(缺少分支,远程不可用)。
- 这很管用。我添加了一个crontab-e文件,每5分钟运行一次,它看起来完全符合我的期望。
- 你激励了我。多谢。
我用这个:
1
| 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
实际上,如果您不知道子文件夹是否有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/bin或PATH上的其他位置。然后,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 st、mr push、mr log、mr 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存储库。/plugins不是存储库
- 啊哈。我的错误。会在一分钟内为您提供bash解决方案。
- 你走吧。如果您想返回父目录,只需在之后运行另一个cd ..。
- 或者使用pushd和popd或者将命令组放在子shell中(当子shell退出时,您将留在原始目录中)。(cd dir; for ... done)
- 太酷了,行得通。现在有没有一种方法可以将ssh密码传递给bash脚本,并让脚本将其传递给git/ssh,而不是每次都提示输入我的密码?
- 出于好奇-为什么不使用ssh密钥?
最紧凑的方法,假设所有子目录都是git repos:
1
| ls | parallel git -C {} pull |
前5个答案对我来说都不管用,这个问题涉及目录。
这起作用了:
1
| for d in *; do pushd $d && git pull && popd; done |
- 对于Windows,请参阅我的答案:stackoverflow.com/a/51016478/207661。这和上面的很相似。
gitfox是在所有子报告上执行命令的工具。
1 2
| npm install gitfox -g
g pull |
- 什么是g?不是每个人都有你的化名
- @ L?紫外线?nhph&250;c gitfox出于某种原因将自己安装在别名"g"下(尽管帮助消息称为"gitfox")。就个人而言,我不认为这是一个命令,不足以要求这样的捷径,但啊,好吧。不过,它确实起到了作用。
- @ L?紫外线?nhph&250;c检查源repo的用法github.com/eqfox/gitfox
你可以试试这个
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 \; |
- 不知道为什么这个答案有净落差。这是最有用的,伊莫,因为我可以去一个更大的最大深度,而不是不断打击非git回购。我使用它在我的"开发人员"报告中的所有存储库上运行GitGC。
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子模块--递归?"
- 另请参见stackoverflow.com/questions/1979167/git-submodule-update和stackoverflow.com/questions/1030169/&hellip;:git submodule foreach git pull也可能感兴趣。
- 注:为了澄清,应将目前不属于git回购的"plugins"作为子模块的母公司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
' |