Escuchar este post
Selecciona una voz y genera audio para escuchar este post
El Problema de las Dependencias Compartidas
En desarrollo profesional, es común encontrarse con esta situación: tienes código que necesitas compartir entre múltiples proyectos. No es una librería pública que publiques en npm o PyPI, sino código interno de tu organización.
Las opciones tradicionales presentan limitaciones:
- Copy-paste: Duplicación de código, pesadilla de mantenimiento
- Git submodules: Complejidad operacional, require sincronización manual constante
- Packages privados: Overhead de versionado y publicación para cambios menores
- Monorepos: Reestructuración completa de la arquitectura del proyecto
Git Subtrees: Una Alternativa Elegante
Git Subtrees resuelve este problema permitiendo incluir un repositorio completo como subdirectorio de otro, manteniendo:
- Bidireccionalidad: Lee cambios del repositorio origen y contribuye de vuelta
- Transparencia: Los archivos están directamente en tu working directory
- Simplicidad operacional: No requiere inicialización especial para nuevos desarrolladores
Arquitectura del Ejemplo
proyecto-principal/
├── src/
│ ├── app/
│ └── shared-ui/ ← Git Subtree (repo independiente)
│ ├── components/
│ ├── hooks/
│ └── utils/
└── package.json
El directorio shared-ui/
es simultáneamente:
- Parte integral de
proyecto-principal
- Un repositorio independiente con su propia historia y colaboradores
Operaciones Fundamentales
1. Integración Inicial (subtree add
)
git subtree add --prefix=src/shared-ui git@github.com:org/shared-ui.git main --squash
Parámetros críticos:
--prefix
: Path de destino en el repositorio host--squash
: Colapsa el historial del subtree en un merge commit únicomain
: Branch de referencia del repositorio remoto
Resultado: El contenido completo del repositorio remoto se integra como subdirectorio, manteniendo la capacidad de sincronización bidireccional.
2. Sincronización Entrante (subtree pull
)
git subtree pull --prefix=src/shared-ui git@github.com:org/shared-ui.git main --squash
Casos de uso:
- Integrar cambios desarrollados por otros teams
- Mantener consistencia con la versión canónica
- Resolver conflicts de sincronización
Comportamiento: Ejecuta un git fetch
+ git merge
especializado que respeta la estructura del subtree.
3. Contribución Upstream (subtree push
)
git subtree push --prefix=src/shared-ui git@github.com:org/shared-ui.git main
Proceso interno: Git extrae únicamente los commits que modificaron archivos dentro del prefix y los reaplica al repositorio de destino.
Consideración importante: A diferencia de pull
, push
no usa --squash
para preservar la granularidad de commits en el repositorio upstream.
Workflow de Desarrollo
Configuración Inicial
# Integrar dependencia compartida git subtree add --prefix=src/shared-ui git@github.com:org/shared-ui.git main --squash git push origin main
Ciclo de Desarrollo Iterativo
# 1. Sincronizar con upstream git subtree pull --prefix=src/shared-ui git@github.com:org/shared-ui.git main --squash # 2. Desarrollo local en el subtree vim src/shared-ui/components/Button.tsx git add src/shared-ui/ git commit -m "feat(shared-ui): implement dark mode variant" # 3. Integration en el proyecto host git push origin feature/dark-mode # 4. Contribución upstream (después del code review) git subtree push --prefix=src/shared-ui git@github.com:org/shared-ui.git main
Comparativa Técnica: Subtrees vs Alternativas
Git Subtrees
- Working Directory: ✅ Archivos nativos directamente en el repo
- Onboarding: ✅
git clone
único incluye todo el código - Desarrollo Bidireccional: ✅ Push y pull nativos sin configuración adicional
- Historia del Proyecto: ❌ Se infla con commits del subtree
- Granularidad de Updates: ⚠️ Solo a nivel de commit individual
Git Submodules
- Working Directory: ❌ Referencias indirectas, archivos separados
- Onboarding: ❌ Requiere
git submodule init/update
manual - Desarrollo Bidireccional: ⚠️ Posible pero workflow complejo
- Historia del Proyecto: ✅ Mantiene historia limpia y separada
- Granularidad de Updates: ✅ Control preciso con SHA específicos
Package Registry (npm/PyPI)
- Working Directory: ✅ Archivos nativos después de instalación
- Onboarding: ✅
npm install
o equivalente resuelve todo - Desarrollo Bidireccional: ❌ Requiere ciclo completo de publishing
- Historia del Proyecto: ✅ Historia limpia, sin dependencias
- Granularidad de Updates: ✅ Semantic versioning con control granular
Configuración Avanzada
Automatización con Git Aliases
# ~/.gitconfig [alias] st-add = "!f() { git subtree add --prefix=\"$1\" \"$2\" main --squash; }; f" st-sync = "!f() { git subtree pull --prefix=\"$1\" \"$2\" main --squash; }; f" st-push = "!f() { git subtree push --prefix=\"$1\" \"$2\" main; }; f" # Uso: # git st-add src/shared-ui git@github.com:org/shared-ui.git # git st-sync src/shared-ui git@github.com:org/shared-ui.git # git st-push src/shared-ui git@github.com:org/shared-ui.git
CI/CD Integration
# .github/workflows/subtree-sync.yml name: Sync Subtrees on: schedule: - cron: '0 9 * * MON' # Weekly sync workflow_dispatch: jobs: sync: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: token: ${{ secrets.SUBTREE_TOKEN }} - name: Sync shared-ui run: | git subtree pull --prefix=src/shared-ui \ git@github.com:org/shared-ui.git main --squash || true - name: Create PR if changes run: | if [[ -n $(git status --porcelain) ]]; then gh pr create --title "chore: sync subtree dependencies" \ --body "Automated subtree synchronization" fi
Caso de Estudio: Design System Compartido
Contexto Empresarial
Tu organización mantiene un design system (@company/design-tokens
) usado por múltiples productos:
- Web App (React/TypeScript)
- Mobile App (React Native)
- Marketing Site (Next.js)
Implementación con Subtrees
1. Setup Inicial en cada Proyecto
# Web App git subtree add --prefix=src/design-system git@github.com:company/design-tokens.git main --squash # Mobile App git subtree add --prefix=shared/design-system git@github.com:company/design-tokens.git main --squash # Marketing Site git subtree add --prefix=design/tokens git@github.com:company/design-tokens.git main --squash
2. Desarrollo Cross-Project
# Designer modifica tokens en Web App vim src/design-system/tokens/colors.json git commit -m "feat(tokens): add dark mode palette" # Contribuir cambios al design system central git subtree push --prefix=src/design-system git@github.com:company/design-tokens.git main # Otros proyectos sincronizan los cambios git subtree pull --prefix=shared/design-system git@github.com:company/design-tokens.git main --squash
Criterios de Adopción
✅ Casos de Uso Óptimos
- Internal libraries: Código propietario compartido entre proyectos
- Cross-team collaboration: Múltiples equipos contribuyen al mismo código base
- Rapid iteration: Cambios frecuentes que requieren feedback inmediato
- Monorepo alternative: Compartir código sin reestructurar completamente
❌ Anti-patterns
- Third-party dependencies: Usa package managers (npm, pip, cargo)
- Large binary assets: Git no está optimizado para archivos grandes
- Complex branching: Subtrees funcionan mejor con workflows lineales
- High-security environments: La bidireccionalidad puede crear vectores de ataque
Reference Card
# Core Operations git subtree add --prefix=PATH REMOTE BRANCH --squash # Initial integration git subtree pull --prefix=PATH REMOTE BRANCH --squash # Sync downstream git subtree push --prefix=PATH REMOTE BRANCH # Contribute upstream # Management git log --grep="git-subtree-dir: PATH" # Subtree history git subtree merge --prefix=PATH --squash COMMIT # Manual merge
Nota técnica: Los subtrees usan .git/subtree-cache
para optimizar operaciones repetidas. No requiere configuración manual pero puede consumir espacio de disco en proyectos grandes.
Abrazo. Bliss. 🤓

Aprende en 5 minutos qué es HTML y cuando utilizar cada una de sus etiquetas
Checa este otro Post
