LinuxCommandLibrary

git-for-each-repo

Run Git commands across multiple repositories

TLDR

Run maintenance on each of a list of repositories stored in the maintenance.repo user configuration variable

$ git for-each-repo --config maintenance.repo [maintenance run]
copy

Run git pull on each repository listed in a global configuration variable
$ git for-each-repo --config [global_configuration_variable] [pull]
copy

SYNOPSIS

git-for-each-repo [--path directory] --exec command [--dry-run] [--verbose] [--exclude pattern]

PARAMETERS

--path directory
    Specifies the root directory to begin searching for Git repositories. If omitted, the current working directory is used.

--exec command
    The shell command to execute within each discovered Git repository. This is typically a Git command (e.g., git status, git pull) or any other shell command.

--dry-run
    Performs a simulation: it lists the repositories that would be processed and the commands that would be executed, without actually running them.

--verbose
    Increases the verbosity of the output, showing additional details such as the path of each repository before executing the command.

--exclude pattern
    A pattern to exclude directories from the search for Git repositories. This can be useful to skip specific subdirectories or repositories.

DESCRIPTION

The git-for-each-repo command is not a standard Git utility, but rather a common pattern implemented as a custom shell script or part of a larger repository management tool. Its primary purpose is to automate tasks across multiple independent Git repositories located within a specified directory hierarchy.

Typically, this command works by recursively searching for Git repository directories (those containing a .git folder) starting from a given path. For each repository found, it then executes a user-defined shell command within that repository's working directory.

This functionality is incredibly useful for system administrators, developers managing monorepos without using Git submodules, or anyone needing to perform bulk operations like fetching updates, checking statuses, or analyzing branches across numerous projects. While its exact implementation can vary, the core idea remains consistent: simplify repetitive Git operations by iterating through a collection of repositories.

CAVEATS

This command is not a standard, officially distributed Git command. It is most often a custom script written by users or bundled with specific development environments. Therefore, its availability, exact syntax, and behavior can vary significantly depending on its implementation. Users should verify its source and functionality before relying on it, especially when executing arbitrary commands.

TYPICAL IMPLEMENTATION

Most implementations of git-for-each-repo use shell scripting to recursively find directories containing a .git subdirectory and then execute a command within each found directory. A common pattern involves find . -type d -name '.git' -print0 | xargs -0 -I {} sh -c 'cd "$(dirname {})" && '.

SECURITY CONSIDERATIONS

Since this command executes arbitrary shell commands within multiple directories, it's crucial to be aware of the security implications. Always ensure the source of the script is trusted and carefully review the --exec command to prevent unintended or malicious actions, especially when running with elevated privileges.

HISTORY

The concept behind git-for-each-repo emerged from the common need to manage and operate on multiple independent Git repositories within a single project directory or across a development environment. Lacking a built-in Git command for this specific purpose (beyond submodules), developers and system administrators began creating their own shell scripts. These scripts typically leverage standard Unix tools like find and xargs to locate Git repositories and execute commands within them. While no single official history exists, its widespread adoption as a custom script reflects a persistent user demand for streamlined multi-repository operations.

SEE ALSO

git submodule foreach(1), repo forall(1), find(1), xargs(1)

Copied to clipboard