Claude Code Multi-Repository Project Management
Table of Contents
- Cross-Repository Refactoring Techniques
- Maintaining Consistency Across Microservices
- Dependency Update Coordination
- Shared Configuration Management
- Monorepo vs Polyrepo Best Practices
- Git Submodules and Subtrees Usage
- Cross-Repo Search and Replace Patterns
- Repository Synchronization Strategies
Cross-Repository Refactoring Techniques
Modern Tools and Approaches
1. Composite Builds with Gradle
The Gradle Composite Builds feature enables treating separate multi-projects as a single cohesive build:
// settings.gradle
includeBuild('../common-library')
includeBuild('../service-a')
includeBuild('../service-b')This approach provides:
- Cross-repository IDE experience with IntelliJ IDEA integration
- Convenient code navigation across repositories
- Cross-multiproduct refactoring capabilities
2. Moderne Platform for Large-Scale Refactoring
Moderne leverages lossless semantic tree (LST) representations and OpenRewrite recipes:
# Example OpenRewrite recipe
type: specs.openrewrite.org/v1beta/recipe
name: com.example.MigrateToJava17
recipeList:
- org.openrewrite.java.migrate.Java8toJava11
- org.openrewrite.java.migrate.Java11toJava17Common use cases:
- Language version migrations (Java 8 to Java 17)
- Framework version migrations (Spring Boot, JUnit)
- Technology platform migrations (Cloud Foundry to Kubernetes)
3. AI-Assisted Cross-Repository Navigation
Tools like Sourcegraph Cody provide:
- Understanding of cross-repository dependencies
- Inline suggestions for modularization
- Context-aware refactoring recommendations
Best Practices
-
Start with Documentation
- Understand why code exists before refactoring
- Document the history and rationale
- Map out dependencies across repositories
-
Temporary Repository Consolidation
# Create temporary consolidated repo git init temp-refactor cd temp-refactor # Add all repositories as subdirectories git subtree add --prefix=service-a https://github.com/org/service-a main git subtree add --prefix=service-b https://github.com/org/service-b main # Perform refactoring # Split back when complete -
Incremental Changes
- Break down refactoring into bite-sized modifications
- Maintain working state between changes
- Use feature flags for gradual rollout
Maintaining Consistency Across Microservices
Key Consistency Patterns
1. Saga Pattern
Manages distributed transactions across microservices:
// Orchestration-based Saga example
class OrderSaga {
async execute(order) {
try {
await paymentService.charge(order);
await inventoryService.reserve(order);
await shippingService.schedule(order);
} catch (error) {
// Compensating transactions
await this.rollback(order, error);
}
}
}Implementation frameworks:
- Camunda
- Apache Camel
- Axon Framework
2. Event Sourcing
Store data changes as a series of events:
// Event sourcing example
class OrderAggregate {
applyEvent(event) {
switch(event.type) {
case 'OrderCreated':
this.status = 'pending';
break;
case 'PaymentReceived':
this.paid = true;
break;
}
}
}3. CQRS (Command Query Responsibility Segregation)
Separate read and write models:
// Command model
interface CreateOrderCommand {
customerId: string;
items: OrderItem[];
}
// Query model
interface OrderReadModel {
orderId: string;
customerName: string;
totalAmount: number;
status: string;
}Best Practices for 2024
-
Idempotency
// Idempotent operation example async processPayment(paymentId, amount) { const existing = await this.findPayment(paymentId); if (existing) return existing; return await this.createPayment(paymentId, amount); } -
Event Monitoring
- Use distributed tracing (Jaeger, Zipkin)
- Implement event stores with audit logs
- Set up alerting for failed compensations
-
Avoid Synchronous Calls
- Prefer async messaging (RabbitMQ, Kafka)
- Use circuit breakers for necessary sync calls
- Implement timeouts and retries
Dependency Update Coordination
Major Tools
1. Renovate Bot
// renovate.json configuration
{
"extends": ["config:base"],
"packageRules": [
{
"matchRepositories": ["org/service-*"],
"groupName": "microservices",
"schedule": ["after 10pm on sunday"]
}
],
"prConcurrentLimit": 3,
"automerge": true,
"automergeType": "pr"
}Features:
- Supports 90+ package managers
- Highly configurable
- Platform agnostic (runs as Docker container)
2. Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
production-dependencies:
dependency-type: "production"
development-dependencies:
dependency-type: "development"Features:
- Native GitHub integration
- Grouped updates support
- Security vulnerability detection
3. Custom Coordination Scripts
#!/bin/bash
# update-dependencies.sh
REPOS=("service-a" "service-b" "service-c")
for repo in "${REPOS[@]}"; do
cd "$repo"
npm update shared-library@latest
git add package.json package-lock.json
git commit -m "chore: update shared-library"
git push origin update-shared-library
gh pr create --title "Update shared-library" --body "Automated update"
cd ..
doneBest Practices
-
Grouped Updates
- Group related dependencies
- Coordinate updates across repositories
- Use consistent versioning strategies
-
Review Process
- Establish clear ownership for reviews
- Automate testing for dependency updates
- Use staging environments for validation
-
Timing Strategy
- Schedule updates during low-traffic periods
- Batch updates to reduce noise
- Implement gradual rollout strategies
Shared Configuration Management
Strategies
1. Separate Configuration Repository
# config-repo/base/database.yml
production:
host: ${DB_HOST}
port: 5432
pool: 20
# service-a/config/database.yml
imports:
- git::https://github.com/org/config-repo//base/database.yml2. GitOps Approach
# platform-config/namespaces/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- target:
kind: ConfigMap
name: app-config
patch: |-
- op: replace
path: /data/environment
value: production3. Centralized Configuration Service
// config-service/index.js
class ConfigService {
async getConfig(service, environment) {
const baseConfig = await this.loadBase(service);
const envConfig = await this.loadEnvironment(service, environment);
return merge(baseConfig, envConfig);
}
}Best Practices
-
Version Control Everything
- Treat configuration as code
- Use semantic versioning for configs
- Maintain change history
-
Environment Separation
config-repo/ ├── base/ │ ├── app.yml │ └── database.yml ├── environments/ │ ├── dev/ │ ├── staging/ │ └── production/ -
Access Control
- Use CODEOWNERS files
- Implement RBAC for sensitive configs
- Audit configuration changes
Monorepo vs Polyrepo Best Practices
Comparison Matrix
| Aspect | Monorepo | Polyrepo |
|---|---|---|
| Code Sharing | Trivial | Requires packages |
| Atomic Changes | Easy | Complex coordination |
| CI/CD | Complex setup | Simple per-repo |
| Access Control | Challenging | Granular |
| Tooling | Specialized required | Standard tools work |
| Scaling | Eventually problematic | No limits |
Monorepo Best Practices
-
Use Modern Tooling
// nx.json { "tasksRunnerOptions": { "default": { "runner": "@nrwl/nx-cloud", "options": { "cacheableOperations": ["build", "test", "lint"], "parallel": true } } } } -
Implement Efficient CI/CD
# Only build affected projects - name: Build affected run: nx affected:build --base=origin/main -
Structure for Scale
monorepo/ ├── apps/ │ ├── web-app/ │ └── mobile-app/ ├── libs/ │ ├── shared-ui/ │ └── common-utils/ └── tools/ └── workspace-scripts/
Polyrepo Best Practices
-
Standardize Repository Structure
service-template/ ├── .github/ │ └── workflows/ ├── src/ ├── tests/ ├── Dockerfile └── README.md -
Implement Shared Libraries
// package.json { "dependencies": { "@company/shared-lib": "^2.1.0", "@company/auth-lib": "^1.5.0" } } -
Coordinate Releases
# release-coordinator.sh ./scripts/update-version.sh 2.0.0 ./scripts/create-releases.sh ./scripts/update-dependencies.sh
Git Submodules and Subtrees Usage
Git Submodules
When to Use
- External dependencies with specific versions
- Separate repository access control needed
- Component-based development
Example Usage
# Add submodule
git submodule add https://github.com/org/shared-lib libs/shared
git commit -m "Add shared library submodule"
# Update submodule
git submodule update --remote libs/shared
git add libs/shared
git commit -m "Update shared library"
# Clone with submodules
git clone --recurse-submodules https://github.com/org/main-projectGit Subtrees
When to Use
- Need full history in main repository
- Simpler workflow for team members
- System-based development
Example Usage
# Add subtree
git subtree add --prefix=vendor/shared \
https://github.com/org/shared-lib main --squash
# Pull updates
git subtree pull --prefix=vendor/shared \
https://github.com/org/shared-lib main --squash
# Push changes back
git subtree push --prefix=vendor/shared \
https://github.com/org/shared-lib feature-branchComparison
| Feature | Submodules | Subtrees |
|---|---|---|
| Repository Size | Smaller (links) | Larger (full copy) |
| Update Process | Manual | Integrated |
| Learning Curve | Steeper | Minimal |
| Push Changes | Easy | More complex |
| Metadata | .gitmodules | None |
Cross-Repo Search and Replace Patterns
Tools and Techniques
1. Moderne Platform with OpenRewrite
# rewrite.yml
type: specs.openrewrite.org/v1beta/recipe
name: com.example.UpdateApiEndpoints
recipeList:
- org.openrewrite.java.ChangeMethodName:
methodPattern: "com.example.api.* getUser(..)"
newMethodName: "fetchUser"2. IDE-Based Solutions
IntelliJ IDEA Structural Search and Replace:
// Search template
$Instance$.$MethodCall$($Arguments$)
// Replace template
$Instance$.newMethodName($Arguments$)3. Script-Based Approach
#!/bin/bash
# cross-repo-replace.sh
PATTERN="oldFunction"
REPLACEMENT="newFunction"
REPOS=("service-a" "service-b" "service-c")
for repo in "${REPOS[@]}"; do
cd "$repo"
# Use ripgrep for finding
rg -l "$PATTERN" | while read file; do
sed -i "s/$PATTERN/$REPLACEMENT/g" "$file"
done
# Create PR
git checkout -b "refactor-$PATTERN"
git add -A
git commit -m "refactor: replace $PATTERN with $REPLACEMENT"
git push origin "refactor-$PATTERN"
gh pr create --title "Refactor: $PATTERN → $REPLACEMENT"
cd ..
doneBest Practices
-
Test Thoroughly
# Dry run first rg "$PATTERN" --stats -
Use AST-Based Tools
- More accurate than text replacement
- Handles edge cases better
- Preserves code structure
-
Coordinate Changes
- Create tracking issue
- Use feature branches
- Deploy incrementally
Repository Synchronization Strategies
Strategy 1: Multiple Remotes
# Setup
git remote add github https://github.com/org/project.git
git remote add gitlab https://gitlab.com/org/project.git
# Sync workflow
git fetch github
git fetch gitlab
git checkout -b sync-branch github/main
git push gitlab sync-branchStrategy 2: Mirror Repository
# Create mirror
git clone --mirror https://github.com/org/source.git
cd source.git
# Setup push mirror
git remote set-url --push origin https://gitlab.com/org/mirror.git
# Sync
git fetch -p origin
git push --mirrorStrategy 3: Automated Synchronization
Using git-sync Tool
# git-sync configuration
sync:
- source:
url: https://github.com/org/source.git
branch: main
target:
url: https://gitlab.com/org/target.git
branch: main
conflict_resolution: source_winsUsing GitHub Actions
# .github/workflows/sync.yml
name: Sync Repositories
on:
push:
branches: [main]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Push to GitLab
run: |
git remote add gitlab https://oauth2:${{ secrets.GITLAB_TOKEN }}@gitlab.com/org/mirror.git
git push gitlab main --forceBest Practices
-
Conflict Resolution Strategy
- Define clear ownership rules
- Use prefix-based branching
- Automate conflict detection
-
Security Considerations
- Use deploy keys or tokens
- Avoid storing credentials in code
- Implement audit logging
-
Monitoring and Alerts
# monitoring/sync-health.yml checks: - name: sync_lag query: "time_since_last_sync > 3600" alert: true - name: sync_conflicts query: "unresolved_conflicts > 0" alert: true
Practical Examples and Scenarios
Scenario 1: Microservices API Update
# 1. Create tracking issue
gh issue create --title "API v2 Migration" --body "Migrate all services to API v2"
# 2. Update shared library
cd shared-api-lib
npm version major
git push --tags
# 3. Update services using Renovate grouping
# renovate.json in each service
{
"packageRules": [{
"matchPackageNames": ["@company/shared-api-lib"],
"groupName": "api-v2-migration"
}]
}
# 4. Coordinate deployment
kubectl rollout status deployment/service-a
kubectl rollout status deployment/service-bScenario 2: Security Patch Across Repositories
// security-patch.js
const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function applySecurityPatch() {
const repos = await getAffectedRepos();
for (const repo of repos) {
await createBranch(repo, 'security-patch');
await updateDependency(repo, 'vulnerable-lib', '2.0.1');
await createPR(repo, {
title: 'Security: Update vulnerable-lib',
body: 'Fixes CVE-2024-12345',
labels: ['security', 'priority-high']
});
}
}Scenario 3: Monorepo to Polyrepo Migration
# 1. Identify boundaries
nx graph # Visualize dependencies
# 2. Extract service
git subtree split --prefix=apps/service-a -b service-a-branch
# 3. Create new repository
gh repo create org/service-a
git remote add service-a https://github.com/org/service-a.git
git push service-a service-a-branch:main
# 4. Update references
find . -name "*.json" -exec sed -i 's|apps/service-a|@org/service-a|g' {} \;
# 5. Setup CI/CD
cp .github/workflows/template.yml ../service-a/.github/workflows/ci.ymlConclusion
Managing multiple repositories effectively requires a combination of:
- Right tooling (Renovate, Moderne, Git features)
- Clear strategies (consistency patterns, synchronization approaches)
- Best practices (incremental changes, automation, monitoring)
- Team coordination (review processes, documentation, communication)
The choice between monorepo and polyrepo, the selection of synchronization strategies, and the implementation of cross-repository operations should align with your organization’s scale, team structure, and technical requirements.
Key takeaways:
- Automate repetitive tasks with tools like Renovate and custom scripts
- Use event-driven architectures for microservices consistency
- Implement proper CI/CD strategies for both monorepo and polyrepo setups
- Choose between submodules and subtrees based on your workflow needs
- Leverage modern tools for cross-repository refactoring
- Maintain clear documentation and communication channels
Success in multi-repository management comes from finding the right balance between automation and control, standardization and flexibility, and independence and coordination.