¿Alguna vez has perdido horas configurando tu terminal o editor tras cambiar de computadora? Los dotfiles, esos archivos ocultos como .bashrc o .gitconfig, guardan tus personalizaciones, pero gestionarlos a mano es un caos. GNU Stow simplifica todo: organiza tus configuraciones en un repositorio central y usa enlaces simbólicos para sincronizarlas en minutos.
¿Qué es Dotfiles?
Los dotfiles son archivos ocultos en sistemas Unix (Linux, macOS) que empiezan con un punto (ej., .zshrc, .gitconfig, .config/nvim). Almacenan configuraciones personalizadas para tu terminal, editor de código o gestor de ventanas. Por ejemplo, .bashrc define alias y variables de entorno, mientras que .vimrc ajusta tu editor Vim. Estos archivos son el corazón de tu flujo de trabajo, ya que personalizan tus herramientas favoritas.
Tener dotfiles bien organizados te ahorra horas al replicar tu entorno en nuevas máquinas. Imagina configurar tu shell o editor desde cero tras reinstalar tu sistema: ¡es tedioso! Con una gestión adecuada, puedes clonar tus configuraciones y tener todo listo rápidamente. Esto es importante para desarrolladores que trabajan en múltiples dispositivos o entornos como servidores y laptops.
Problemas de la Gestión Manual
Copiar dotfiles manualmente o usar scripts caseros es lento y arriesgado. Puedes sobrescribir archivos, olvidar configuraciones o perderlas en una reinstalación. Por ejemplo, mover .zshrc a otra máquina sin un sistema organizado puede causar errores si las versiones del software difieren. GNU Stow soluciona esto al centralizar tus archivos y crear enlaces simbólicos automáticamente, manteniendo todo sincronizado.
¿Qué es GNU Stow?
GNU Stow es un gestor de granjas de enlaces simbólicos (symlink farm manager) que permite administrar múltiples paquetes de software o conjuntos de archivos de configuración de manera organizada. Concepto principal:
Instalar cada paquete en su propio árbol de directorios
↓
Usar enlaces simbólicos para que aparezcan en un árbol común
↓
Administrar fácilmente cada paquete de forma independiente
Problema original:
Solución con Stow:
Gestión de Dotfiles
Aunque Stow fue diseñado para software, hoy en día su uso principal es gestionar dotfiles:
Ventajas:
- Mantener dotfiles organizados por aplicación
- Sincronizar con Git
- Instalar/desinstalar configuraciones selectivamente
- Mantener backups sin perder estructura
- Compartir configuraciones entre máquinas
- Control de versiones granular
Comparación: Antes vs Después de Stow
Sin Stow:
Con Stow:
~/dotfiles/ # Stow directory
├── nvim/ # Package
│ └── .config/
│ └── nvim/
├── kitty/ # Package
│ └── .config/
│ └── kitty/
└── zsh/ # Package
├── .zshrc
└── .zshenv
# Ventajas:
# - Cada aplicación es un "paquete"
# - Fácil stow/unstow selectivo
# - Git maneja cada paquete independientemente
# - Estructura clara y mantenible1 Instalación
1.1 Linux
Ubuntu/Debian:
Arch Linux:
Fedora/RHEL:
openSUSE:
1.2 macOS
1.3 Desde Fuente
1.4 Verificar Instalación
2 Conceptos Fundamentales
2.1 Terminología Clave
2.1.1 Package (Paquete)
Una colección relacionada de archivos y directorios que administras como una unidad.
2.1.2 Target Directory (Directorio Objetivo)
El directorio raíz donde quieres que aparezcan instalados tus paquetes.
2.1.3 Stow Directory (Directorio Stow)
El directorio raíz que contiene todos tus paquetes en subdirectorios separados.
2.1.4 Installation Image (Imagen de Instalación)
La estructura de archivos y directorios requerida por un paquete, relativa al target directory.
2.1.5 Symlink (Enlace Simbólico)
Un archivo especial que apunta a otro archivo o directorio.
Tipos de symlinks:
- Absoluto:
/home/user/dotfiles/zsh/.zshrc - Relativo:
../dotfiles/zsh/.zshrc
Nota: Stow solo crea symlinks relativos dentro del target directory.
2.2 Jerarquía de Directorios
┌─────────────────────────────────────────┐
│ /home/user/ (target directory) │
│ │
│ .zshrc ──────┐ │
│ .config/ │ │
│ ├── nvim/ │ symlinks │
│ └── kitty/ │ │
└─────────────────┼──────────────────────┘
│
↓
┌─────────────────────────────────────────┐
│ /home/user/dotfiles/ (stow dir) │
│ │
│ ├── zsh/ (package) │
│ │ └── .zshrc │
│ ├── nvim/ (package) │
│ │ └── .config/ │
│ │ └── nvim/ │
│ └── kitty/ (package) │
│ └── .config/ │
│ └── kitty/ │
└─────────────────────────────────────────┘
3 Sintaxis y Comandos
3.1 Sintaxis Básica
3.2 Acciones Principales
3.2.1 Stow (Instalar)
3.2.2 Delete (Desinstalar)
3.2.3 Restow (Reinstalar)
3.3 Opciones de Directorio
3.3.1 -d / --dir (Stow Directory)
3.3.2 -t / --target (Target Directory)
Ejemplo completo:
3.4 Opciones de Simulación y Verbosidad
3.4.1 -n / --no / --simulate (Dry Run)
3.4.2 -v / --verbose (Verbosidad)
Ejemplo:
3.5 Opciones Avanzadas
3.5.1 --ignore (Ignorar Archivos)
3.5.2 --defer (Diferir)
3.5.3 --override (Sobrescribir)
3.5.4 --dotfiles (Modo Dotfiles)
3.5.5 --no-folding (Sin Tree Folding)
3.5.6 --adopt (Adoptar Archivos)
3.6 Combinando Operaciones
4 Estructura de Directorios
4.1 Estructura Recomendada para Dotfiles
~/dotfiles/ # Stow directory
├── git/ # Package
│ └── .gitconfig
├── zsh/ # Package
│ ├── .zshrc
│ ├── .zshenv
│ └── .config/
│ └── zsh/
│ ├── aliases.zsh
│ └── functions.zsh
├── nvim/ # Package
│ └── .config/
│ └── nvim/
│ ├── init.lua
│ └── lua/
│ ├── plugins/
│ └── config/
├── kitty/ # Package
│ └── .config/
│ └── kitty/
│ ├── kitty.conf
│ └── themes/
├── tmux/ # Package
│ ├── .tmux.conf
│ └── .config/
│ └── tmux/
└── kde/ # Package
└── .config/
├── kdeglobals
├── dolphinrc
└── kwinrc4.2 Principios de Organización
4.2.1 Un Directorio = Un Paquete
4.2.2 Replicar Estructura del HOME
4.2.3 Agrupar Lógicamente
4.3 Ejemplos de Estructuras
4.3.1 Estructura Simple
Instalación:
mkdir ~/dotfiles
cd ~/dotfiles
# Crear la estructura para bash
mkdir -p bash
# o mueve, o crea symlink, como prefieras
cp ~/.bashrc bash/.bashrc
# (opcional) cp ~/.bash_profile bash/.bash_profile
# Para git
mkdir git
cp ~/.gitconfig git/.gitconfig
# Para vim
mkdir vim
cp ~/.vimrc vim/.vimrc
# si tienes ~/.vim/ con plugins, etc → también lo copias/mueves
# Para zsh + oh-my-zsh customizaciones
mkdir -p zsh/.config
cp ~/.zshrc zsh/.zshrcUna vez que tengas (por ejemplo) la carpeta bash/ con .bashrc dentro:
Resultado:
4.3.2 Estructura Compleja
~/dotfiles/
├── shell/
│ ├── .bashrc
│ ├── .zshrc
│ └── .config/
│ ├── bash/
│ │ └── aliases.bash
│ └── zsh/
│ └── aliases.zsh
├── terminal/
│ └── .config/
│ ├── kitty/
│ │ ├── kitty.conf
│ │ └── themes/
│ └── alacritty/
│ └── alacritty.yml
└── editor/
└── .config/
└── nvim/
├── init.lua
└── lua/
└── plugins.lua5 Instalación de Paquetes
5.1 Proceso de Instalación
5.1.1 Tree Folding (Plegado de Árbol)
Stow intenta crear el mínimo número de symlinks posible.
Ejemplo 1: Target Vacío
# Estado inicial:
~/ (vacío, sin ~/.config/)
# Paquete:
~/dotfiles/nvim/
└── .config/
└── nvim/
└── init.lua
# Comando:
cd ~/dotfiles
stow nvim
# Resultado (tree folding):
~/.config -> dotfiles/nvim/.config/
# En lugar de:
# ~/.config/nvim/init.lua -> ...
# Stow crea un symlink al directorio completoEjemplo 2: Target con Archivos Existentes
# Estado inicial:
~/.config/
└── kitty/ # ya existe
└── kitty.conf
# Paquete:
~/dotfiles/nvim/
└── .config/
└── nvim/
└── init.lua
# Comando:
stow nvim
# Resultado (NO puede hacer tree folding):
~/.config/ # directorio real
├── kitty/ # ya existía
│ └── kitty.conf
└── nvim -> ../dotfiles/nvim/.config/nvim/5.1.2 Tree Unfolding (Desplegado de Árbol)
Cuando un symlink plegado debe ser “abierto” para acomodar otro paquete.
Escenario:
# Estado inicial:
~/.config -> dotfiles/nvim/.config/
# Instalar otro paquete:
~/dotfiles/kitty/
└── .config/
└── kitty/
└── kitty.conf
# Comando:
stow kitty
# Proceso de unfolding:
# 1. Eliminar symlink: ~/.config
# 2. Crear directorio: ~/.config/
# 3. Crear symlinks:
# ~/.config/nvim -> ../dotfiles/nvim/.config/nvim/
# ~/.config/kitty -> ../dotfiles/kitty/.config/kitty/5.2 Instalación Básica
5.3 Instalación con Verificación
5.4 Instalación Selectiva
6 Desinstalación de Paquetes
6.1 Proceso de Desinstalación
6.1.1 Eliminación de Symlinks
6.1.2 Eliminación de Directorios Vacíos
6.1.3 Tree Refolding (Re-plegado)
Después de eliminar symlinks, si un directorio contiene solo symlinks a un único paquete, Stow lo “re-pliega”.
Escenario:
6.2 Desinstalación Básica
6.3 Desinstalación con Verificación
6.4 Desinstalación Parcial
7 Reinstalación de Paquetes
7.1 Comando Restow
7.2 Cuándo Usar Restow
1. Después de actualizar un paquete:
2. Para limpiar symlinks obsoletos:
3. Después de cambiar estructura:
7.3 Restow vs Delete + Stow
8 Gestión de Dotfiles
8.1 Setup Inicial
8.1.1 Crear Estructura
8.1.2 Mover Configuraciones Existentes
Método manual:
Con script:
#!/bin/bash
# migrate-to-stow.sh
DOTFILES="$HOME/dotfiles"
mkdir -p "$DOTFILES"
# Migrar zsh
mkdir -p "$DOTFILES/zsh"
mv ~/.zshrc "$DOTFILES/zsh/"
mv ~/.zshenv "$DOTFILES/zsh/"
# Migrar nvim
mkdir -p "$DOTFILES/nvim/.config"
mv ~/.config/nvim "$DOTFILES/nvim/.config/"
# Migrar git
mkdir -p "$DOTFILES/git"
mv ~/.gitconfig "$DOTFILES/git/"
# Stow todo
cd "$DOTFILES"
stow zsh nvim git8.1.3 Usar --adopt (Con Precaución)
8.2 Workflow Diario
8.2.1 Editar Configuraciones
8.2.2 Agregar Nueva Aplicación
8.2.3 Sincronizar con Git
8.3 Manejo de Archivos Sensibles
8.3.1 Estrategia 1: .gitignore
8.3.2 Estrategia 2: Archivos Template
# Crear template sin datos sensibles
# ~/dotfiles/git/.gitconfig.local.template
[user]
name = YOUR_NAME
email = YOUR_EMAIL
# .gitignore
.gitconfig.local
# Script de setup
#!/bin/bash
if [ ! -f ~/dotfiles/git/.gitconfig.local ]; then
cp ~/dotfiles/git/.gitconfig.local.template \
~/dotfiles/git/.gitconfig.local
echo "Edit ~/dotfiles/git/.gitconfig.local"
fi8.3.3 Estrategia 3: Encriptación
8.4 Estructura para Múltiples Hosts
Script de instalación por host:
9 Ignore Lists
9.1 Tipos de Ignore Lists
9.1.1 Built-in (Predeterminado)
Stow ignora automáticamente:
RCS
.+,v
CVS
\.\#.+ # CVS conflict files / emacs lock files
\.cvsignore
\.svn
_darcs
\.hg
\.git
\.gitignore
\.gitmodules
.+~ # emacs backup files
\#.*\# # emacs autosave files
^/README.*
^/LICENSE.*
^/COPYING
9.1.2 Global Ignore List
Archivo: ~/.stow-global-ignore
9.1.3 Package-Local Ignore List
Archivo: <package>/.stow-local-ignore
9.2 Sintaxis de Ignore Lists
9.2.1 Reglas de Matching
1. Expresiones con / (path completo):
2. Expresiones sin / (basename):
9.2.2 Ejemplos Prácticos
Ejemplo 1: Ignorar documentación:
Ejemplo 2: Ignorar archivos temporales:
Ejemplo 3: Ignorar por aplicación:
9.3 Precedencia de Ignore Lists
1. .stow-local-ignore (en paquete)
↓ (si no existe)
2. ~/.stow-global-ignore
↓ (si no existe)
3. Built-in ignore list
9.4 Opción --ignore en CLI
10 Opciones Avanzadas
10.1 Tree Folding Control
10.1.1 --no-folding
Desactiva tree folding completamente.
Sin –no-folding (default):
Con –no-folding:
Uso:
10.2 Adopt Mode
10.2.1 --adopt
ADVERTENCIA: Modifica el contenido del stow directory.
Escenario:
# Tienes configuración existente:
~/.config/nvim/init.lua
# Quieres adoptarla en tu paquete:
~/dotfiles/nvim/.config/nvim/ (vacío)
# Comando:
cd ~/dotfiles
stow --adopt nvim
# Resultado:
# 1. ~/.config/nvim/init.lua → movido a ~/dotfiles/nvim/.config/nvim/init.lua
# 2. ~/.config/nvim/init.lua → se convierte en symlinkUso con Git:
10.3 Defer y Override
10.3.1 --defer
Evita stowing si el archivo ya está stowed por otro paquete.
Escenario:
10.3.2 --override
Fuerza stowing incluso si ya existe symlink de otro paquete.
Escenario:
10.4 Dotfiles Mode
10.4.1 --dotfiles
Transforma dot- en . al hacer stow.
Uso:
Ventajas:
- Mantiene paquetes visibles (no ocultos por
.) - Más fácil navegar en GUI
- Mejor para Git
Desventajas:
- Necesita usar
--dotfilessiempre - Puede confundir
- No estándar
Recomendación: Usar nombres normales con . en vez de dot-.
10.5 Multiple Stow Directories
Puedes tener múltiples stow directories para diferentes propósitos.
Ejemplo:
.stow file: Indica que un directorio es stow directory, protegiéndolo de operaciones de unstow.
11 Integración con Git
11.1 Estructura de Repositorio
11.2 .gitignore Completo
# ~/dotfiles/.gitignore
# ========================================
# BACKUPS
# ========================================
*~
*.bak
*.old
*.orig
*.swp
*.swo
# ========================================
# HISTORIA Y DATOS SENSIBLES
# ========================================
# Shell history (puede contener comandos con passwords)
**/.zsh_history
**/.bash_history
**/.history
# Credenciales
.netrc
.authinfo
**/.ssh/id_*
**/.ssh/*.pem
# Tokens
**/.config/gh/hosts.yml
# ========================================
# CACHE Y TEMPORALES
# ========================================
# Directorios de cache
**/.cache/
**/__pycache__/
**/node_modules/
# Compilados
*.pyc
*.zwc
.zcompdump*
# Logs
**/*.log
# ========================================
# ARCHIVOS DE SISTEMA
# ========================================
.DS_Store
Thumbs.db
desktop.ini
# ========================================
# STOW
# ========================================
.stow
# ========================================
# APLICACIONES ESPECÍFICAS
# ========================================
# Zotero (database muy grande)
zotero/.zotero/zotero/*/zotero.sqlite*
zotero/.zotero/zotero/*/storage/
# VSCode
vscode/.config/Code/User/workspaceStorage/
vscode/.config/Code/CachedData/
vscode/.config/Code/logs/
# Obsidian
obsidian/Documents/thoughts/.obsidian/workspace
obsidian/Documents/thoughts/.obsidian/workspace.json
# KDE
kde/.config/session/
kde/.cache/11.3 Commits Best Practices
# Commits semánticos
# Agregar nueva aplicación
git commit -m "feat(tmux): Add tmux configuration"
# Actualizar configuración
git commit -m "chore(nvim): Update LSP settings"
# Fix
git commit -m "fix(zsh): Correct path to starship"
# Documentación
git commit -m "docs: Update README with stow instructions"
# Refactor
git commit -m "refactor(shell): Reorganize shell configs"11.4 Branches Strategy
11.6 Submodules para Plugins
11.7 GitHub Actions para Validación
# .github/workflows/validate.yml
name: Validate Dotfiles
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install stow
run: sudo apt-get install -y stow
- name: Test stow (dry run)
run: |
cd $GITHUB_WORKSPACE
stow -nv */
- name: Check for sensitive data
run: |
# Verificar que no haya claves SSH
if find . -name "id_rsa" -o -name "id_ed25519"; then
echo "ERROR: SSH keys found!"
exit 1
fi12 Troubleshooting
12.1 Problema 1: Conflictos al Stow
Error:
WARNING! stowing nvim would cause conflicts:
* existing target is neither a link nor a directory: .config/nvim/init.lua
All operations aborted.
Causa: Ya existe un archivo/directorio en el target que no es un symlink de Stow.
Soluciones:
Opción 1: Hacer backup y eliminar
Opción 2: Usar –adopt (cuidado)
Opción 3: Verificar y resolver manualmente
12.2 Problema 2: Symlinks Rotos
Error:
Causa: El paquete fue movido o eliminado.
Soluciones:
Opción 1: Restow
Opción 2: Desinstalar y reinstalar
Opción 3: Encontrar todos los symlinks rotos
12.3 Problema 3: Directorio No Vacío
Error:
BUG in find_stowed_path? Absolute/relative mismatch
Causa: Stow está confundido por la estructura de directorios.
Solución:
12.4 Problema 4: Tree Folding Inesperado
Problema: Stow crea symlink a directorio completo en lugar de entrar y enlazar archivos.
Ejemplo:
Causa: Stow hace tree folding por defecto para minimizar symlinks.
Solución si no lo quieres:
12.5 Problema 5: Permiso Denegado
Error:
cannot stow: permission denied
Causa: No tienes permisos para crear symlinks en target directory.
Soluciones:
Para /usr/local:
Para HOME:
12.6 Problema 6: Stow No Encuentra Paquete
Error:
stow: Cannot read package description: No such file or directory
Causa: No estás en el stow directory o el paquete no existe.
Solución:
12.7 Problema 7: .stowrc No Se Aplica
Problema: Las opciones en .stowrc no se usan.
Causas y soluciones:
1. Archivo en ubicación incorrecta:
2. Sintaxis incorrecta:
3. Variables no expandidas:
12.8 Problema 8: Stow Muy Lento
Causa: Directorios muy grandes o muchos archivos.
Soluciones:
1. Usar ignore lists:
2. Evitar stowing todo junto:
3. Simplificar estructura:
13 Scripts de Automatización
13.1 Script 1: install.sh Completo
Ya proporcioné un ejemplo arriba. Aquí una versión más robusta:
#!/bin/bash
# ~/dotfiles/install.sh
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOTFILES="$SCRIPT_DIR"
BACKUP_DIR="$HOME/dotfiles-backup-$(date +%Y%m%d-%H%M%S)"
LOG_FILE="$DOTFILES/install.log"
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Logging
log() {
echo -e "$1" | tee -a "$LOG_FILE"
}
log_info() {
log "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${GREEN}[INFO]${NC} $1"
}
log_warn() {
log "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${YELLOW}[WARN]${NC} $1"
}
log_error() {
log "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${RED}[ERROR]${NC} $1"
}
# Verificar dependencias
check_dependencies() {
log_info "Verificando dependencias..."
if ! command -v stow &> /dev/null; then
log_error "Stow no está instalado"
read -p "¿Instalar stow? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
if command -v apt &> /dev/null; then
sudo apt update && sudo apt install -y stow
elif command -v pacman &> /dev/null; then
sudo pacman -S stow
elif command -v brew &> /dev/null; then
brew install stow
else
log_error "No se pudo instalar stow automáticamente"
exit 1
fi
else
exit 1
fi
fi
log_info "✓ Dependencias OK"
}
# Backup de archivo/directorio existente
backup_if_exists() {
local path="$1"
local name="$2"
if [ -e "$path" ] && [ ! -L "$path" ]; then
log_warn "Existe: $path"
mkdir -p "$BACKUP_DIR"
cp -r "$path" "$BACKUP_DIR/"
log_info "Backup: $name → $BACKUP_DIR/"
return 0
fi
return 1
}
# Verificar conflictos antes de stow
check_conflicts() {
local package="$1"
if stow -nv "$package" 2>&1 | grep -q "WARNING\|ERROR"; then
return 1
fi
return 0
}
# Stow paquete con manejo de errores
stow_package() {
local package="$1"
local force="${2:-false}"
if [ ! -d "$package" ]; then
log_error "Paquete no existe: $package"
return 1
fi
log_info "Procesando: $package"
# Check conflicts
if ! check_conflicts "$package"; then
log_warn "Conflictos detectados en: $package"
if [ "$force" = "true" ]; then
log_info "Forzando instalación..."
# Aquí podrías implementar lógica de backup automático
else
read -p "¿Continuar? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_error "Saltado: $package"
return 1
fi
fi
fi
# Stow
if stow -v "$package"; then
log_info "✓ Instalado: $package"
return 0
else
log_error "✗ Error al instalar: $package"
return 1
fi
}
# Mostrar ayuda
show_help() {
cat << EOF
Uso: $0 [opciones] [paquetes...]
Opciones:
-h, --help Mostrar esta ayuda
-a, --all Instalar todos los paquetes
-f, --force Forzar instalación (saltear prompts)
-l, --list Listar paquetes disponibles
-d, --dry-run Simular sin hacer cambios
Ejemplos:
$0 nvim zsh git # Instalar paquetes específicos
$0 --all # Instalar todo
$0 --list # Ver paquetes disponibles
EOF
}
# Listar paquetes disponibles
list_packages() {
log_info "Paquetes disponibles:"
cd "$DOTFILES"
for package in */; do
package=${package%/}
if [ "$package" != ".git" ] && [ -d "$package" ]; then
echo " - $package"
fi
done
}
# Main
main() {
local force=false
local dry_run=false
local packages=()
# Parse argumentos
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-a|--all)
cd "$DOTFILES"
packages=($(ls -d */ | sed 's#/#' | grep -v '^\.'))
shift
;;
-f|--force)
force=true
shift
;;
-l|--list)
list_packages
exit 0
;;
-d|--dry-run)
dry_run=true
shift
;;
*)
packages+=("$1")
shift
;;
esac
done
# Verificar que hay paquetes para instalar
if [ ${#packages[@]} -eq 0 ]; then
log_error "No se especificaron paquetes"
show_help
exit 1
fi
# Iniciar log
log_info "=== Instalación de Dotfiles ==="
log_info "Directorio: $DOTFILES"
log_info "Paquetes: ${packages[*]}"
# Verificar dependencias
check_dependencies
# Cambiar a dotfiles directory
cd "$DOTFILES" || exit 1
# Dry run si se especificó
if [ "$dry_run" = true ]; then
log_info "=== DRY RUN ==="
for package in "${packages[@]}"; do
log_info "Simulating: $package"
stow -nv "$package" || true
done
exit 0
fi
# Instalar paquetes
local success=0
local failed=0
for package in "${packages[@]}"; do
if stow_package "$package" "$force"; then
((success++))
else
((failed++))
fi
done
# Resumen
log_info ""
log_info "=== Resumen ==="
log_info "Exitosos: $success"
if [ $failed -gt 0 ]; then
log_warn "Fallidos: $failed"
fi
if [ -d "$BACKUP_DIR" ]; then
log_info "Backups en: $BACKUP_DIR"
fi
log_info "Log completo en: $LOG_FILE"
}
# Ejecutar
main "$@"13.2 Script 2: update.sh
#!/bin/bash
# ~/dotfiles/update.sh
set -e
DOTFILES="$HOME/dotfiles"
cd "$DOTFILES"
echo "🔄 Actualizando dotfiles..."
# Pull latest changes
git pull origin main
# Restow todos los paquetes instalados
for package in */; do
package=${package%/}
# Verificar si está stowed
if find "$HOME" -maxdepth 2 -type l -lname "*$DOTFILES/$package/*" 2>/dev/null | grep -q .; then
echo "↻ Restowing $package..."
stow -R "$package"
fi
done
echo "✓ Actualización completa!"13.3 Script 3: check.sh
#!/bin/bash
# ~/dotfiles/check.sh
DOTFILES="$HOME/dotfiles"
echo "📋 Estado de paquetes:"
echo "===================="
cd "$DOTFILES"
for package in */; do
package=${package%/}
if [ "$package" = ".git" ]; then
continue
fi
# Buscar primer archivo del paquete
first_file=$(find "$package" -type f -o -type l | head -1)
if [ -z "$first_file" ]; then
echo "⚠️ $package (vacío)"
continue
fi
# Convertir a path en HOME
home_path="$HOME/${first_file#$package/}"
if [ -L "$home_path" ]; then
target=$(readlink "$home_path")
if [[ "$target" == *"$DOTFILES/$package"* ]]; then
echo "✅ $package"
else
echo "⚠️ $package (symlink apunta a: $target)"
fi
elif [ -e "$home_path" ]; then
echo "❌ $package (existe pero no es symlink)"
else
echo "❌ $package (no instalado)"
fi
done
# Verificar symlinks rotos
echo ""
echo "🔗 Verificando symlinks rotos..."
broken_links=$(find "$HOME" -maxdepth 3 -xtype l -lname "*$DOTFILES/*" 2>/dev/null)
if [ -z "$broken_links" ]; then
echo "✅ No hay symlinks rotos"
else
echo "⚠️ Symlinks rotos encontrados:"
echo "$broken_links"
fi13.4 Script 4: clean.sh
#!/bin/bash
# ~/dotfiles/clean.sh
DOTFILES="$HOME/dotfiles"
echo "🧹 Limpiando symlinks huérfanos..."
# Encontrar symlinks rotos que apuntan a dotfiles
find "$HOME" -maxdepth 3 -xtype l -lname "*$DOTFILES/*" 2>/dev/null | while read -r broken_link; do
echo "Eliminando: $broken_link"
rm "$broken_link"
done
echo "✓ Limpieza completa!"14 Casos de Uso Prácticos
14.1 Caso 1: Crear Dotfiles desde Cero (Primera Vez)
Escenario: Nunca has usado Stow, quieres empezar desde cero organizando tus configuraciones.
Objetivo: Crear estructura de dotfiles, migrar configs existentes, versionar con Git.
14.1.1 Paso 1: Preparación
# 1.1 Instalar herramientas necesarias
sudo pacman -S stow git zsh starship # Arch/Archcraft
# o
sudo apt install stow git zsh # Kubuntu/Debian
# 1.2 Verificar instalación
stow --version
git --version
# 1.3 Crear directorio para dotfiles
mkdir -p ~/dotfiles
cd ~/dotfiles
# 1.4 Inicializar Git
git init
git branch -M main
# 1.5 Configurar Git (si no está configurado)
git config user.name "Edison Achalma"
git config user.email "achalmaedison@gmail.com"14.1.2 Paso 2: Crear Estructura de Paquetes
14.1.3 Paso 3: Migrar Configuraciones Existentes
3.1 Git (.gitconfig):
3.2 Shell (Zsh):
3.3 Terminal (Konsole):
# Crear estructura que replica HOME
mkdir -p terminal/.config
# Mover config de Konsole
mv ~/.config/konsolerc terminal/.config/
# Si tienes perfiles personalizados
cp -r ~/.local/share/konsole terminal/.local/share/ 2>/dev/null || true
# Verificar
tree terminal/
# terminal/
# └── .config/
# └── konsolerc3.4 VSCode:
# Crear estructura
mkdir -p vscode/.config/Code/User
# Mover settings
mv ~/.config/Code/User/settings.json vscode/.config/Code/User/
mv ~/.config/Code/User/keybindings.json vscode/.config/Code/User/
# Snippets
mv ~/.config/Code/User/snippets vscode/.config/Code/User/ 2>/dev/null || true
# Verificar
tree vscode/.config/Code/User/3.5 KDE Plasma:
# Crear estructura
mkdir -p kde/.config
# Mover configuraciones principales
mv ~/.config/kdeglobals kde/.config/
mv ~/.config/dolphinrc kde/.config/
mv ~/.config/kwinrc kde/.config/
mv ~/.config/plasmarc kde/.config/
mv ~/.config/plasma-org.kde.plasma.desktop-appletsrc kde/.config/
mv ~/.config/mimeapps.list kde/.config/
# Verificar
ls kde/.config/14.1.4 Paso 4: Crear Ignore Lists
4.1 Global ignore:
4.2 Ignore por paquete (shell):
4.3 Ignore para VSCode:
14.1.5 Paso 5: Crear .gitignore
cat > .gitignore << 'EOF'
# ========================================
# BACKUPS
# ========================================
*~
*.bak
*.old
*.orig
*.swp
*.swo
# ========================================
# DATOS SENSIBLES
# ========================================
# Historia de shells
**/.zsh_history
**/.bash_history
# SSH keys
**/.ssh/id_*
**/.ssh/*.pem
# Credenciales
.netrc
.authinfo
# ========================================
# CACHE Y TEMPORALES
# ========================================
**/.cache/
**/__pycache__/
*.pyc
.zcompdump*
# ========================================
# STOW
# ========================================
.stow
# ========================================
# LOGS
# ========================================
**/*.log
*.log
# ========================================
# SISTEMA
# ========================================
.DS_Store
Thumbs.db
desktop.ini
EOF14.1.6 Paso 6: Crear .stowrc
14.1.7 Paso 7: Instalar con Stow (Primera Vez)
# Navegar a dotfiles
cd ~/dotfiles
# Dry run primero para cada paquete
stow -nv git
stow -nv shell
stow -nv terminal
stow -nv vscode
stow -nv kde
# Si todo OK, instalar realmente
stow git shell terminal vscode kde
# Verificar symlinks
ls -la ~/.gitconfig
# lrwxrwxrwx ... .gitconfig -> dotfiles/git/.gitconfig
ls -la ~/.zshrc
# lrwxrwxrwx ... .zshrc -> dotfiles/shell/.zshrc
ls -la ~/.config/konsolerc
# lrwxrwxrwx ... konsolerc -> ../dotfiles/terminal/.config/konsolerc14.1.8 Paso 8: Verificar que Todo Funciona
14.1.9 Paso 9: Crear Scripts de Ayuda
9.1 Script de instalación:
cat > install.sh << 'EOF'
#!/bin/bash
set -e
DOTFILES="$HOME/dotfiles"
echo "🚀 Instalando dotfiles..."
cd "$DOTFILES"
# Lista de paquetes
PACKAGES=(
"git"
"shell"
"terminal"
"vscode"
"kde"
)
# Instalar cada paquete
for pkg in "${PACKAGES[@]}"; do
echo "📦 Instalando $pkg..."
stow "$pkg"
done
echo "✅ ¡Instalación completa!"
EOF
chmod +x install.sh9.2 Script de verificación:
cat > check.sh << 'EOF'
#!/bin/bash
DOTFILES="$HOME/dotfiles"
echo "📋 Verificando dotfiles..."
echo ""
cd "$DOTFILES"
for pkg in */; do
pkg=${pkg%/}
# Buscar primer archivo
first_file=$(find "$pkg" -type f | head -1)
if [ -z "$first_file" ]; then
continue
fi
# Path en HOME
home_path="$HOME/${first_file#$pkg/}"
if [ -L "$home_path" ]; then
echo "✅ $pkg"
else
echo "❌ $pkg (no instalado)"
fi
done
EOF
chmod +x check.sh14.1.10 Paso 10: Crear Repositorio en GitHub
# 10.1 Agregar todo a Git
cd ~/dotfiles
git add .
# 10.2 Commit inicial
git commit -m "Initial commit: Estructura básica de dotfiles
- Git configuration
- Zsh/Starship setup
- Konsole terminal config
- VSCode settings
- KDE Plasma configuration"
# 10.3 Crear repo en GitHub (vía navegador o gh CLI)
# Opción A: Navegador
# Ve a https://github.com/new
# Nombre: .dotfiles
# Descripción: "Dotfiles para Archcraft/Kubuntu con Stow"
# Público o Privado
# NO inicializar con README (ya lo tienes)
# Opción B: GitHub CLI
gh repo create .dotfiles --public --source=. --remote=origin
# 10.4 Agregar remote y push
git remote add origin https://github.com/achalmaedison/.dotfiles.git
git push -u origin main14.1.11 Paso 11: Crear README.md
cat > README.md << 'EOF'
# Dotfiles
Configuraciones personales para Archcraft/Kubuntu gestionadas con GNU Stow.
## Estructura
``
~/dotfiles/
├── git/ # Git config
├── shell/ # Zsh + Starship
├── terminal/ # Konsole
├── vscode/ # Visual Studio Code
└── kde/ # KDE Plasma
``
## Instalación
``bash
# Clonar
git clone https://github.com/achalmaedison/.dotfiles.git ~/dotfiles
# Instalar Stow
sudo pacman -S stow # Arch
# o
sudo apt install stow # Debian/Ubuntu
# Instalar todo
cd ~/dotfiles
./install.sh
# O instalar selectivo
stow git shell terminal
``
## Actualizar
``bash
cd ~/dotfiles
git pull
stow -R */
``
## Requisitos
- stow
- git
- zsh
- starship (opcional)
- VSCode (opcional)
- KDE Plasma (opcional)
EOF
git add README.md
git commit -m "docs: Add README"
git push14.2 Caso 2: Replicar Dotfiles en Laptop Nueva
Escenario: Acabas de comprar/instalar una laptop nueva con Archcraft y quieres replicar tu setup completo.
Objetivo: Clonar tu repo de dotfiles e instalar todo en la nueva máquina.
14.2.1 Paso 1: Preparar Nueva Máquina
14.2.2 Paso 2: Backup de Configs Existentes (Precaución)
# 2.1 Crear directorio de backup
mkdir -p ~/dotfiles-backup-$(date +%Y%m%d)
BACKUP_DIR=~/dotfiles-backup-$(date +%Y%m%d)
# 2.2 Backup de archivos que podrían existir
cp ~/.zshrc "$BACKUP_DIR/" 2>/dev/null || true
cp ~/.gitconfig "$BACKUP_DIR/" 2>/dev/null || true
cp -r ~/.config/Code "$BACKUP_DIR/" 2>/dev/null || true
echo "Backup guardado en: $BACKUP_DIR"
ls -la "$BACKUP_DIR"14.2.3 Paso 3: Clonar Repositorio
14.2.4 Paso 4: Revisar y Ajustar (Si Necesario)
14.2.5 Paso 5: Instalar Dependencias
# 5.1 Aplicaciones de tu setup
sudo pacman -S \
zsh \
starship \
konsole \
code \ # VSCode (si está en repos)
plasma-desktop \
dolphin \
kate \
okular
# 5.2 Si usas AUR (yay/paru)
# VSCode desde AUR
yay -S visual-studio-code-bin
# Starship (si no está en repos oficiales)
yay -S starship-bin
# 5.3 Verificar instalaciones
which zsh
which starship
which code14.2.6 Paso 6: Dry Run (Simulación)
14.2.7 Paso 7: Resolver Conflictos (Si Existen)
Si ves algo como:
WARNING! stowing shell would cause conflicts:
* existing target is neither a link nor a directory: .zshrc
Resolver:
14.2.8 Paso 8: Instalar Todo
Opción A: Con script (recomendado):
Opción B: Manual:
Opción C: Todo de una vez:
14.2.9 Paso 9: Verificar Instalación
# 9.1 Verificar symlinks creados
ls -la ~/.gitconfig
# lrwxrwxrwx ... .gitconfig -> dotfiles/git/.gitconfig
ls -la ~/.zshrc
# lrwxrwxrwx ... .zshrc -> dotfiles/shell/.zshrc
ls -la ~/.config/Code/User/settings.json
# lrwxrwxrwx ... settings.json -> ../../../../dotfiles/vscode/.config/Code/User/settings.json
# 9.2 Usar script de verificación
cd ~/dotfiles
./check.sh14.2.10 Paso 10: Configurar Shell
14.2.11 Paso 11: Instalar Dependencias Específicas
11.1 Extensiones de VSCode:
11.2 Plugins de Zsh (si usas):
11.3 Temas de KDE (si los tienes):
14.2.12 Paso 12: Probar Todo
# 12.1 Git
git config --list | grep user
# user.name=Edison Achalma
# user.email=achalmaedison@gmail.com
# 12.2 Zsh
cat ~/.zshrc | head -5
# 12.3 VSCode
code
# Debería cargar con tu configuración
# 12.4 Konsole
konsole
# Debería usar tu configuración
# 12.5 KDE
# Logout/login para ver cambios en KDE14.2.13 Paso 13: Ajustes Finales
14.3 Caso 3: Actualizar Configs y Sincronizar
Escenario: Has estado usando tus dotfiles y has hecho cambios en tu máquina principal. Quieres sincronizar con GitHub y otras máquinas.
14.3.1 Paso 1: Identificar Cambios
14.3.2 Paso 2: Probar Cambios Localmente
# Si editaste configs directamente en HOME (a través de symlinks),
# los cambios ya están en ~/dotfiles/
# 2.1 Verificar que todo funciona
source ~/.zshrc # Para shell
code # Abrir VSCode para verificar settings
# 2.2 Si hay problemas, revertir temporalmente
cd ~/dotfiles
git checkout -- shell/.zshrc # Revertir cambios
# Probar de nuevo14.3.3 Paso 3: Commit Cambios
cd ~/dotfiles
# 3.1 Agregar archivos modificados
git add shell/.zshrc
git add vscode/.config/Code/User/settings.json
# O agregar todo:
git add -A
# 3.2 Ver qué se va a commitear
git status
# 3.3 Commit con mensaje descriptivo
git commit -m "chore(shell): Update Zsh aliases and PATH
- Add alias for git status
- Update PATH to include ~/.local/bin
- Remove deprecated exports"
git commit -m "feat(vscode): Enable format on save
- Set editor.formatOnSave to true
- Add Python formatting rules
- Update keybindings for terminal"14.3.4 Paso 4: Push a GitHub
14.3.5 Paso 5: Actualizar Otras Máquinas
En laptop/otra máquina:
# 5.1 Pull cambios
cd ~/dotfiles
git pull origin main
# 5.2 Los symlinks reflejan cambios automáticamente!
cat ~/.zshrc # Ya tiene los cambios
# 5.3 Recargar configs
source ~/.zshrc # Shell
# VSCode se recarga automáticamente
# 5.4 Si hay cambios en estructura (archivos nuevos/eliminados):
stow -R shell # Restow para actualizar symlinks
stow -R vscode14.3.6 Paso 6: Manejar Conflictos (Si Existen)
Si modificaste el mismo archivo en dos máquinas:
cd ~/dotfiles
git pull origin main
# Si hay conflicto:
# CONFLICT (content): Merge conflict in shell/.zshrc
# 6.1 Ver conflicto
git status
# both modified: shell/.zshrc
# 6.2 Editar archivo
nano shell/.zshrc
# Verás marcadores:
# <<<<<<< HEAD
# (tu cambio local)
# =======
# (cambio de GitHub)
# >>>>>>> origin/main
# 6.3 Resolver manualmente, eliminar marcadores
# 6.4 Marcar como resuelto
git add shell/.zshrc
git commit -m "merge: Resolve conflict in .zshrc"
git push14.4 Caso 4: Agregar Nueva Aplicación (Kate Editor)
Escenario: Instalaste Kate y quieres agregar su configuración a tus dotfiles.
14.4.1 Paso 1: Usar Kate y Configurar
14.4.2 Paso 2: Localizar Archivos de Config
# 2.1 Archivos de configuración están en ~/.config/
ls -la ~/.config/ | grep kate
# drwxr-xr-x - achalmaedison kate/
# 2.2 Ver qué hay dentro
ls -la ~/.config/kate/
# katerc
# externaltools/
# formatting/
# lspclient/
# 2.3 También puede haber datos en ~/.local/share/
ls -la ~/.local/share/ | grep kate14.4.3 Paso 3: Crear Paquete Kate
# 3.1 Crear estructura que replica HOME
cd ~/dotfiles
mkdir -p kate/.config
# 3.2 Copiar configs (NO mover todavía)
cp -r ~/.config/kate kate/.config/
# 3.3 También copiar datos locales si existen
mkdir -p kate/.local/share
cp -r ~/.local/share/kate kate/.local/share/ 2>/dev/null || true
# 3.4 Verificar estructura
tree kate/
# kate/
# ├── .config/
# │ └── kate/
# │ ├── katerc
# │ ├── externaltools/
# │ ├── formatting/
# │ └── lspclient/
# └── .local/
# └── share/
# └── kate/14.4.4 Paso 4: Crear Ignore List para Kate
14.4.5 Paso 5: Test Stow (Dry Run)
14.4.6 Paso 6: Hacer Backup y Eliminar Original
14.4.7 Paso 7: Stow Kate
14.4.8 Paso 8: Versionar con Git
14.4.9 Paso 9: Actualizar README
14.4.10 Paso 10: Actualizar Script de Instalación
14.5 Caso 5: Migrar de Kubuntu a Archcraft
Escenario: Usabas Kubuntu, ahora instalaste Archcraft. Quieres migrar tus dotfiles pero adaptándolos.
14.5.1 Paso 1: Evaluar Diferencias
# 1.1 En tu Kubuntu original, ver qué tienes
cd ~/dotfiles
ls -d */
# Ejemplo:
# git/ shell/ terminal/ vscode/ kde/ digikam/ okular/ ...
# 1.2 Identificar qué es compatible con Archcraft
# ✅ Compatible: git, shell, vscode
# ⚠️ Adaptar: kde (Archcraft puede usar i3/bspwm)
# ❌ No necesario: apps específicas de Kubuntu14.5.2 Paso 2: En Archcraft Nueva
14.5.3 Paso 3: Crear Branch para Archcraft
14.5.4 Paso 4: Instalar Paquetes Universales
14.5.5 Paso 5: Adaptar o Crear Nuevos Paquetes
5.1 Window Manager (Si Archcraft usa i3/bspwm):
5.2 Terminal (Si Archcraft usa otro terminal):
# Supongamos que Archcraft usa Alacritty en vez de Konsole
# Crear paquete
mkdir -p alacritty/.config/alacritty
# Config de Alacritty
cat > alacritty/.config/alacritty/alacritty.yml << 'EOF'
# Alacritty configuration
font:
size: 11.0
normal:
family: JetBrains Mono
window:
opacity: 0.95
colors:
# Tu esquema de colores...
EOF
# Stow
stow alacritty5.3 Polybar (Si Archcraft lo usa):
14.5.6 Paso 6: No Instalar Paquetes Incompatibles
14.5.7 Paso 7: Commit Cambios
cd ~/dotfiles
# Agregar nuevos paquetes
git add i3/ alacritty/ polybar/
# Commit en branch archcraft
git commit -m "feat(archcraft): Add i3, Alacritty, Polybar configs
- i3 window manager configuration
- Alacritty terminal setup
- Polybar panel configuration"
# Push branch
git push origin archcraft-setup14.5.8 Paso 8: Estrategia de Branches
Opción A: Mantener branches separadas:
Opción B: Usar estructura de directorios:
# Reorganizar dotfiles:
~/dotfiles/
├── common/ # Configs universales
│ ├── git/
│ ├── shell/
│ └── vscode/
├── kubuntu/ # Específicos de Kubuntu
│ ├── kde/
│ └── konsole/
└── archcraft/ # Específicos de Archcraft
├── i3/
├── alacritty/
└── polybar/
# Instalar según distro:
cd ~/dotfiles/common && stow */
cd ~/dotfiles/archcraft && stow */14.5.9 Paso 9: Script de Instalación por Distro
cat > install-arch.sh << 'EOF'
#!/bin/bash
# Install script para Archcraft
DOTFILES="$HOME/dotfiles"
echo "🚀 Instalando dotfiles para Archcraft..."
# Common packages
cd "$DOTFILES/common"
stow git shell vscode
# Archcraft-specific
cd "$DOTFILES/archcraft"
stow i3 alacritty polybar rofi
echo "✅ ¡Instalación completa!"
EOF
chmod +x install-arch.sh14.5.10 Paso 10: Mantener Ambos Sistemas
# Cuando hagas cambios en configs comunes (git, shell, vscode):
# 1. Hacer cambio en cualquier máquina
cd ~/dotfiles
nano common/shell/.zshrc
# 2. Commit
git add common/shell/.zshrc
git commit -m "chore(shell): Update aliases"
# 3. Push
git push origin main
# 4. En otra máquina (Kubuntu o Archcraft):
git pull origin main
# Los symlinks se actualizan automáticamente14.6 Caso 6: Probar Nueva Configuración Sin Romper
Escenario: Quieres probar una nueva configuración de Neovim sin afectar tu setup actual.
14.6.1 Paso 1: Crear Branch Experimental
14.6.2 Paso 2: Crear Paquete Alternativo
14.6.3 Paso 3: Desinstalar Neovim Actual
14.6.4 Paso 4: Instalar Nueva Config
14.6.5 Paso 5: Probar
14.6.6 Paso 6: Decidir Qué Hacer
Opción A: Mantener nueva config (si te gustó):
cd ~/dotfiles
# 1. Eliminar config vieja
rm -rf nvim/ # O hacer backup
# 2. Renombrar nueva
mv nvim-lazy nvim
# 3. Restow
stow -R nvim
# 4. Commit
git add .
git commit -m "refactor(nvim): Switch to LazyVim configuration"
# 5. Merge a main
git checkout main
git merge experiment/nvim-lazyvim
# 6. Push
git push origin main
# 7. Eliminar branch experimental
git branch -d experiment/nvim-lazyvimOpción B: Volver a config anterior (si no te gustó):
Opción C: Mantener ambas (para casos específicos):
14.7 Caso 7: Sincronizar Múltiples Máquinas en Tiempo Real
Escenario: Trabajas en 3 máquinas (desktop, laptop, servidor) y quieres mantener dotfiles sincronizados.
14.7.1 Configuración Inicial (Una Vez)
14.7.2 Workflow Diario
Máquina A (Desktop) - Hacer Cambios:
Máquina B (Laptop) - Recibir Cambios:
Máquina C (Servidor) - Recibir Cambios:
14.7.3 Automatizar con Cron (Opcional)
# Crear script de sync
cat > ~/dotfiles/sync.sh << 'EOF'
#!/bin/bash
cd "$HOME/dotfiles"
# Pull cambios silenciosamente
git pull origin main --quiet
# Log
echo "$(date): Dotfiles sincronizados" >> ~/dotfiles/sync.log
EOF
chmod +x ~/dotfiles/sync.sh
# Agregar a crontab (sync cada hora)
crontab -e
# Agregar línea:
0 * * * * $HOME/dotfiles/sync.sh14.7.4 Manejar Conflictos Automáticamente
# Script más robusto
cat > ~/dotfiles/sync.sh << 'EOF'
#!/bin/bash
cd "$HOME/dotfiles"
# Stash cambios locales si existen
git stash
# Pull
git pull origin main --quiet
# Reapply stash
git stash pop
# Si hay conflictos, notificar
if [ $? -ne 0 ]; then
notify-send "Dotfiles" "Conflicto detectado, revisar manualmente"
fi
EOF14.7.5 Usar Git Hooks (Avanzado)
# Pre-commit hook para validar antes de commit
cat > ~/dotfiles/.git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Verificar que no hay datos sensibles
if git diff --cached | grep -i "password\|secret\|token"; then
echo "ERROR: Posible dato sensible detectado!"
exit 1
fi
exit 0
EOF
chmod +x ~/dotfiles/.git/hooks/pre-commit14.8 Caso 8: Compartir Dotfiles con Equipo/Lab
Escenario: Trabajas en un lab con múltiples usuarios y quieren compartir configuraciones base.
14.8.1 Paso 1: Crear Repo de Equipo
14.8.2 Paso 2: Estructura Multi-Usuario
14.8.3 Paso 3: Setup Común
# Git config compartido (sin user.name/email)
cat > common/git/.gitconfig << 'EOF'
[core]
editor = nano
autocrlf = input
[alias]
st = status
co = checkout
br = branch
[push]
default = simple
EOF
# Shell común
cat > common/shell/.zshrc << 'EOF'
# Shared Zsh configuration for Lab
# Common aliases
alias ll='ls -lah'
alias ..='cd ..'
# Lab-specific paths
export LAB_DATA="/data/lab"
export LAB_TOOLS="/opt/lab-tools"
# Source user-specific config if exists
[ -f ~/.zshrc.local ] && source ~/.zshrc.local
EOF14.8.4 Paso 4: Configs Personales
14.8.5 Paso 5: Script de Instalación
cat > install-lab.sh << 'EOF'
#!/bin/bash
USERNAME="$1"
if [ -z "$USERNAME" ]; then
echo "Uso: $0 <username>"
echo "Ejemplo: $0 alice"
exit 1
fi
DOTFILES="$HOME/lab-dotfiles"
# Instalar común
cd "$DOTFILES/common"
stow git shell terminal
# Instalar personal del usuario
if [ -d "$DOTFILES/users/$USERNAME" ]; then
cd "$DOTFILES/users/$USERNAME"
stow .
echo "✅ Configs de $USERNAME instaladas"
else
echo "⚠️ No hay configs personales para $USERNAME"
fi
echo "✅ Instalación completa para $USERNAME"
EOF
chmod +x install-lab.sh14.8.6 Paso 6: Cada Usuario Instala
14.8.7 Paso 7: Actualizar Configs Compartidas
# Cualquier usuario puede actualizar common/
# 1. Modificar
nano ~/lab-dotfiles/common/shell/.zshrc
# 2. Commit
cd ~/lab-dotfiles
git add common/shell/.zshrc
git commit -m "feat(shell): Add lab-wide utility function"
# 3. Push
git push origin main
# 4. Otros usuarios pull
git pull origin main
# Cambios se aplican automáticamente via symlinks14.8.8 Paso 8: Usuarios Agregan Sus Configs
# Bob quiere agregar su config de Neovim
# 1. Crear su directorio personal
mkdir -p ~/lab-dotfiles/users/bob/.config
# 2. Copiar config
cp -r ~/.config/nvim ~/lab-dotfiles/users/bob/.config/
# 3. Commit (solo su carpeta)
cd ~/lab-dotfiles
git add users/bob/.config/nvim
git commit -m "feat(bob): Add Neovim configuration"
git push
# Otros usuarios no se afectan14.9 Caso 9: Migrar de Sistema Manual a Stow
Escenario: Tienes dotfiles en GitHub pero SIN Stow (todos en raíz del repo). Quieres migrar a Stow.
14.9.1 Estado Inicial
14.9.2 Paso 1: Backup Completo
14.9.3 Paso 2: Crear Nueva Estructura
14.9.4 Paso 3: Reorganizar Archivos
cd ~/dotfiles
# Git
mv .gitconfig git/
# Shell
mv .zshrc shell/
mv .zshenv shell/
# Neovim (crear estructura correcta)
mkdir -p nvim/.config
mv nvim/ nvim/.config/nvim/
# Terminal
mkdir -p terminal/.config
mv konsolerc terminal/.config/
# VSCode
mkdir -p vscode/.config/Code/User
mv settings.json vscode/.config/Code/User/14.9.5 Paso 4: Verificar Nueva Estructura
14.9.6 Paso 5: Eliminar Symlinks/Archivos Viejos de HOME
14.9.7 Paso 6: Instalar con Stow
14.9.8 Paso 7: Commit Nueva Estructura
cd ~/dotfiles
# Stage todo
git add -A
# Ver cambios
git status
# Commit
git commit -m "refactor: Migrate to GNU Stow structure
BREAKING CHANGE: Repository structure changed to use Stow
- Organized configs into packages (git, shell, nvim, etc.)
- Each package replicates HOME directory structure
- Use 'stow <package>' to install
Migration guide:
1. stow -D * (if already installed)
2. stow git shell nvim terminal vscode"
# Push
git push origin main14.9.9 Paso 8: Actualizar README
cat > README.md << 'EOF'
# Dotfiles (Stow-managed)
Personal configurations managed with GNU Stow.
# Structure
``
~/dotfiles/
├── git/ # Git config
├── shell/ # Zsh
├── nvim/ # Neovim
├── terminal/ # Konsole
└── vscode/ # VSCode
``
## Installation
``bash
# Install Stow
sudo pacman -S stow
# Clone
git clone https://github.com/user/dotfiles.git ~/dotfiles
# Install all
cd ~/dotfiles
stow */
# Or selective
stow git shell nvim
``
## Update
``bash
cd ~/dotfiles
git pull
stow -R */
``
EOF
git add README.md
git commit -m "docs: Update README for Stow"
git push14.9.10 Paso 9: Crear Scripts
14.9.11 Paso 10: Limpiar Historial de Git (Opcional)
# Si tu repo era muy grande con historia antigua,
# puedes limpiarlo:
cd ~/dotfiles
# Crear orphan branch
git checkout --orphan latest_branch
# Add all files
git add -A
# Commit
git commit -m "refactor: Fresh start with Stow structure"
# Delete main
git branch -D main
# Rename current branch to main
git branch -m main
# Force push
git push -f origin main14.10 Caso 10: Setup para Desarrollo Multi-Proyecto
Escenario: Trabajas en múltiples proyectos (Python, Web, Latex) y quieres configs específicas por proyecto.
14.10.1 Estructura de Dotfiles
14.10.2 Paso 1: Crear Estructura
14.10.3 Paso 2: Configs Comunes
# Git (igual para todos)
cat > common/git/.gitconfig << 'EOF'
[user]
name = Edison Achalma
email = achalmaedison@gmail.com
[core]
editor = nvim
EOF
# Shell base
cat > common/shell/.zshrc << 'EOF'
# Common shell config
# Aliases
alias gs='git status'
alias ll='ls -lah'
# Load project-specific config
[ -f ~/.zshrc.project ] && source ~/.zshrc.project
EOF14.10.4 Paso 3: Configs Específicas por Proyecto
Python Development:
# Neovim para Python
cat > python-dev/nvim/.config/nvim/init.lua << 'EOF'
-- Python-focused Neovim config
-- LSP
require('lspconfig').pyright.setup{}
-- Python-specific keymaps
vim.keymap.set('n', '<leader>r', ':!python %<CR>')
EOF
# VSCode para Python
cat > python-dev/vscode/.config/Code/User/settings.json << 'EOF'
{
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.provider": "black"
}
EOF
# Shell additions para Python
cat > python-dev/shell/.zshrc.project << 'EOF'
# Python dev environment
export PYTHONPATH="$HOME/projects/python:$PYTHONPATH"
alias pytest='python -m pytest'
alias venv='python -m venv venv && source venv/bin/activate'
EOFWeb Development:
# Neovim para Web
cat > web-dev/nvim/.config/nvim/init.lua << 'EOF'
-- Web-focused Neovim config
-- LSP for JS/TS
require('lspconfig').tsserver.setup{}
-- Live server
vim.keymap.set('n', '<leader>l', ':!live-server .<CR>')
EOF
# VSCode para Web
cat > web-dev/vscode/.config/Code/User/settings.json << 'EOF'
{
"emmet.includeLanguages": {
"javascript": "javascriptreact"
},
"prettier.enable": true,
"editor.formatOnSave": true
}
EOF14.10.5 Paso 4: Scripts de Activación
# Script para activar proyecto Python
cat > ~/dotfiles/activate-python.sh << 'EOF'
#!/bin/bash
echo "🐍 Activando entorno Python..."
cd ~/dotfiles
# Unstow otros proyectos
stow -D web-dev/nvim 2>/dev/null || true
stow -D latex-writing/nvim 2>/dev/null || true
# Stow común
stow common/*
# Stow Python
stow python-dev/*
# Copiar project-specific shell config
cp python-dev/shell/.zshrc.project ~/.zshrc.project
echo "✅ Entorno Python activado"
EOF
chmod +x ~/dotfiles/activate-python.sh# Script para activar proyecto Web
cat > ~/dotfiles/activate-web.sh << 'EOF'
#!/bin/bash
echo "🌐 Activando entorno Web..."
cd ~/dotfiles
# Unstow otros
stow -D python-dev/nvim 2>/dev/null || true
stow -D latex-writing/nvim 2>/dev/null || true
# Stow común
stow common/*
# Stow Web
stow web-dev/*
# Shell config
cp web-dev/shell/.zshrc.project ~/.zshrc.project
echo "✅ Entorno Web activado"
EOF
chmod +x ~/dotfiles/activate-web.sh14.10.6 Paso 5: Uso
14.10.7 Paso 6: Automatizar con Direnv (Avanzado)
15 Mi Repositorio .dotfiles
15.1 Mi Estructura Actual
~/dotfiles/
├── git/
│ └── .gitconfig
├── kde/
│ └── .config/
│ ├── kdeglobals
│ ├── dolphinrc
│ └── ...
├── shell/
│ ├── .zshrc
│ └── starship.toml
├── terminal/
│ └── .config/
│ └── konsolerc
├── vscode/
│ └── .config/
│ ├── settings.json
│ └── keybindings.json
├── zotero/
│ └── .zotero/...
├── obsidian/
│ └── Documents/thoughts/.obsidian/
└── ... (más paquetes)15.2 Implementación de Stow
15.2.1 Script install.sh
Mi install.sh actual debe usar Stow. Aquí está mi versión mejorada:
#!/bin/bash
# ~/dotfiles/install.sh
set -e
DOTFILES="$HOME/dotfiles"
BACKUP_DIR="$HOME/dotfiles-backup-$(date +%Y%m%d-%H%M%S)"
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Funciones
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Verificar que Stow está instalado
if ! command -v stow &> /dev/null; then
log_error "Stow no está instalado"
log_info "Instalando stow..."
sudo apt update && sudo apt install -y stow
fi
# Función para hacer backup
backup_if_exists() {
local file="$1"
if [ -e "$file" ] && [ ! -L "$file" ]; then
mkdir -p "$BACKUP_DIR"
cp -r "$file" "$BACKUP_DIR/"
log_warn "Backup: $file -> $BACKUP_DIR/"
fi
}
# Función para stow paquete
stow_package() {
local package="$1"
log_info "Stowing $package..."
# Dry run primero
if stow -nv "$package" 2>&1 | grep -q "WARNING"; then
log_warn "Conflicto detectado para $package"
read -p "¿Hacer backup y continuar? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Hacer backup de archivos conflictivos
# (aquí necesitarías lógica más sofisticada)
stow "$package"
else
log_error "Saltando $package"
return 1
fi
else
stow "$package"
log_info "✓ $package instalado"
fi
}
# Cambiar a dotfiles directory
cd "$DOTFILES" || exit 1
# Lista de paquetes a instalar
PACKAGES=(
"git"
"shell"
"terminal"
"kde"
"vscode"
"nvim"
"kitty"
# ... más paquetes
)
# Opción para instalar todo o selectivo
if [ "$1" == "all" ]; then
PACKAGES=($(ls -d */ | sed 's#/#'))
log_info "Instalando TODOS los paquetes"
elif [ $# -gt 0 ]; then
PACKAGES=("$@")
log_info "Instalando paquetes especificados: ${PACKAGES[*]}"
fi
# Instalar paquetes
for package in "${PACKAGES[@]}"; do
stow_package "$package" || true
done
log_info "Instalación completa!"
if [ -d "$BACKUP_DIR" ]; then
log_info "Backups guardados en: $BACKUP_DIR"
fiUso:
15.2.2 Script para Desinstalar
#!/bin/bash
# ~/dotfiles/uninstall.sh
DOTFILES="$HOME/dotfiles"
cd "$DOTFILES" || exit 1
if [ $# -eq 0 ]; then
echo "Uso: $0 <paquete1> [paquete2] ..."
echo "O: $0 all"
exit 1
fi
if [ "$1" == "all" ]; then
PACKAGES=($(ls -d */ | sed 's#/#'))
else
PACKAGES=("$@")
fi
for package in "${PACKAGES[@]}"; do
echo "Unstowing $package..."
stow -D "$package"
echo "✓ $package desinstalado"
done15.2.3 Reorganizar Paquetes Problemáticos
Zotero: Ubicación no estándar
# Actual:
zotero/
└── .zotero/zotero/25vfdnq5.default/
└── prefs.js
# Problema: .zotero está en HOME pero tiene subdirectorios profundos
# Solución 1: Usar como está (funciona)
stow zotero
# Resultado: ~/.zotero/... → dotfiles/zotero/.zotero/...
# Solución 2: Si solo quieres prefs.js, simplificar:
zotero/
└── .zotero/
└── zotero/
└── 25vfdnq5.default/
└── prefs.jsObsidian: Ruta específica
15.2.4 .stowrc
Crear ~/dotfiles/.stowrc:
Con esto, no necesitas especificar -t ~ cada vez.
15.2.5 .stow-local-ignore por Paquete
Para vscode:
Para kde:
Para shell:
15.2.6 Script de Verificación
#!/bin/bash
# ~/dotfiles/check-stow.sh
# Verificar qué está stowed
DOTFILES="$HOME/dotfiles"
echo "Paquetes stowed:"
echo "================"
cd "$DOTFILES" || exit 1
for package in */; do
package=${package%/}
# Encontrar primer archivo del paquete
first_file=$(find "$package" -type f | head -1)
if [ -z "$first_file" ]; then
continue
fi
# Convertir a path en HOME
home_path="$HOME/${first_file#$package/}"
if [ -L "$home_path" ]; then
target=$(readlink "$home_path")
if [[ "$target" == *"$DOTFILES/$package"* ]]; then
echo "✓ $package"
else
echo "✗ $package (symlink apunta a otro lugar)"
fi
else
echo "✗ $package (no stowed)"
fi
done15.2.7 Actualizar .gitignore
# ~/dotfiles/.gitignore
# Backups
*~
*.bak
*.old
*.orig
.*.swp
# Datos sensibles
shell/.zsh_history
shell/.bash_history
.netrc
.authinfo
# Cache y temporales
**/.cache/
**/__pycache__/
**/node_modules/
# Logs
**/*.log
# Sistema
.DS_Store
Thumbs.db
# Archivos de Stow
.stow
# Zotero database (demasiado grande)
zotero/.zotero/zotero/*/zotero.sqlite*
# VSCode workspace storage
vscode/.config/Code/User/workspaceStorage/15.2.8 Comandos Útiles
# Navegar a dotfiles
cd ~/dotfiles
# Instalar todo (primera vez)
./install.sh all
# Instalar paquetes esenciales
./install.sh git shell terminal kde
# Verificar qué está instalado
./check-stow.sh
# Actualizar después de pull
git pull
stow -R */ # Restow todo
# Desinstalar temporalmente para pruebas
stow -D vscode
# hacer pruebas...
stow vscode # Reinstalar
# Agregar nuevo paquete
mkdir new-app
# crear estructura...
stow new-app
git add new-app/
git commit -m "Add new-app"16 Workflows
16.1 Workflow 1: Configuración Inicial
# Paso 1: Crear estructura
mkdir -p ~/dotfiles
cd ~/dotfiles
git init
# Paso 2: Crear paquetes
mkdir -p zsh nvim git
# Paso 3: Mover configs existentes
mv ~/.zshrc zsh/
mv ~/.config/nvim nvim/.config/
mv ~/.gitconfig git/
# Paso 4: Stow
stow zsh nvim git
# Paso 5: Verificar
ls -la ~/.zshrc # debe ser symlink
# Paso 6: Git
git add .
git commit -m "Initial dotfiles"
git remote add origin git@github.com:user/dotfiles.git
git push -u origin main16.2 Workflow 2: Día a Día
# Editar configuración (desde cualquier lugar)
nvim ~/.config/nvim/init.lua # Edita a través del symlink
# Commit cambios
cd ~/dotfiles
git add nvim/
git commit -m "Update nvim config: add new plugin"
git push
# En otra máquina
cd ~/dotfiles
git pull
# Los cambios se reflejan automáticamente (symlinks)16.3 Workflow 3: Nueva Máquina
# Clonar
git clone https://github.com/user/dotfiles.git ~/dotfiles
# Instalar Stow
sudo apt install stow
# Backup existentes (precaución)
mkdir ~/backup
cp ~/.zshrc ~/backup/ 2>/dev/null || true
# Stow
cd ~/dotfiles
stow */
# Verificar
ls -la ~/ | grep '\->'
# Instalar dependencias de apps
# (nvim plugins, zsh plugins, etc)16.4 Workflow 4: Experimentar
# Crear branch de experimento
cd ~/dotfiles
git checkout -b experiment-new-nvim
# Modificar libremente
nvim nvim/.config/nvim/init.lua
# Restow para aplicar
stow -R nvim
# Probar...
# Si funciona:
git checkout main
git merge experiment-new-nvim
# Si no funciona:
git checkout main
stow -R nvim # Vuelve a main automáticamente16.5 Workflow 5: Actualización Limpia
17 Best Practices
17.1 Organización de Paquetes
DO:
DON’T:
17.2 Uso de Ignore Lists
DO:
DON’T:
17.3 Commits y Mensajes
DO:
DON’T:
17.4 Testing Antes de Commit
DO:
DON’T:
17.5 Backup Siempre
DO:
DON’T:
17.6 Documentación
DO:
DON’T:
17.7 Estructura Consistente
DO:
DON’T:
17.8 Versionado
DO:
DON’T:
18 Alternativas a Stow
18.1 Yadm (Yet Another Dotfiles Manager)
Ventajas:
- Git nativo, no symlinks
- Encriptación built-in
- Templates con Jinja2
- Bootstrap scripts
Desventajas:
- Menos control granular
- Todo en un repo
18.2 Chezmoi
Ventajas:
- Templates
- Secrets management
- Cross-platform
- Estado vs archivos
Desventajas:
- Más complejo
- Curva de aprendizaje
18.3 Dotbot
Ventajas:
- Basado en configuración YAML
- Bootstrapping automático
- Plugins
Desventajas:
- Otra herramienta que aprender
- Menos flexibilidad que Stow
18.4 Bare Git Repository
Ventajas:
- Solo Git, no tools extra
- Total control
Desventajas:
- Más manual
- Conflictos con .gitignore
18.5 Comparación
| Característica | GNU Stow | yadm | chezmoi | dotbot | Repositorio Git bare |
|---|---|---|---|---|---|
| Simplicidad | Muy alta | Alta | Media | Alta | Media |
| Flexibilidad | Muy alta | Media | Muy alta | Media | Muy alta |
| Soporte para plantillas | No | Parcial | Completo (Jinja2) | No | No |
| Manejo de secretos | No | Bueno | Excelente (integrado) | No | No |
| Facilidad de instalación | Muy sencilla | Muy sencilla | Muy sencilla | Muy sencilla | Sin instalación adicional |
| Tamaño de la comunidad | Grande | Mediana | Grande | Pequeña | N/A (herramienta nativa) |
| Curva de aprendizaje | Baja | Baja | Media-alta | Baja | Media |
| Uso de enlaces simbólicos | Sí (principal) | No | Sí (opcional) | Sí | No |
| Soporte multiplataforma | Excelente | Bueno | Excelente | Bueno | Excelente |
Recomendación: Stow es ideal si quieres:
- Simplicidad
- Control total
- Organización por paquetes
- Solo symlinks, sin magia
19 Conclusión
La gestión de dotfiles es una práctica esencial para optimizar el entorno de desarrollo y asegurar la persistencia de las configuraciones personalizadas. GNU Stow, en particular, se destaca por su simplicidad y eficacia al manejar enlaces simbólicos, especialmente cuando se combina con Git para el versionado y la sincronización. Permite una modularidad excelente y una replicación rápida de entornos.
Si bien existen alternativas más avanzadas como Chezmoi o YADM (que ofrecen funciones adicionales como plantillas y cifrado de secretos) o soluciones declarativas como NixOS/Home-Manager, Stow sigue siendo una opción robusta y preferida por muchos por su enfoque directo y la curva de aprendizaje mínima. La clave es elegir la herramienta que mejor se adapte a las necesidades y al nivel de complejidad deseado, siempre priorizando la seguridad de la información sensible.
19.1 Comandos Esenciales
19.2 Recursos Adicionales
Documentación:
- Manual oficial:
man stow - Info pages:
info stow - Web: https://www.gnu.org/software/stow/
Comunidad:
- r/unixporn (ejemplos de dotfiles)
- GitHub topic: dotfiles
- YouTube: “dotfiles management”
Ejemplos de dotfiles con Stow:
- https://github.com/search?q=stow+dotfiles
- https://dotfiles.github.io/
20 Publicaciones Similares
Si te interesó este artículo, te recomendamos que explores otros blogs y recursos relacionados que pueden ampliar tus conocimientos. Aquí te dejo algunas sugerencias:
- Comandos De Informacion Windows
- Adb
- Limpieza Y Optimizacion De Pc
- Scrcpy
- Gestionar Versiones De Jdk En Kubuntu
- Instalar Tor Browser
- Crear Enlaces Duros O Hard Link En Linux
- Comandos Vim
- Guia De Git Y Github
- 00 Primeros Pasos En Linux
- 01 Introduccion Linux
- 02 Distribuciones Linux
- 03 Instalacion Linux
- 04 Administracion Particiones Volumenes
- Atajos De Teclado Y Comandos Para Usar Vim
- Instalando Specitify
- Gestiona Tus Dotfiles Con Gnu Stow
- Guia De Ranger
- Guia De Kitty Terminal
- Guia De Positron Ide
- Guia De Rsync
Esperamos que encuentres estas publicaciones igualmente interesantes y útiles. ¡Disfruta de la lectura!