72

I have a set of repositories sorted into directories based on their VCS (Git, Mercurial, SVN). With Subversion I was able to run svn update * in the parent directory and it would loop through each directory and update each repository as expected. That's not the case for Git or Mercurial.

I would like to come up with a bash script that I can run to do exactly that, loop through directories and either git pull or hg pull in each. I just don't have much bash scripting experience.

Bryan Veloso
  • 823
  • 1
  • 7
  • 6
  • It could be clarified whether you want the commands executed recursively (in all subfolders), where mj41's answer is the only one I've tried (from here and at other SO sites) that does that. – r_alex_hall Nov 08 '19 at 01:48
  • * does that with a tweak that I mention in a comment on it. – r_alex_hall Nov 08 '19 at 01:54

5 Answers5

117
for dir in ~/projects/git/*; do (cd "$dir" && git pull); done
slhck
  • 223,558
  • 70
  • 607
  • 592
jtimberman
  • 21,597
  • 12
  • 68
  • 77
  • 2
    Thnx... but i need to capture errors as well. How can I do so. I've never done shell programming before. – shashwat Feb 16 '15 at 10:37
  • If I remove parenthesis it stops working. What's the concept behind it? – mohit Dec 17 '19 at 06:28
  • @mohit parentheses create a sub-shell where the commands are executed, so the `cd` will descend into the given directory and then when the sub-shell exits you'll be back in the original directory. – Ken Williams Mar 23 '22 at 15:41
29

If you need it to be recursive:

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

This will descend into all the directories under the current one, and perform a git pull on those subdirectories that have a .git directory (you can limit it with -maxdepth).

Dennis Williamson
  • 106,229
  • 19
  • 167
  • 187
10

If you have GNU Parallel http:// www.gnu.org/software/parallel/ installed you can do this:

cd ~/projects/git/; ls | parallel 'cd {} && git pull'

This will run in parallel so if some of the git servers' network connection are slow this may speed up things.

If the dir listing is < 128 KBytes, you can also do:

parallel 'cd {} && git pull' ::: ~/projects/git/*/

If you want to follow the pull happening (requires version 20230322):

parallel --ll 'cd {} && git pull' ::: ~/projects/git/*/

Watch the intro video for GNU Parallel to learn more: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
  • 4,529
  • 2
  • 34
  • 51
4

This should work

find . -maxdepth 1 -type d -name '.git' -exec sh -c 'cd "{}" && pwd && git pull' \;
slhck
  • 223,558
  • 70
  • 607
  • 592
mj41
  • 141
  • 2
  • removing the `-maxdepth 1` flag, this is the only command I've found in a lot of searching and trying that executes a command _recursively_ (in all subdirectories, not just the directories one level down). – r_alex_hall Nov 08 '19 at 01:46
2

To do it without using find but forloop

for dir in ~/projects/git/*/*/; do (cd "$dir" && git pull); done
loretoparisi
  • 241
  • 2
  • 7