16

I have a git repository root at /git

There are different depth of paths, such as:

/git/project/project1/module1.git
/git/project/project1/module2.git
/git/project/project2/dev/module1.git
/git/library/libgit2.git
/git/library/jquery/jquery.git

How to I run git gc recursively in all repos inside /git?

I would prefer to use a shell script to iterate over the repositories: If that directory is not a valid git repository, do not run git gc.

David Cain
  • 16,484
  • 14
  • 65
  • 75
linquize
  • 19,828
  • 10
  • 59
  • 83

3 Answers3

41

You could try something like:

find /git -name '*.git' -execdir sh -c 'cd {} && git gc' \;

This will find every directory matching *.git under /git, cd into it, and run git gc.

Bob the Angry Coder
  • 1,284
  • 11
  • 5
  • 1
    Thanks! I got some of the following errors: `sh: line 0: cd: ./.git: Not a directory`, probably because .git can also be a file if it represents a submodule. – Paul Aug 11 '18 at 13:56
  • that command complains that its insecure blah blah `find . -name "*.git" -exec bash -c 'cd {} && git gc' printf {} ';'` works but both of them dont work for directories with spaces in them.... (if `find` returns a folder with spaces on the name its not escaped and causes problems) – Rodrigo Graça Dec 16 '19 at 17:39
1

On some systems (ie. OSX) the for loop treats spaces as delimiters, breaking directory names that contain spaces. Set IFS to only use linebreaks \n for this to work properly, and reset to default when done:

oldIFS=$IFS; IFS=$'\n'; for line in $(find /git -name '*.git'); do (echo $line; cd $line; git gc); done; IFS=$oldIFS
Ducktales
  • 11
  • 3
0

Since find (version 4.1) from msysgit is too old, -execdir option is not supported.

We have to write a for loop instead.

for line in $(find /git -name '*.git'); do (cd $line && git gc); done
linquize
  • 19,828
  • 10
  • 59
  • 83