Efficiently run git commands across multiple repositories in parallel
Before:
cd project1 && git pull && cd ..
cd project2 && git pull && cd ..
cd project3 && git pull && cd ..
# ... repeat for dozens of repositoriesAfter:
gih pull # Done! All repositories updated in parallelIt is just a tool to do this. It does nothing else.
I created it because I was tired of managing dozens of microservice repositories for the projects I work on.
- 🚀 Parallel Execution: Execute git commands across multiple repositories simultaneously
- 🎯 Filtering: Use regex patterns to target specific repositories or exclude others
- 🔍 Directory Discovery: Automatically finds all git repositories in subdirectories
- ⚡ High Performance: Leverages Go's goroutines for maximum efficiency
- ⏰ Configurable Timeouts: Aborts immediately at the specified timeouts
go install github.com/takecy/git-here/gih@latestVerify installation:
gih version- Download the latest binary from the Release Page for your platform
- Extract and place the binary in your
$PATH - Make it executable:
chmod +x gih(Unix-like systems)
Supported Platforms:
- Linux (amd64, arm64)
- macOS (amd64, arm64)
- Windows (amd64, arm64)
gih [options] <git_command> [git_options]# Pull all repositories in current directory
gih pull
# Check status of all repositories
gih status
# Fetch from all remotes
gih fetch --allUpdate all repositories:
gih pull
# Equivalent to running 'git pull' in each repository directoryCheck status across all repositories:
gih status --short
# Shows git status for each repository in a compact formatFetch from all remotes:
gih fetch --all --prune
# Fetches from all remotes and prunes deleted branchesTarget specific repositories with regex:
# Only operate on repositories matching the pattern
gih --target "^(frontend|backend)" pull
# Only pulls repositories starting with 'frontend' or 'backend'
gih --target ".*-service$" status
# Only checks status of repositories ending with '-service'Exclude repositories:
# Ignore specific repositories
gih --ignore "^(test|temp)" pull
# Pulls all repositories except those starting with 'test' or 'temp'
gih --ignore ".*-wip$" status
# Check status of all repositories except those ending with '-wip'Combine target and ignore patterns:
gih --target "^microservice" --ignore "deprecated" pull
# Pull only microservice repositories that aren't deprecatedSet custom timeout:
# Increase timeout for slow operations
gih --timeout 60s pull
# Each repository operation will timeout after 60 seconds
gih --timeout 5m clone --recursive
# For operations that might take longerControl concurrency:
# Limit concurrent operations (useful for resource-constrained environments)
gih -c 2 pull
# Only run 2 operations in parallel
# Maximize parallelism (default is number of CPU cores)
gih -c 20 fetch
# Run up to 20 operations in parallelMicroservices maintenance:
# Update all microservices before deployment
gih --target ".*-service$" pull
# Check which microservices have uncommitted changes
gih --target ".*-service$" status --porcelainOpen source contribution workflow:
# Fetch latest changes from all your forks
gih fetch upstream
# Check status of all your projects
gih status --shortMonorepo-adjacent development:
# Update all related projects in your workspace
gih --ignore "node_modules|\.venv" pullgit-here discovers repositories based on this structure:
workspace/
├── .hidden-repo/ # ❌ Ignored (hidden directories starting with .)
├── project-a/ # ✅ Target (contains .git)
│ └── .git/
├── project-b/ # ✅ Target (contains .git)
│ └── .git/
├── non-git-dir/ # ❌ Ignored (no .git directory)
│ └── some-file.txt
└── nested/
└── deep-repo/ # ❌ Not target (only scans direct subdirectories)
└── .git/
Key Rules:
- Only direct subdirectories are scanned (not deeply nested)
- Directories must contain a
.gitfolder to be considered repositories - Hidden directories (starting with
.) are automatically ignored
| Option | Description | Default | Example |
|---|---|---|---|
--target |
Regex pattern to target specific directories | "" (all) |
--target "^api" |
--ignore |
Regex pattern to ignore directories | "" (none) |
--ignore "test$" |
--timeout |
Timeout per repository operation | 20s |
--timeout 60s |
-c |
Concurrency level (max parallel operations) | CPU cores | -c 4 |
Built-in:
gih version- Show version information and check for updatesgih- Show help message
Git Commands: Any valid git command can be used:
gih pull- Pull latest changesgih fetch --all- Fetch from all remotesgih status --short- Show compact statusgih push origin main- Push to origin/maingih checkout -b feature/new- Create and checkout new branchgih commit -m "message"- Commit changes- And many more...
0- Success (all operations completed)1- General error (invalid arguments, setup issues)2- Some repositories failed (partial success)
- Go 1.24 or later
# Clone the repository
git clone https://github.com/takecy/git-here.git
cd git-here
# Build for development
make build
# Run tests
make test
# Run linter
make lintmake build # Build development binary (gih_dev)
make install # Install production binary
make test # Run all tests with race detection
make lint # Run golangci-lint
make tidy # Run go mod tidy
make update # Update all dependencies# Build and test your changes
make build
make test
make lint
# Test manually with debug output
DEBUG=* go run gih/main.go status
# Test with the development binary
./gih_dev statusThe project is structured into several key packages:
gih/main.go- CLI entry point and argument parsingsyncer/- Core orchestration logicsyncer.go- Main execution controllerdir.go- Repository discoverygit.go- Git command execution
printer/- Output formatting and coloring
We welcome contributions! Here's how to get started:
- Use the GitHub Issues page
- Include your OS, Go version, and git-here version
- Provide steps to reproduce the issue
- Include relevant command output
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes with tests
- Run the full test suite:
make test lint - Commit your changes:
git commit -m 'Add amazing feature' - Push to your branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow standard Go conventions
- Run
make lintbefore submitting - Add tests for new functionality
- Update documentation as needed
# Run all tests
make test
# Run specific package tests
go test -v ./syncer/
# Run with coverage
go test -cover ./...A: By design, git-here only scans direct subdirectories for performance and clarity. If you need to work with deeply nested repos, consider running git-here from different directory levels.
A: No, git-here is specifically designed for git commands. It expects git repositories and uses git-specific logic.
A: git-here uses your existing git configuration and SSH keys. Ensure your git setup works normally first.
A: Individual repository failures don't stop the entire operation. Failed repositories are reported, but git-here continues with the remaining repositories.
A: Currently, git-here uses command-line flags. Environment variable support may be added in future versions.
A: Run go install github.com/takecy/git-here/gih@latest or download the latest binary from the releases page.