我得到一个包含不同Git repos的本地目录。目录树是这样的:
rid gamedate hid home Home Score vid visitor Visitor Score
-----------------------------------------------------------------
183 08/31/2017 4 Aliso 3 15 Beck 2
187 08/31/2017 7 Martin Luther 3 15 Beck 2
161 09/05/2017 25 Burrou 16 15 Beck 18
261 09/20/2017 4 Aliso 12 137 Mission 2
211 08/25/2017 25 Burrou 14 137 Mission 7
我想创建一个使用Dir
- dir1 --- repo1
- dir2 --- repo2
- dir3 --- repo3
命令获取所有find
目录名的Bash脚本,然后将.git
循环中的所有路径传递给{{1}来自远程仓库的所有更新。
因此,我可以通过运行此bash脚本来更新所有repos。
任何人都可以提示如何做到这一点吗?相关文档也很有帮助。
答案 0 :(得分:2)
目前还不清楚您的所有存储库是否都位于同一目录级别,但它们似乎来自您的问题。从这个角度来看,没有必要调用find
,只需使用globbing,例如
for dir in */; do ## for each dir under present
if [ -d "$dir/.git" ]; then ## does it have a .git dir?
pushd "$dir" >/dev/null 2>&1 ## if so, change to it
git pull ## update repo
popd >/dev/null 2>&1 ## change back to original dir
fi
done
有很多变化。我使用pushd
和popd
来避免解析路径或使用..
。如果您愿意,可以cd "$dir"
然后cd ..
。
目录不是全部在同一级别,您可以使用find
,如果您正在寻找最短的实现,它可能会像:
cwd="$PWD" ## save current path
for dir in $(find . -type d -name "*\.git"); do ## loop over all with .git
dname="${dir#./}" ## trim leading './'
cd "$cwd/${dname%/.git}" && git pull ## change to and git pull
done
让我知道这对你有好处。
答案 1 :(得分:2)
我将建议一种相当不同的方法,一种利用find
运行命令的能力。
cd Dir # Change to the top-level directory
find . -type d -name .git -exec \
sh -c 'for d in "$@"; do (cd "$d/.."; git pull) done' argv0 {} +
这会将目录更改为顶级目录,然后运行find
以找到.git
目录。执行-exec
后的命令,每个Git目录名称代替脚本中的{}
,+
表示将使用方便的名称。单一命令执行。执行的命令是:
sh -c 'for d in "$@"; do (cd "$d/.." && git pull) done' argv0 dir1/.git dir2/.git …
argv0
参数是通过$0
运行的shell脚本的-c '…'
- 如果您愿意,可以使用git-multi-pull
之类的名称。该脚本依次处理每个参数,仔细保留空格,通过(cd "$d/.." && git pull)
将目录更改为存储库的顶级目录并运行git pull
。 (…)
在子shell中运行操作,这意味着如果存在问题(很难看到它会是什么,但以防万一),只有一个子子shell受到影响。没有必要尝试回到下一个cd
的正确位置 - 退出前一个子shell而不影响sh -c '…'
shell。这样做的好处是文件名中的所有偏心字符都可以自动完成处理。
这是'在命令行输入'版本。您可以删除cd Dir
并在.
命令中将"${@:-.}"
替换为find
,从而将其设置为脚本。然后,您可以将要搜索Git repos的目录指定为命令行参数,或者如果没有命令行参数,则使用当前目录。
您可以在shell脚本中添加pwd
或echo "$d"
,以便随时回复目录名称,从而为您提供进度跟踪。如果您愿意,可以证明argv0
是$0
,其中包含:
sh -c 'for d in "$@"; do (cd "$d/.." && echo "$0: $PWD" && git pull) done' git-multi-pull {} +
如果你正在进入神秘的shell脚本,你可以省略in "$@"
;写for d; do (…) done
时隐含着这一点。另请注意,当循环的整个主体是子shell时,在done
之前不需要分号; )
就足够了。
答案 2 :(得分:0)
EXEC功能
find / "*.git" -type d -exec git pull {} \;
你可以使用find命令的exec函数。它作用于从find获取的结果。在上面,它将从/目录中搜索系统中的所有git目录/ repos,一旦找到目录,它就会对它们进行git pull。
希望这可以解决您的问题
答案 3 :(得分:-1)
你可以这样做:
for i in `find . -type d -name .git`
do
dir=`dirname $i`
pushd .
cd $dir
git pull
popd
done
答案 4 :(得分:-1)
您可以强制IFS
仅包含\n
作为字分隔符,因此您可以执行类似
IFS='
' #only a new line.
for i in `find . -type d`
do
if [ -d "$i/.git" ]
then
foo_bar "$i"
fi
done
这不仅适用于bash,而且适用于标准的bourne shell(包括UNIX(tm)V7 !!!)
更好的是
find . -type d ... |\
while read dir
do
if [ -d "$i/.git" ]
then
foo_bar "$i" # or `basename "$i"` or whatever you like.
fi
done
当然,您可以使用
直接转到.git
存储库
find . -type d -name .git |\
while read git_repo
do
foo_bar `dirname "$i"`
done
如果你知道所有的回购都在这个水平之下,那就去做
for repo in */.git
do
repo_name=`dirname "$repo"`
foo_bar "$repo_name"
done
例如,正如您在问题中注意到的那样
for repo in */.git
do
( cd `dirname "$repo"`
git pull
) # subshell it to conserve current dir in parent shell.
done
(语法与所有Bourne Shell兼容,而不是特定于bash(1))