¿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 mantenibleInstalación
Linux
Ubuntu/Debian:
Arch Linux:
Fedora/RHEL:
openSUSE:
macOS
Desde Fuente
Verificar Instalación
Conceptos Fundamentales
Terminología Clave
Package (Paquete)
Una colección relacionada de archivos y directorios que administras como una unidad.
Target Directory (Directorio Objetivo)
El directorio raíz donde quieres que aparezcan instalados tus paquetes.
Stow Directory (Directorio Stow)
El directorio raíz que contiene todos tus paquetes en subdirectorios separados.
Installation Image (Imagen de Instalación)
La estructura de archivos y directorios requerida por un paquete, relativa al target directory.
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.
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/ │
└─────────────────────────────────────────┘
Sintaxis y Comandos
Sintaxis Básica
Acciones Principales
Stow (Instalar)
Delete (Desinstalar)
Restow (Reinstalar)
Opciones de Directorio
-d / --dir (Stow Directory)
-t / --target (Target Directory)
Ejemplo completo:
Opciones de Simulación y Verbosidad
-n / --no / --simulate (Dry Run)
-v / --verbose (Verbosidad)
Ejemplo:
Opciones Avanzadas
--ignore (Ignorar Archivos)
--defer (Diferir)
--override (Sobrescribir)
--dotfiles (Modo Dotfiles)
--no-folding (Sin Tree Folding)
--adopt (Adoptar Archivos)
Combinando Operaciones
Estructura de Directorios
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
└── kwinrcPrincipios de Organización
Un Directorio = Un Paquete
Replicar Estructura del HOME
Agrupar Lógicamente
Ejemplos de Estructuras
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:
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.luaInstalación de Paquetes
Proceso de Instalación
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/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/Instalación Básica
Instalación con Verificación
Instalación Selectiva
Desinstalación de Paquetes
Proceso de Desinstalación
Eliminación de Symlinks
Eliminación de Directorios Vacíos
Tree Refolding (Re-plegado)
Después de eliminar symlinks, si un directorio contiene solo symlinks a un único paquete, Stow lo “re-pliega”.
Escenario:
Desinstalación Básica
Desinstalación con Verificación
Desinstalación Parcial
Reinstalación de Paquetes
Comando Restow
Cuándo Usar Restow
1. Después de actualizar un paquete:
2. Para limpiar symlinks obsoletos:
3. Después de cambiar estructura:
Restow vs Delete + Stow
Gestión de Dotfiles
Setup Inicial
Crear Estructura
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 gitUsar --adopt (Con Precaución)
Workflow Diario
Editar Configuraciones
Agregar Nueva Aplicación
Sincronizar con Git
Manejo de Archivos Sensibles
Estrategia 1: .gitignore
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"
fiEstrategia 3: Encriptación
Estructura para Múltiples Hosts
Script de instalación por host:
Ignore Lists
Tipos de Ignore Lists
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
Global Ignore List
Archivo: ~/.stow-global-ignore
Package-Local Ignore List
Archivo: <package>/.stow-local-ignore
Sintaxis de Ignore Lists
Reglas de Matching
1. Expresiones con / (path completo):
2. Expresiones sin / (basename):
Ejemplos Prácticos
Ejemplo 1: Ignorar documentación:
Ejemplo 2: Ignorar archivos temporales:
Ejemplo 3: Ignorar por aplicación:
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
Opción --ignore en CLI
Opciones Avanzadas
Tree Folding Control
--no-folding
Desactiva tree folding completamente.
Sin –no-folding (default):
Con –no-folding:
Uso:
Adopt Mode
--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:
Defer y Override
--defer
Evita stowing si el archivo ya está stowed por otro paquete.
Escenario:
--override
Fuerza stowing incluso si ya existe symlink de otro paquete.
Escenario:
Dotfiles Mode
--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-.
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.
Integración con Git
Estructura de Repositorio
.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/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"Branches Strategy
Submodules para Plugins
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
fiTroubleshooting
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
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
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:
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:
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:
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:
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:
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:
Scripts de Automatización
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 "$@"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!"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"
fiScript 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!"Casos de Uso Prácticos
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.
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"Paso 2: Crear Estructura de Paquetes
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/Paso 4: Crear Ignore Lists
4.1 Global ignore:
4.2 Ignore por paquete (shell):
4.3 Ignore para VSCode:
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
EOFPaso 6: Crear .stowrc
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/konsolercPaso 8: Verificar que Todo Funciona
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.shPaso 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 mainPaso 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 pushCaso 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.
Paso 1: Preparar Nueva Máquina
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"Paso 3: Clonar Repositorio
Paso 4: Revisar y Ajustar (Si Necesario)
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 codePaso 6: Dry Run (Simulación)
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:
Paso 8: Instalar Todo
Opción A: Con script (recomendado):
Opción B: Manual:
Opción C: Todo de una vez:
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.shPaso 10: Configurar Shell
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):
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 KDEPaso 13: Ajustes Finales
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.
Paso 1: Identificar Cambios
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 nuevoPaso 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"Paso 4: Push a GitHub
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 vscodePaso 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 pushCaso 4: Agregar Nueva Aplicación (Kate Editor)
Escenario: Instalaste Kate y quieres agregar su configuración a tus dotfiles.
Paso 1: Usar Kate y Configurar
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 katePaso 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/Paso 4: Crear Ignore List para Kate
Paso 5: Test Stow (Dry Run)
Paso 6: Hacer Backup y Eliminar Original
Paso 7: Stow Kate
Paso 8: Versionar con Git
Paso 9: Actualizar README
Paso 10: Actualizar Script de Instalación
Caso 5: Migrar de Kubuntu a Archcraft
Escenario: Usabas Kubuntu, ahora instalaste Archcraft. Quieres migrar tus dotfiles pero adaptándolos.
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 KubuntuPaso 2: En Archcraft Nueva
Paso 3: Crear Branch para Archcraft
Paso 4: Instalar Paquetes Universales
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):
Paso 6: No Instalar Paquetes Incompatibles
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-setupPaso 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 */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.shPaso 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áticamenteCaso 6: Probar Nueva Configuración Sin Romper
Escenario: Quieres probar una nueva configuración de Neovim sin afectar tu setup actual.
Paso 1: Crear Branch Experimental
Paso 2: Crear Paquete Alternativo
Paso 3: Desinstalar Neovim Actual
Paso 4: Instalar Nueva Config
Paso 5: Probar
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):
Caso 7: Sincronizar Múltiples Máquinas en Tiempo Real
Escenario: Trabajas en 3 máquinas (desktop, laptop, servidor) y quieres mantener dotfiles sincronizados.
Configuración Inicial (Una Vez)
Workflow Diario
Máquina A (Desktop) - Hacer Cambios:
Máquina B (Laptop) - Recibir Cambios:
Máquina C (Servidor) - Recibir Cambios:
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.shManejar 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
EOFUsar 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-commitCaso 8: Compartir Dotfiles con Equipo/Lab
Escenario: Trabajas en un lab con múltiples usuarios y quieren compartir configuraciones base.
Paso 1: Crear Repo de Equipo
Paso 2: Estructura Multi-Usuario
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
EOFPaso 4: Configs Personales
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.shPaso 6: Cada Usuario Instala
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 symlinksPaso 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 afectanCaso 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.
Estado Inicial
Paso 1: Backup Completo
Paso 2: Crear Nueva Estructura
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/Paso 4: Verificar Nueva Estructura
Paso 5: Eliminar Symlinks/Archivos Viejos de HOME
Paso 6: Instalar con Stow
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 mainPaso 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 pushPaso 9: Crear Scripts
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 mainCaso 10: Setup para Desarrollo Multi-Proyecto
Escenario: Trabajas en múltiples proyectos (Python, Web, Latex) y quieres configs específicas por proyecto.
Estructura de Dotfiles
Paso 1: Crear Estructura
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
EOFPaso 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
}
EOFPaso 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.shPaso 5: Uso
Paso 6: Automatizar con Direnv (Avanzado)
Mi Repositorio .dotfiles
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)Implementación de Stow
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:
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"
doneReorganizar 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
.stowrc
Crear ~/dotfiles/.stowrc:
Con esto, no necesitas especificar -t ~ cada vez.
.stow-local-ignore por Paquete
Para vscode:
Para kde:
Para shell:
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
doneActualizar .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/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"Workflows
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 mainWorkflow 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)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)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áticamenteWorkflow 5: Actualización Limpia
Best Practices
Organización de Paquetes
DO:
DON’T:
Uso de Ignore Lists
DO:
DON’T:
Commits y Mensajes
DO:
DON’T:
Testing Antes de Commit
DO:
DON’T:
Backup Siempre
DO:
DON’T:
Documentación
DO:
DON’T:
Estructura Consistente
DO:
DON’T:
Versionado
DO:
DON’T:
Alternativas a Stow
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
Chezmoi
Ventajas:
- Templates
- Secrets management
- Cross-platform
- Estado vs archivos
Desventajas:
- Más complejo
- Curva de aprendizaje
Dotbot
Ventajas:
- Basado en configuración YAML
- Bootstrapping automático
- Plugins
Desventajas:
- Otra herramienta que aprender
- Menos flexibilidad que Stow
Bare Git Repository
Ventajas:
- Solo Git, no tools extra
- Total control
Desventajas:
- Más manual
- Conflictos con .gitignore
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
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.
Comandos Esenciales
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/
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
- Usando Apk En Windown 11
- 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
Esperamos que encuentres estas publicaciones igualmente interesantes y útiles. ¡Disfruta de la lectura!