Batch Clone & Pull Multiple Git Repos with a Bash Script
Automate cloning, checking out, and pulling multiple Git repositories at once using simple bash scripts — plus auto-generating a Maven parent POM for Java projects.
When you join a new company or get assigned to a new feature, you often need to clone multiple repositories — the main service plus several shared libraries. Doing this manually means typing git clone, cd, git checkout, git pull over and over. It gets old fast.
I ran into this exact problem working on Java microservices in banking, where a single project depended on 5+ library repos. So I wrote a few bash scripts to automate the entire setup in one command. Here's what I learned.
Bash Basics (Quick Recap)
If you're already comfortable with bash, skip to the Clone Script section.
Hello World
Create a file called hello.sh:
#!/bin/bash
echo "Hello World!"
Make it executable and run:
chmod +x hello.sh
./hello.sh
Variables
#!/bin/bash
name="Noka"
echo "Hello, $name!" # Output: Hello, Noka!
Parameters
Bash scripts accept positional arguments via $1, $2, etc.:
#!/bin/bash
echo "Hello, $1!"
./hello.sh Noka
# Output: Hello, Noka!
Conditionals
if [ "$folder" = "library" ]; then
echo "This is the library folder"
else
echo "Not the library folder"
fi
Loops
# Loop through all items in the current directory
for item in *; do
echo "$item"
done
Clone Multiple Repos
Here's the scenario: you need to clone a main project and several shared libraries into a structured folder:
project/
├── main-service/ ← main project
└── library/ ← shared libraries
├── common-utils/
├── auth-lib/
├── payment-lib/
└── notification-lib/
clone-source.sh
#!/bin/bash
# Colors for pretty output
GREEN='\033[1;32m'
BLUE='\033[1;34m'
NC='\033[0m' # No Color
LIB_DIR="library"
echo -e "${GREEN}=== Cloning source code ===${NC}"
# Clone main project
echo -e "${BLUE}[1/2] Cloning main service...${NC}"
git clone git@github.com:your-org/main-service.git
# Create library directory and clone shared libs
echo -e "${BLUE}[2/2] Cloning libraries...${NC}"
mkdir -p "$LIB_DIR"
cd "$LIB_DIR"
git clone git@github.com:your-org/common-utils.git
echo -e "${GREEN} ✓ common-utils${NC}"
git clone git@github.com:your-org/auth-lib.git
echo -e "${GREEN} ✓ auth-lib${NC}"
git clone git@github.com:your-org/payment-lib.git
echo -e "${GREEN} ✓ payment-lib${NC}"
git clone git@github.com:your-org/notification-lib.git
echo -e "${GREEN} ✓ notification-lib${NC}"
cd ..
echo -e "${GREEN}=== Clone complete! ===${NC}"
Usage:
chmod +x clone-source.sh
./clone-source.sh
Checkout All Repos to the Same Branch
When you need all repos on the same feature branch (e.g., dev or feature/payment-v2):
checkout-source.sh
#!/bin/bash
# Colors
RED='\033[1;31m'
GREEN='\033[1;32m'
BLUE='\033[1;34m'
NC='\033[0m'
BRANCH="$1"
LIB_DIR="library"
if [ -z "$BRANCH" ]; then
echo -e "${RED}Usage: ./checkout-source.sh <branch-name>${NC}"
exit 1
fi
echo -e "${BLUE}=== Checking out branch: ${BRANCH} ===${NC}"
for folder in */; do
# Remove trailing slash
folder="${folder%/}"
if [ "$folder" = "$LIB_DIR" ]; then
# Library folder — checkout each sub-folder
echo -e "${GREEN}📁 ${folder}/${NC}"
for sub_folder in "$folder"/*/; do
sub_folder="${sub_folder%/}"
sub_name=$(basename "$sub_folder")
cd "$sub_folder"
echo -e " ${BLUE}→ ${sub_name}${NC}"
git checkout "$BRANCH" 2>/dev/null || echo -e " ${RED} ⚠ Branch not found: ${BRANCH}${NC}"
cd ../..
done
elif [ -d "$folder/.git" ]; then
# Regular git repo
echo -e "${GREEN}📁 ${folder}${NC}"
cd "$folder"
git checkout "$BRANCH" 2>/dev/null || echo -e " ${RED}⚠ Branch not found: ${BRANCH}${NC}"
cd ..
fi
done
echo -e "${BLUE}=== Checkout complete ===${NC}"
Usage:
chmod +x checkout-source.sh
./checkout-source.sh dev
./checkout-source.sh feature/payment-v2
Pull All Repos at Once
Same pattern — loop through all repos and pull the latest changes:
pull-source.sh
#!/bin/bash
# Colors
GREEN='\033[1;32m'
BLUE='\033[1;34m'
RED='\033[1;31m'
NC='\033[0m'
LIB_DIR="library"
echo -e "${BLUE}=== Pulling latest changes ===${NC}"
for folder in */; do
folder="${folder%/}"
if [ "$folder" = "$LIB_DIR" ]; then
echo -e "${GREEN}📁 ${folder}/${NC}"
for sub_folder in "$folder"/*/; do
sub_folder="${sub_folder%/}"
sub_name=$(basename "$sub_folder")
cd "$sub_folder"
echo -e " ${BLUE}→ ${sub_name}${NC}"
git pull 2>/dev/null || echo -e " ${RED} ⚠ Pull failed${NC}"
cd ../..
done
elif [ -d "$folder/.git" ]; then
echo -e "${GREEN}📁 ${folder}${NC}"
cd "$folder"
git pull 2>/dev/null || echo -e " ${RED}⚠ Pull failed${NC}"
cd ..
fi
done
echo -e "${BLUE}=== Pull complete ===${NC}"
Bonus: Auto-Generate Maven Parent POM
If you're working with Java Maven projects, you can auto-generate a parent pom.xml that includes all cloned repos as modules. This lets you open everything in IntelliJ as a single project.
generate-pom.sh
#!/bin/bash
GREEN='\033[1;32m'
BLUE='\033[1;34m'
NC='\033[0m'
LIB_DIR="library"
POM_FILE="pom.xml"
echo -e "${BLUE}=== Generating parent pom.xml ===${NC}"
# Write POM header
cat > "$POM_FILE" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hoclamdev</groupId>
<artifactId>workspace-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
EOF
# Add modules dynamically
ROOT_PATH="$(pwd)/"
for folder in */; do
folder="${folder%/}"
if [ "$folder" = "$LIB_DIR" ]; then
for sub_folder in "$folder"/*/; do
sub_folder="${sub_folder%/}"
echo " <module>${sub_folder}</module>" >> "$POM_FILE"
echo -e " ${GREEN}✓ ${sub_folder}${NC}"
done
elif [ -d "$folder/.git" ] && [ -f "$folder/pom.xml" ]; then
echo " <module>${folder}</module>" >> "$POM_FILE"
echo -e " ${GREEN}✓ ${folder}${NC}"
fi
done
# Write POM footer
cat >> "$POM_FILE" << 'EOF'
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
EOF
echo -e "${BLUE}=== Generated ${POM_FILE} ===${NC}"
echo ""
echo "Open IntelliJ → File → Open → select the generated pom.xml"
This produces a pom.xml like:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.hoclamdev</groupId>
<artifactId>workspace-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>main-service</module>
<module>library/common-utils</module>
<module>library/auth-lib</module>
<module>library/payment-lib</module>
<module>library/notification-lib</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Tip: Open this
pom.xmlin IntelliJ IDEA → it will import all modules as a single workspace, with cross-module navigation and dependency resolution.
Complete Workflow
Here's the full workflow to set up a new project in one go:
# 1. Clone everything
./clone-source.sh
# 2. Checkout the right branch
./checkout-source.sh dev
# 3. Generate parent POM (Java projects)
./generate-pom.sh
# 4. Open in IntelliJ and start coding! 🎉
For daily development:
# Pull latest changes across all repos
./pull-source.sh
Key Takeaways
- Automate repetitive Git workflows — if you're typing the same commands across 5+ repos, write a script.
- Use colored output — it makes scripts easier to debug and looks professional.
- Add error handling — check if branches exist before switching, handle pull failures gracefully.
- Generate parent POMs — for Java projects, a multi-module POM lets IntelliJ treat everything as one workspace.
- Keep scripts in the project root — commit them to Git so your team can use them too.
Thanks for reading! If you're working with multiple repos in your daily workflow, these scripts can save you a lot of time. Also check out my Ubuntu post-install guide and LazyVim + Tmux setup for more dev environment tips. 🚀