1

I want compress all the git repositories on my computer (say in ~). I.e., for each directory {}, that contains directory or file (in case of submodules) named .git, I want to execute git gc --aggressive --git-dir={}.

I tried the following:

/bin/find /c/libs/boost/ -name '.git' -print -exec git --git-dir=dirname {} gc --aggressive \;

but output consist of plenty of fatal: Not a git repository: 'dirname /c/libs/boost/.git' etc. What should I do to use dirname command correctly? Or something else to achieve desired effect?

1
  • Also I tried bash -c "" with \$\(dirname {}\) and `dirname {}`, but without any positive effect. Commented Dec 26, 2013 at 19:31

3 Answers 3

2

You're passing the word dirname as the argument to --git-dir.

With GNU or FreeBSD find, the -execdir action executes a command in the directory containing the matching file.

find /c/libs/boost/ -name '.git' -execdir git gc --aggressive \;

If your find command doesn't have -execdir, you can pass the .git directory as an argument to --git-dir.

find /c/libs/boost/ -name '.git' -exec git --git-dir {} gc --aggressive \;

In general, if you need shell expansion, invoke a shell explicitly, with sh -c 'shell command'. Don't attempt to perform any interpolation in the shell command, as that would fail with file names containing special characters. Pass the match(es) as an argument to the shell script. Note that after sh -c 'shell command', the first argument is $0, and the other arguments ($1, $2, …) collectively form "$@".

find /c/libs/boost/ -name '.git' -exec sh -c 'cd "${0%/.}" && git gc --aggressive' {} \;
find /c/libs/boost/ -name '.git' -exec sh -c 'for dir; do cd "${dir%/.}" && git gc --aggressive' _  {} +
1
for location in $( find -type d -name .git /path/to/base/of/search ); do
    if pushd "$location/.."; then
        git gc --aggressive --git-dir=.
        popd
    fi
done
5
  • Ough. Too wordy. I think about 1 loc solution. Commented Dec 26, 2013 at 19:39
  • It can be done on one line; I just broke it up so that you could easily follow the logic.
    – DopeGhoti
    Commented Dec 26, 2013 at 20:12
  • I know that you can delimit lines by means of ;, but this is not the approach. I know, that many languages supports such style (one line of code), but I imply single statement here. Commented Dec 26, 2013 at 20:31
  • Won't work if a directory contains spaces or other special characters. Parsing the output of find is not a good idea, -exec is easier to control. Commented Dec 26, 2013 at 23:46
  • True, @Gilles, but I maintain that if you're putting spaces or other special characters in your directory or file names, you're doing it wrong. (:
    – DopeGhoti
    Commented Dec 27, 2013 at 0:15
1

I find solution (works on msys):

/bin/find /c/libs/boost/ -name '.git' -print -exec bash -c 'cd $(dirname {}) ; git gc --aggressive' \; 2>&1 | tee git-gc.log
2
  • Note, that submodule directories contains .git files, unlike bare or working-tree repositories contains .git directories. Commented Dec 26, 2013 at 20:24
  • @DopeGhoti: Instead, I want to see all the git repositories. Commented Dec 26, 2013 at 20:33

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.