16

I have several git repositories on my system and I want to list them all in terminal.

What I'm looking for is something like this:

/path/to/my/git/repo/1/ REPONAME1
/path/to/my/git/repo/2/ REPONAME2
/path/to/my/git/repo/3/ REPONAME3

If you can come up with how to show branch name and repo's status eg. [master] c:0 u:1 d:0, that would be great.

studiomohawk
  • 380
  • 1
  • 3
  • 12
  • 2
    This is a bit similar to http://stackoverflow.com/questions/2765253/git-status-across-multiple-repositories-on-a-mac where you can also find useful ideas. – VonC Feb 24 '11 at 07:35
  • Yes, it did help me a lot. Thank you for pointing that out. – studiomohawk Feb 25 '11 at 01:48

5 Answers5

13

To list all the git repositories you have on your system you can run the following command in a bash shell terminal (at the command line) and find them.

find / -name .git -type d -exec dirname {} \;
choket
  • 279
  • 4
  • 20
  • This is a reasonable first approximation, but misses a lot. Bare repositories will be missed, as will any repos that use a regular file named .git to specify a git directory. – William Pursell Feb 24 '11 at 14:34
  • *`C:\xampp\htdocs\rimedit>`* `find / -name .git -type d -exec dirname {} \` `"C:/Users/Jakub/AppData/Local/GitHub/PortableGit_fed20eba68b3e238e49a47cdfed0a45 783d93651/bin/find.exe":` **`missing argument to `-exec'`** – Tomáš Zato - Reinstate Monica Jan 13 '14 at 15:02
6

I found this more accurate than the find command and much faster. I'm sure it can be improved but it's a good start. Obviously your file database will need to be up-to-date before running this command. On linux systems you can do this by running sudo updatedb.

locate -br '\.git$' | rev | cut -c 6- | rev
l0b0
  • 48,420
  • 21
  • 118
  • 185
4

lsgit is a script that does this. It's essentially a wrapper around locate -br '^HEAD$'.

If there are multiple clones of the same repo on the local machine, it will indicate that those repos are related.

Dee Newcum
  • 888
  • 1
  • 8
  • 8
3

If you can come up with how to show branch name and repo's status

The idea is to:

First, chose any config key name you want.
For example: "list.repos"

Reinitialize the list, using git config --unset-all (in the global config file):

git config --global --unset-all list.repos

Then use either:

Redirect the result in a file 'list-repos.txt', then register those repositories, reading each line of the file:

while IFS="" read -r repo || [ -n "${repo}" ]
do
  git config --global --add list.repos ${repo}
done < list-repos.txt

Once your repositories are registered (as global git config values), it is trivial to loop over them using the new command git for-each-repo, executing any command you need.

With Git 2.30 (Q4 2020), a new command is introduced, initially to manage parts of "git maintenance"(man) and to ease writing crontab entries (and other scheduling system configuration) for it.

See commit 0016b61, commit 61f7a38, commit a4cb1a2 (15 Oct 2020), commit 2fec604, commit 0c18b70, commit 4950b2a, commit b08ff1f (11 Sep 2020), and commit 1942d48 (28 Aug 2020) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit 7660da1, 18 Nov 2020)

for-each-repo: run subcommands on configured repos

Signed-off-by: Derrick Stolee

It can be helpful to store a list of repositories in global or system config and then iterate Git commands on that list.
Create a new builtin that makes this process simple for experts.
We will use this builtin to run scheduled maintenance on all configured repositories in a future change.

The test is very simple, but does highlight that the "--" argument is optional.

git for-each-repo now includes in its man page:

git-for-each-repo(1)

NAME

git-for-each-repo - Run a Git command on a list of repositories

SYNOPSIS

[verse]
'git for-each-repo' --config=<config> [--] <arguments>

DESCRIPTION

Run a Git command on a list of repositories. The arguments after the known options or -- indicator are used as the arguments for the Git subprocess.

THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.

For example, we could run maintenance on each of a list of repositories stored in a maintenance.repo config variable using


git for-each-repo --config=maintenance.repo maintenance run

This will run git -C <repo> maintenance run for each value <repo> in the multi-valued config variable maintenance.repo.

OPTIONS

--config=<config>

Use the given config variable as a multi-valued list storing absolute path names. Iterate on that list of paths to run the given arguments.

These config values are loaded from system, global, and local Git config, as available. If git for-each-repo is run in a directory that is not a Git repository, then only the system and global config is used.

SUBPROCESS BEHAVIOR

If any git -C <repo> <arguments> subprocess returns a non-zero exit code, then the git for-each-repo process returns that exit code without running more subprocesses.

Each git -C <repo> <arguments> subprocess inherits the standard file descriptors stdin, stdout, and stderr.


With Git 2.30.1 (Q1 2021), "git for-each-repo --config=<var> <cmd>"(man) should not run <cmd> for any repository when the configuration variable <var> is not defined even once.

See commit 6c62f01 (08 Jan 2021) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit aa08688, 15 Jan 2021)

for-each-repo: do nothing on empty config

Reported-by: Andreas Bühmann
Helped-by: Eric Sunshine
Helped-by: Junio C Hamano
Signed-off-by: Derrick Stolee

'git for-each-repo --config=X'(man) should return success without calling any subcommands when the config key 'X' has no value.
The current implementation instead segfaults.

A user could run into this issue if they used 'git maintenance start'(man) to initialize their cron schedule using 'git for-each-repo --config=maintenance.repo ...'(man) but then using 'git maintenance unregister'(man) to remove the config option.
(Note: 'git maintenance stop'(man) would remove the config and remove the cron schedule.)

Add a simple test to ensure this works.
Use 'git help --no-such-option'(man) as the potential subcommand to ensure that we will hit a failure if the subcommand is ever run.

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • the perl and python repo-finders are kinda heavy for a oneliner, and at least the perl one gets it a bit wrong, it will miss valid repos. `find -name HEAD -execdir test -d refs -a -d objects \; -printf %h\\n` will do it, on Macs you need the brew `find` I think. You can use ``(IFS=$'\n'; find `locate */HEAD`…)`` etc to speed up locating repos that weren't cloned or inited since the last updatedb. – jthill Jan 17 '21 at 22:18
  • 1
    @jthill Agree. This answer is *not* about a one-liner approach. It is to illustrate the new command. – VonC Jan 17 '21 at 22:23
1

A wrapper around:
locate -br '^HEAD$' as done by Dee Newcum https://github.com/DeeNewcum/dotfiles/blob/master/bin/lsgit or else find . -name 'HEAD' as modified in https://gist.github.com/nrbray/a0ae8ec59d1fd1ae03e2947368096d2e

gives an alternative to searching for gits by the folder or filename alone.

[Not enough reputation to comment on Dee's answer, but I used his solution and it worked for me]

nrbray
  • 43
  • 7