Todo lo que hemos visto en el módulo daba por supuesta una cosa: que la base de datos de objetos estaba sana. El reflog encontraba el hash, git branch creaba el puntero, git show leía el commit. Los objetos estaban donde tenían que estar y su contenido era el correcto.
Esta lección se ocupa de cuando no lo está.
error: object file .git/objects/4f/8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a is empty fatal: loose object 4f8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a (stored in .git/objects/4f/8a2e6...) is corrupt
Es el mensaje que más asusta de todo el curso, y hay que empezar por dos cosas.
La primera es que casi nunca es corrupción de verdad. La mayoría de los mensajes alarmantes tienen causas mundanas: un disco lleno, un proceso interrumpido, un antivirus que bloqueó un fichero. Antes de "reparar" nada, hay que descartar eso.
La segunda es la que hace habitable esta lección: en un sistema distribuido, cada clon es una copia de seguridad casi completa. El repositorio de Bruno tiene los mismos objetos que el tuyo. El servidor también. Ese es, casi siempre, el camino de recuperación más rápido, y muchas veces el correcto es directamente volver a clonar en lugar de intentar arreglar nada.
Vamos a ver cómo distinguir corrupción real de otra cosa, cómo leer git fsck sin asustarse, cómo reparar los casos frecuentes ordenados de menor a mayor gravedad, y —lo más importante— cuándo dejar de intentarlo.
Contenido
- Cuándo sospechar corrupción y cuándo es otra cosa
- Las causas reales de la corrupción
git fsckcomo herramienta de diagnóstico- Reparaciones, de menor a mayor gravedad
- La red de seguridad del modelo distribuido
- Reconstruir un repositorio conservando tu trabajo
- Prevención: mantenimiento y copias de seguridad de verdad
- Cuándo dejar de reparar y volver a clonar
- Cuándo sospechar corrupción y cuándo es otra cosa
Antes de nada, la tabla de descarte. Muchos errores que parecen corrupción no lo son.
| Mensaje / síntoma | ¿Es corrupción? | Causa real y solución |
|---|---|---|
fatal: Unable to create '.git/index.lock': File exists |
No | Cerrojo huérfano (09-01, apartado 5.5) |
error: insufficient permission for adding an object |
No | Permisos: se usó sudo alguna vez. chown -R |
fatal: detected dubious ownership |
No | Propiedad del directorio (09-01, apartado 5.6) |
error: cannot open .git/objects/...: No space left on device |
No aún, pero lo será | Disco lleno. Libera espacio ANTES de seguir |
fatal: bad object HEAD |
Quizá | HEAD roto (apartado 4.5) o repositorio vacío |
warning: ignoring dangling symref |
No | Referencia simbólica a algo inexistente. Inofensivo |
dangling commit / blob / tree en fsck |
No | Completamente normal (09-04) |
error: object file ... is empty |
Sí | Fichero de objeto de 0 bytes. Apartado 4.4 |
fatal: loose object ... is corrupt |
Sí | El contenido no coincide con su hash. Apartado 4.4 |
error: refs/heads/x does not point to a valid object! |
Sí | Referencia rota. Apartado 4.3 |
missing blob / broken link from en fsck |
Sí | Falta un objeto necesario. Apartado 3 |
fatal: index file smaller than expected |
Sí, pero leve | Índice corrupto (apartado 4.1): es un caché |
error: bad signature 0x00000000 |
Sí, leve | Lo mismo: índice corrupto |
fatal: packed object ... cannot be read |
Sí, grave | Packfile dañado. Apartado 4.4 |
| Todo va lento pero funciona | No | Rendimiento (08-06) |
El descarte previo, en tres comandos
Antes de tocar nada de .git:
Si ves Use% 100%, ese es el problema. Libera espacio antes de seguir; cualquier reparación va a escribir objetos y fallará igual.
# 2. ¿Es mío el repositorio? ¿Tengo permisos?
ls -ld .git .git/objects
find .git -not -user "$(id -un)" | headSi en lugar de ext4/apfs/ntfs local ves nfs, cifs, fuse.sshfs o una ruta dentro de Dropbox, OneDrive, iCloud o Google Drive, ya tienes la explicación, y es el apartado 2.
- Las causas reales de la corrupción
Git es notablemente robusto. Los objetos son inmutables, se escriben una vez, y cada uno lleva su propia suma de verificación: el nombre del objeto es el hash de su contenido, así que cualquier alteración se detecta al leerlo (lección 01-04). La corrupción, cuando ocurre, casi siempre viene de fuera.
| Causa | Cómo ocurre | Frecuencia |
|---|---|---|
| Repositorio en carpeta sincronizada con la nube | Dropbox/OneDrive/iCloud/Drive sincronizan ficheros de .git en pleno commit, o resuelven "conflictos" duplicando ficheros |
La más común con diferencia |
| Disco lleno | Git escribe un objeto a medias y no puede terminarlo | Muy común |
Apagón o cierre forzado durante un commit/gc |
Escritura interrumpida | Común en portátiles |
.git en un volumen de red (NFS, SMB, sshfs) |
Bloqueos y mtime poco fiables, escrituras reordenadas |
Común en entornos corporativos |
| Antivirus | Bloquea o pone en cuarentena ficheros de .git/objects |
Común en Windows |
| Matar procesos de Git a lo bruto | kill -9 durante gc o repack |
Ocasional |
| Disco con sectores defectuosos | Hardware que falla | Rara, pero grave |
Editar ficheros de .git a mano |
"Voy a arreglar esto con un editor de texto" | Autoinfligida |
El caso de la nube, que merece énfasis
No pongas un repositorio Git dentro de una carpeta sincronizada por la nube.
Es la causa clásica, y el razonamiento es sencillo: Git escribe muchos ficheros pequeños en un orden concreto (objeto, luego índice, luego referencia). Un sincronizador los sube según su propio criterio y velocidad. Si trabajas desde dos máquinas, el sincronizador puede combinar un .git/index de una con las referencias de la otra, o crear ficheros del tipo main (conflicted copy 2026-07-28).lock.
El resultado es un repositorio en un estado que Git nunca podría haber producido.
Y lo irónico: no hace ninguna falta. Git ya es un sistema de sincronización distribuido. Para tener el proyecto en dos máquinas, la respuesta es un remoto, no Dropbox.
# Si te encuentras en esta situación: saca el repositorio de la carpeta sincronizada
mv ~/Dropbox/gestor-tareas ~/proyectos/gestor-tareas
cd ~/proyectos/gestor-tareas
git fsck --full # comprobar los dañosSi de verdad necesitas que un repositorio viva ahí, la única forma segura es que sea un repositorio desnudo (--bare) usado como remoto, al que nunca se escribe desde dos sitios a la vez. Aun así, git bundle (apartado 7) es mejor idea.
La comprobación de antivirus en Windows
Si Carla trabaja en Windows 11 y sufre errores intermitentes:
Y en Git for Windows, un ajuste que reduce problemas con antivirus y con sistemas de ficheros lentos:
git fsck como herramienta de diagnóstico
git fsck como herramienta de diagnósticogit fsck (file system check) recorre la base de objetos, verifica que el contenido de cada objeto coincide con su hash, y comprueba que todas las referencias entre objetos se resuelven.
Opciones útiles:
| Opción | Qué hace |
|---|---|
--full |
Comprueba también los objetos dentro de packfiles (por defecto solo los sueltos) |
--no-progress |
Sin barra de progreso: mejor para redirigir a un fichero |
--lost-found |
Crea enlaces en .git/lost-found/ (09-04) |
--unreachable |
Lista también lo inalcanzable contando el reflog |
--connectivity-only |
Rápido: solo comprueba enlaces, no verifica hashes |
--strict |
Más severo: avisa de cosas que Git tolera |
--dangling / --no-dangling |
Mostrar u ocultar los colgantes |
Leer la salida: lo normal frente a lo grave
Esta es la tabla que evita el pánico innecesario.
Línea de fsck |
Gravedad | Qué significa | Qué hacer |
|---|---|---|---|
dangling commit <sha> |
Ninguna | Commit que ninguna referencia alcanza | Nada. Es normal tras reset, rebase, --amend |
dangling blob <sha> |
Ninguna | Contenido de un git add sin confirmar |
Nada (o recuperarlo, 09-04) |
dangling tree <sha> |
Ninguna | Directorio sin commit que lo use | Nada |
unreachable <tipo> <sha> |
Ninguna | Igual, contando el reflog | Nada |
notice: HEAD points to an unborn branch |
Ninguna | Repositorio recién creado sin commits | Nada |
warning: ... has zero-padded file modes |
Muy baja | Repositorio antiguo o importado | Nada, o fsck.zeroPaddedFilemode ignore |
warning: ... missingSpaceBeforeDate |
Muy baja | Metadatos malformados de una importación | Nada |
error: <sha>: object corrupt or missing |
ALTA | El objeto no se puede leer | Apartado 4.4 |
missing blob <sha> |
ALTA | Un árbol referencia un blob que no existe | Apartado 4.4 |
missing tree <sha> |
ALTA | Un commit referencia un árbol inexistente | Apartado 4.4 |
broken link from <sha> to <sha> |
ALTA | Un objeto apunta a otro que falta | Apartado 4.4 |
error: refs/heads/x does not point to a valid object! |
ALTA | Referencia rota | Apartado 4.3 |
dangling commit en cantidades enormes |
Media | Puede indicar un gc interrumpido |
git gc |
La regla de oro para leer fsck:
# Ocultar el ruido normal y quedarse SOLO con lo importante
git fsck --full --no-progress 2>&1 | grep -v "^dangling" | grep -v "^notice"Si eso no devuelve nada, tu repositorio está sano. Punto. Todo lo que hayas visto era ruido.
# Y para separar por gravedad
git fsck --full --no-progress 2>&1 | grep -E "^(error|missing|broken)"Un ejemplo de salida sana
Checking object directories: 100% (256/256), done. Checking objects: 100% (18432/18432), done. dangling commit 9c4e7b2e4a7f3c8b6d2e9a5f1c7b3d8e4a6f2c9b dangling blob 6f2b9d4a8c1e5f3b7d9a2c6e4f8b1d3a5c7e9f2b dangling commit 3e7f1a8b6d2e9a5f1c7b3d8e4a6f2c9b7d3a8f4a
Tres líneas alarmantes en apariencia, cero problemas. Son los restos del reset --hard de la semana pasada y de un git add que no llegó a confirmarse. Un repositorio activo siempre tiene esto.
Un ejemplo de salida grave
Checking object directories: 100% (256/256), done.
error: refs/heads/GT-241 does not point to a valid object!
error: object file .git/objects/4f/8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a is empty
fatal: loose object 4f8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a is corrupt
missing blob 8a1f6c3d5e2b9c7f4a6d1e8b3c5f7a9d2e4b6c8a
broken link from tree 2f8c6e1a4b7d9c3e5f2a8b6d1c9e4f7a3b5d2c8e
to blob 8a1f6c3d5e2b9c7f4a6d1e8b3c5f7a9d2e4b6c8aAquí sí hay trabajo. Una referencia rota y un objeto ilegible, con el árbol que lo necesita identificado. Es el apartado 4.
Comprobar un objeto concreto
Ese mensaje, para un hash que sabes que existía, es la confirmación de que el objeto ha desaparecido.
- Reparaciones, de menor a mayor gravedad
4.1. .git/index corrupto (el caso más frecuente y más leve)
o
No has perdido nada. Y la razón es conceptualmente importante:
El índice es un caché derivado. No contiene información única: es una foto de qué debería haber en el próximo commit, reconstruible enteramente a partir de
HEADy del directorio de trabajo.
Por eso la reparación es de las más agradecidas de Git:
# 1. Quitar el índice roto
rm -f .git/index
# 2. Reconstruirlo desde HEAD
git reset
# 3. Comprobar
git statusLo único que se pierde es qué estaba preparado con git add: tras la reconstrucción, todas tus modificaciones aparecen como no preparadas. Los cambios en sí están intactos, porque viven en los ficheros del disco, no en el índice.
Un matiz importante: usa git reset (--mixed), nunca git reset --hard. El primero reconstruye el índice y deja el directorio de trabajo en paz; el segundo se llevaría por delante todas tus modificaciones (lección 09-02).
Si además tenías un conflicto de fusión a medias, la información de las etapas del índice (:1:, :2:, :3: de la lección 03-05) sí se pierde, y hay que rehacer la fusión:
git merge --abort 2>/dev/null || true
rm -f .git/index
git reset
git merge <rama> # volver a empezar4.2. Cerrojos huérfanos
Ya visto en la lección 09-01, aquí en su versión completa. Los cerrojos son ficheros .lock que Git crea antes de escribir y borra al terminar:
El procedimiento:
# 1. SIEMPRE primero: ¿hay algún Git ejecutándose?
ps aux | grep "[g]it "
# 2. ¿De cuándo son?
ls -l $(find .git -name "*.lock")
# 3. Si no hay procesos y son antiguos, borrarlos
find .git -name "*.lock" -delete
# 4. Comprobar
git statusUn caso especial que merece cuidado: .git/config.lock. Si Git murió escribiendo la configuración, el fichero .git/config puede haber quedado truncado. Compruébalo antes de borrar el cerrojo:
Si está roto, la configuración local es lo más fácil de rehacer a mano de todo el repositorio.
4.3. Referencias rotas
Qué es. El fichero refs/heads/GT-241 contiene un hash que no corresponde a ningún objeto existente. Recuerda que una rama son 41 bytes de texto (lección 03-01):
Confirmado: la referencia apunta al vacío.
Reparación A: el reflog de la rama. Es la mejor opción, porque conserva historia:
b52c9d1 GT-241@{0}: commit: GT-241 estilos del indicador
7d3a8f4 GT-241@{1}: commit: GT-241 calcular el contador
4f8a2e6 GT-241@{2}: branch: Created from mainPrueba las entradas de arriba abajo hasta encontrar una válida:
git cat-file -t 7d3a8f4 # commit → esta sí existe
git update-ref refs/heads/GT-241 7d3a8f4
git log --oneline GT-241 -3Has perdido el último commit, pero recuperas la rama. Mucho mejor que nada.
Reparación B: packed-refs. Las referencias también viven consolidadas en un fichero (lección 08-06):
A veces la versión empaquetada es válida aunque la suelta esté rota. Borrando la suelta, Git usa la empaquetada:
Reparación C: el remoto.
Reparación D: si la rama no importa, borrarla.
Y la limpieza masiva, cuando hay muchas referencias rotas:
# Ver todas las referencias y su validez
git for-each-ref --format='%(refname) %(objectname)' | while read -r ref sha; do
git cat-file -e "$sha" 2>/dev/null || echo "ROTA: $ref -> $sha"
done4.4. Objetos sueltos ilegibles o ausentes
Este es el caso serio.
error: object file .git/objects/4f/8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a is empty fatal: loose object 4f8a2e6... is corrupt
Primer paso, el diagnóstico exacto:
Cero bytes: escritura interrumpida. Es el patrón típico de disco lleno o apagón.
# ¿Qué se supone que era? (a menudo se puede deducir del contexto de fsck)
git fsck --full --no-progress 2>&1 | grep -A2 "4f8a2e6"broken link from tree 2f8c6e1a4b7d9c3e5f2a8b6d1c9e4f7a3b5d2c8e
to blob 4f8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9aLa reparación que casi siempre funciona: traerlo de otro clon.
Esta es la idea central de la lección y el apartado 5 la desarrolla. Los objetos de Git son idénticos en todas partes: el mismo contenido produce el mismo hash y el mismo fichero comprimido. Si Bruno tiene ese commit, su objeto sirve exactamente igual.
# 1. Quitar el objeto roto (¡de cero bytes: no hay nada que perder!)
rm .git/objects/4f/8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a
# 2. Traerlo del remoto: la forma sencilla
git fetch origin --force '+refs/heads/*:refs/remotes/origin/*'
# 3. O copiarlo directamente de otro clon
cp /ruta/al/clon/de/bruno/.git/objects/4f/8a2e6c9b1d5e3a... \
.git/objects/4f/
# 4. Comprobar
git fsck --full --no-progress 2>&1 | grep -E "^(error|missing|broken)"Si el otro clon lo tiene empaquetado en lugar de suelto, hay que extraerlo:
# En el clon sano:
cd /ruta/al/clon/de/bruno
git cat-file -p 4f8a2e6 > /tmp/objeto-recuperado
# En el repositorio roto:
cd ~/proyectos/gestor-tareas
git hash-object -w -t blob /tmp/objeto-recuperadoSi el hash resultante coincide con el que faltaba, la reparación es exacta. Y no puede no coincidir: el hash se calcula del contenido, así que si sale otro, el contenido no era el mismo (lección 01-04).
Para un objeto de tipo tree o commit, el mismo procedimiento con -t tree / -t commit y el contenido exacto que da cat-file -p en el clon sano.
Si el objeto era un packfile dañado:
Un packfile roto es peor, porque contiene miles de objetos y las cadenas de delta dependen unas de otras (lección 08-06). Se puede intentar extraer lo salvable:
# Mover el pack roto fuera y ver qué sobrevive
mkdir -p /tmp/packs-rotos
mv .git/objects/pack/pack-a1b2c3.* /tmp/packs-rotos/
git fsck --full --no-progress
# Intentar recuperar objetos individuales del pack roto
git verify-pack -v /tmp/packs-rotos/pack-a1b2c3.idx 2>/dev/null | headPero seamos claros: con un packfile dañado, la respuesta correcta casi siempre es reclonar (apartado 8). Extraer objetos de un pack roto es un ejercicio de arqueología que rara vez compensa cuando hay un clon sano a un git clone de distancia.
4.5. HEAD roto
HEAD es un fichero de texto de una línea (lección 03-01):
Lo que debería contener:
Lo que puede haber pasado:
Contenido de .git/HEAD |
Problema | Reparación |
|---|---|---|
ref: refs/heads/rama-borrada |
La rama no existe | git symbolic-ref HEAD refs/heads/main |
| Vacío o basura binaria | Escritura interrumpida | Reescribirlo |
Un hash suelto (sin ref:) |
Detached HEAD: no es un error | git switch main |
| Un hash de un objeto inexistente | Corrupción real | Apuntar a una rama válida |
# Ver qué ramas hay realmente
ls .git/refs/heads/
cat .git/packed-refs 2>/dev/null | grep refs/heads
# Reparar apuntando a una rama existente (forma correcta, no editar a mano)
git symbolic-ref HEAD refs/heads/main
# Comprobar
git status
git log --oneline -3Si no queda ninguna rama válida, el reflog de HEAD sigue siendo texto plano y legible aunque Git no funcione:
4.6. .git/config corrupto
Es el fichero más fácil de reparar, porque su contenido es trivial de rehacer:
[core]
repositoryformatversion = 0
filemode = true
bare = false
[remote "origin"]
url = git.ejemplo.es:equipo/gestor-tareas.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/mainSi está truncado, edítalo (aquí sí, con un editor de texto: config es texto plano por diseño y Git no lo verifica con hashes) o reconstruye lo esencial:
git remote add origin git.ejemplo.es:equipo/gestor-tareas.git
git branch --set-upstream-to=origin/main main
git config user.name "Ana Ferrer"
git config user.email "[email protected]"Tabla resumen de reparaciones
| Problema | Gravedad | Reparación | ¿Se pierde algo? |
|---|---|---|---|
.git/index corrupto |
Baja | rm .git/index && git reset |
Solo qué estaba preparado |
Cerrojo .lock huérfano |
Baja | Comprobar procesos y borrar | Nada |
.git/config roto |
Baja | Editar o rehacer con git config |
Configuración local |
| Referencia rota | Media | Reflog, packed-refs, o el remoto |
Quizá los últimos commits de esa rama |
HEAD roto |
Media | git symbolic-ref HEAD refs/heads/main |
Nada |
| Objeto suelto ilegible | Alta | Traerlo de otro clon | Nada, si alguien lo tiene |
| Packfile dañado | Muy alta | Reclonar | Solo lo que fuera exclusivamente local |
| Corrupción extendida | Muy alta | Reclonar | Lo mismo |
- La red de seguridad del modelo distribuido
Aquí está la idea que convierte esta lección en algo manejable, y que cierra el círculo del módulo 1.
En un sistema centralizado, el servidor es un punto único de fallo: si se corrompe, se ha corrompido el proyecto. En Git, cada clon contiene todo el historial. Ana, Bruno, Carla, Diego y el servidor tienen cinco copias completas de la base de objetos.
flowchart TD
S["git.ejemplo.es<br/>historia completa"]
A["Ana (Ubuntu)<br/>historia completa<br/>+ GT-241 sin publicar"]
B["Bruno (macOS)<br/>historia completa"]
C["Carla (Windows)<br/>historia completa"]
D["Diego (fork)<br/>historia completa"]
S <--> A
S <--> B
S <--> C
S <--> D
Consecuencia práctica: cuando tu repositorio se corrompe, la pregunta correcta no es "¿cómo lo reparo?" sino "¿qué tengo yo que no tenga nadie más?".
# 1. ¿Qué ramas tengo sin publicar?
git for-each-ref --format='%(refname:short) upstream=[%(upstream:short)]' refs/headsGT-241 no tiene upstream: existe solo en esta máquina. Es lo único que hay que salvar.
# 2. ¿Qué commits tengo por delante del remoto?
git log --oneline origin/main..main
git log --oneline --branches --not --remotes
# 3. ¿Hay stashes?
git stash list
# 4. ¿Hay cambios sin confirmar?
git status --shortCon esas cuatro respuestas ya sabes exactamente cuánto vale la reparación. Si la respuesta es "nada, todo está publicado", reclonar tarda dos minutos y es la solución perfecta.
Y si el problema es del servidor, la dirección se invierte: cualquier clon del equipo puede reconstruirlo.
# Reconstruir el remoto desde un clon sano
cd ~/proyectos/gestor-tareas
git push --all origin
git push --tags origin
# O crear un espejo completo desde cero
git clone --mirror ~/proyectos/gestor-tareas /tmp/gestor-tareas-restaurado.git--mirror copia todas las referencias tal cual: ramas, etiquetas, notas. Es la forma correcta de duplicar un repositorio desnudo.
- Reconstruir un repositorio conservando tu trabajo
El procedimiento completo, cuando has decidido reclonar pero tienes cosas locales que salvar.
Paso 1: la copia de seguridad, siempre
Aunque vayas a reclonar. Cuesta diez segundos y es lo único que impide que un error durante el rescate sea definitivo.
Paso 2: inventario de lo que solo tienes tú
cd ~/proyectos/gestor-tareas
# Ramas sin publicar
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads | awk '$2==""{print $1}'
# Commits locales por delante del remoto, de todas las ramas
git log --oneline --branches --not --remotes
# Stashes
git stash list
# Cambios sin confirmar
git status --short
# Etiquetas locales sin publicar
git tag --no-merged origin/main 2>/dev/nullPaso 3: extraer lo local a un bundle
git bundle empaqueta commits en un solo fichero que funciona como un remoto. Es la herramienta correcta para esto, y funciona incluso si el repositorio está parcialmente dañado (mientras los objetos implicados estén sanos).
# Todo lo que tengo y no está en el remoto
git bundle create /tmp/rescate.bundle --branches --not --remotes
# O solo una rama concreta
git bundle create /tmp/GT-241.bundle GT-241
# Comprobar que el bundle es válido
git bundle verify /tmp/rescate.bundleThe bundle contains these 2 refs: 7d3a8f4a2c6e9b1d5f3a8c6e2b9d4f7a1c5e8b3d refs/heads/GT-241 b52c9d1e4a7f3c8b6d2e9a5f1c7b3d8e4a6f2c9b refs/heads/GT-238 The bundle requires these 1 ref: 4f8a2e6c9b1d5e3a7f2c8b6d9e4a1f5c3b7d2e9a refs/heads/main /tmp/rescate.bundle is okay
Si además tienes cambios sin confirmar, sácalos aparte:
git diff > /tmp/cambios-sin-confirmar.patch
git diff --cached > /tmp/cambios-preparados.patch
# Y los ficheros sin seguimiento, a mano:
cp -a borrador.txt notas.md /tmp/rescate-ficheros/Si git bundle falla porque el repositorio está demasiado dañado, la vía bruta también sirve:
# Copiar los ficheros del proyecto (sin .git) y tratarlos como cambios nuevos
mkdir /tmp/rescate-trabajo
rsync -a --exclude='.git' ~/proyectos/gestor-tareas/ /tmp/rescate-trabajo/Se pierde el historial de las ramas locales, pero se conserva el contenido, que suele ser lo que importaba.
Paso 4: clonar de nuevo
cd ~/proyectos
mv gestor-tareas gestor-tareas-roto
git clone git.ejemplo.es:equipo/gestor-tareas.git
cd gestor-tareasPaso 5: reincorporar lo rescatado
# Traer el bundle como si fuera un remoto
git fetch /tmp/rescate.bundle 'refs/heads/*:refs/heads/*'
git branchLas ramas locales han vuelto, con todos sus commits.
# Los cambios sin confirmar
git apply /tmp/cambios-sin-confirmar.patch
# Los que estaban preparados
git apply --cached /tmp/cambios-preparados.patch
# Los ficheros sin seguimiento
cp -a /tmp/rescate-ficheros/* .Paso 6: verificar y limpiar
git fsck --full --no-progress 2>&1 | grep -E "^(error|missing|broken)"
git log --oneline --all --graph -15
git statusSi no hay errores y todo tu trabajo está ahí:
No borres la copia hasta haber verificado. Es la única regla que importa de este apartado.
El procedimiento en una tabla
| Paso | Comando | Para qué |
|---|---|---|
| 1 | cp -a <repo> <repo>-ROTO-<fecha> |
Red de seguridad |
| 2 | git for-each-ref + git log --branches --not --remotes |
Saber qué es exclusivamente tuyo |
| 3 | git bundle create /tmp/rescate.bundle --branches --not --remotes |
Empaquetar lo local |
| 4 | git clone <url> |
Repositorio limpio |
| 5 | git fetch /tmp/rescate.bundle 'refs/heads/*:refs/heads/*' |
Devolver lo local |
| 6 | git fsck --full + comprobar |
Verificar antes de borrar nada |
- Prevención: mantenimiento y copias de seguridad de verdad
git maintenance y git fsck periódicos
Retomando la lección 08-06:
Además de mejorar el rendimiento, mantiene la base de objetos ordenada y reduce el número de ficheros sueltos expuestos a escrituras interrumpidas.
Y una comprobación periódica, que en un repositorio normal tarda segundos:
# Rápida: solo enlaces, no verifica hashes
git fsck --connectivity-only --no-progress
# Completa: verifica cada objeto contra su hash. Mensual está bien
git fsck --full --no-progress 2>&1 | grep -vE "^(dangling|notice)"Y una configuración que hace que Git verifique los objetos al recibirlos, detectando la corrupción en el momento en lugar de meses después:
git config --global transfer.fsckObjects true
git config --global fetch.fsckObjects true
git config --global receive.fsckObjects trueCuesta un poco de tiempo en cada fetch y a cambio impide que un objeto malformado entre en tu repositorio. En el servidor, receive.fsckObjects es directamente obligatorio.
git bundle: la copia de seguridad de verdad
Un bundle es un único fichero con todo lo que le pidas, que funciona como un remoto. Es portátil, verificable y no depende de ningún servicio.
# Copia completa del repositorio
git bundle create ~/copias/gestor-tareas-$(date +%Y%m%d).bundle --all
# Comprobar
git bundle verify ~/copias/gestor-tareas-20260731.bundle
# Restaurar: se clona como si fuera una URL
git clone ~/copias/gestor-tareas-20260731.bundle gestor-tareas-restauradoY copias incrementales, si el repositorio es grande:
Un guion de copia semanal:
#!/usr/bin/env bash
# copia-git.sh — copia de seguridad de los repositorios de trabajo
DESTINO=~/copias/git
mkdir -p "$DESTINO"
for repo in ~/proyectos/*/; do
[ -d "$repo/.git" ] || continue
nombre=$(basename "$repo")
echo "=== $nombre ==="
git -C "$repo" bundle create "$DESTINO/$nombre-$(date +%Y%m%d).bundle" --all \
&& git -C "$repo" bundle verify "$DESTINO/$nombre-$(date +%Y%m%d).bundle" > /dev/null \
&& echo " OK" || echo " FALLÓ"
done
# Conservar solo las 8 copias más recientes de cada repositorio
find "$DESTINO" -name "*.bundle" -mtime +56 -deletePor qué un bundle es mejor que copiar .git con cp:
cp -a .git |
git bundle |
|
|---|---|---|
| Coherencia si hay un Git escribiendo | Puede copiar un estado a medias | Coherente: Git lo genera |
| Verificable | No | Sí: git bundle verify |
| Tamaño | Todo, incluidos objetos huérfanos | Solo lo alcanzable, comprimido |
| Restauración | Copiar de vuelta | git clone <fichero> |
| Portátil (correo, USB) | Miles de ficheros | Un fichero |
La lista de prevención
1. Nunca un repositorio en una carpeta sincronizada por la nube. La causa número uno. Usa un remoto.
2. Nunca .git en un volumen de red si puedes evitarlo. Clona en local y publica.
3. Excluye tus carpetas de proyectos del antivirus en Windows.
4. Vigila el espacio en disco. Un df -h de vez en cuando.
5. git maintenance start en los repositorios de trabajo.
6. transfer.fsckObjects true para detectar la corrupción cuando entra.
7. Publica tus ramas. Una rama publicada está en dos máquinas. Es la mejor copia de seguridad y la más barata.
8. git bundle semanal de lo que solo tienes tú.
9. No mates procesos de Git con kill -9, especialmente durante gc o repack.
10. No edites ficheros de .git a mano (salvo config, que es texto por diseño). Usa git update-ref, git symbolic-ref, git config.
- Cuándo dejar de reparar y volver a clonar
La decisión más importante de la lección, y la que más tiempo ahorra.
Reclonar es la respuesta correcta cuando:
- El repositorio está completamente publicado (nada local sin enviar). Entonces reclonar no tiene ningún coste.
- Hay un packfile dañado. Extraer objetos de un pack roto rara vez compensa.
git fsckdevuelve más de un puñado de errores.- La corrupción reaparece tras repararla: hay una causa de fondo (disco, nube, antivirus) que no has resuelto.
- Llevas más de treinta minutos intentando repararlo. El coste de un
git clonees de minutos; el de una tarde de arqueología, no.
Merece la pena intentar la reparación cuando:
- El problema es el índice, un cerrojo,
HEADoconfig. Son minutos y no se pierde nada. - Es una referencia rota y el reflog o
packed-refsla resuelven. - Falta un objeto y sabes de dónde traerlo.
- Tienes trabajo local importante sin publicar y necesitas extraerlo antes de reclonar (apartado 6).
En forma de árbol:
flowchart TD
Q1{"¿Tengo trabajo local<br/>sin publicar?"}
Q1 -->|No| R1["RECLONAR.<br/>Es la respuesta correcta<br/>y tarda dos minutos"]
Q1 -->|Sí| Q2{"¿El daño es índice, cerrojo,<br/>HEAD o una referencia?"}
Q2 -->|Sí| R2["Reparar: apartado 4.<br/>Minutos, sin pérdida"]
Q2 -->|No: objetos o packfiles| Q3{"¿Puedo extraer lo local<br/>con git bundle?"}
Q3 -->|Sí| R3["Bundle + reclonar +<br/>reincorporar (apartado 6)"]
Q3 -->|No| R4["rsync del contenido sin .git,<br/>reclonar, y reaplicar como cambios"]
Y la frase que resume la lección:
Un repositorio Git dañado no es un problema de datos: es un problema de logística. Los datos casi siempre están en otro sitio. Tu trabajo consiste en identificar qué es exclusivamente tuyo, salvarlo, y traer el resto de donde esté sano.
Errores Comunes y Consejos
Error 1: asustarse con los dangling de git fsck. Son completamente normales en cualquier repositorio activo. Filtra con grep -v "^dangling" y mira si queda algo.
Error 2: dar por corrupto lo que es un disco lleno. df -h es el primer comando. Reparar con el disco al 100 % no puede funcionar.
Error 3: tener el repositorio en Dropbox, OneDrive o iCloud. Es la causa número uno de corrupción real, y no hace ninguna falta: Git ya sincroniza.
Error 4: git reset --hard para reparar un índice corrupto. rm .git/index && git reset reconstruye sin tocar tus ficheros; con --hard los perderías todos.
Error 5: editar ficheros de .git con un editor de texto. Salvo config, usa los comandos: git update-ref, git symbolic-ref, git config.
Error 6: reparar sin haber hecho una copia. cp -a cuesta diez segundos y evita que un error durante el rescate sea definitivo.
Error 7: pasar horas reparando un repositorio que está íntegramente publicado. Comprueba primero qué tienes que no tenga nadie más. Si la respuesta es "nada", reclona.
Error 8: usar cp -a .git como copia de seguridad "oficial". Vale para una emergencia, pero puede copiar un estado a medias. git bundle es coherente y verificable.
Error 9: borrar el repositorio roto antes de verificar el nuevo. Verifica con git fsck y comprueba que todo tu trabajo está ahí; luego borra.
Consejo 1: aprende el filtro de fsck. git fsck --full --no-progress 2>&1 | grep -vE "^(dangling|notice)". Si no devuelve nada, estás sano.
Consejo 2: git bundle create ... --all semanal. Un fichero, verificable, restaurable con git clone.
Consejo 3: transfer.fsckObjects true en la configuración global. Detecta la corrupción cuando entra, no meses después.
Consejo 4: publica tus ramas. Es la copia de seguridad más barata y la que más veces salva.
Consejo 5: el índice es un caché. Perderlo no tiene importancia; recordarlo evita mucho pánico innecesario.
Consejo 6: pon un límite de tiempo. Treinta minutos de reparación y, si sigue roto, reclona. El clon tarda dos.
Ejercicios
Ejercicio 1: leer git fsck sin asustarse
- Crea un repositorio con diez commits, una rama con tres commits propios y un
git addsin confirmar. - Provoca objetos colgantes: un
reset --hard HEAD~3, uncommit --amendy unbranch -D. - Ejecuta
git fsck --fully cuenta cuántas líneas devuelve. - Aplica el filtro del consejo 1 y comprueba que no queda nada. Explica por qué el repositorio está sano pese a las líneas anteriores.
- Identifica, entre los colgantes, cuál corresponde al
git addsin confirmar y recupéralo congit cat-file -p.
Ejercicio 2: romper y reparar
Sobre un repositorio de pruebas (nunca sobre uno real):
- Corrompe el índice:
printf 'basura' > .git/index. Ejecutagit statusy anota el error. Repáralo y explica por qué no se pierde nada. - Rompe una referencia:
echo "0000000000000000000000000000000000000000" > .git/refs/heads/GT-241. Ejecutagit fscky repárala con el reflog. - Rompe
HEAD:echo "ref: refs/heads/inexistente" > .git/HEAD. Diagnostica y repara congit symbolic-ref. - Vacía un objeto suelto: localiza uno con
find .git/objects -type fy trúncalo con: > <fichero>. Ejecutagit fsck --fully observa el error. - Repara el punto 4 desde un clon sano que habrás hecho antes de romper nada.
- Después de cada reparación, ejecuta
git fsck --fullfiltrado y confirma que está limpio.
Ejercicio 3: rescate completo con bundle
- Monta un remoto local con
git init --barey clónalo. - En el clon, publica dos commits en
mainy crea dos ramas locales sin publicar con tres commits cada una. Añade un stash y algún cambio sin confirmar. - Haz el inventario del apartado 5: qué ramas no tienen upstream, qué commits no están en el remoto.
- Crea un bundle con todo lo local y verifícalo.
- Borra el clon entero (simulando corrupción irreparable) y vuelve a clonar.
- Reincorpora las dos ramas desde el bundle y comprueba que los seis commits están.
- Explica qué se ha perdido y qué no, y cómo lo habrías evitado publicando las ramas.
Soluciones
Solución 1:
rm -rf /tmp/p9-05 && mkdir /tmp/p9-05 && cd /tmp/p9-05 && git init -q -b main
git config user.name "Ana Ferrer"; git config user.email "[email protected]"
for i in $(seq 1 10); do echo "linea $i" >> app.js; git add .; git commit -q -m "commit $i"; done
git switch -q -c GT-241
for i in 1 2 3; do echo "filtro $i" >> filtro.js; git add .; git commit -q -m "GT-241 parte $i"; done
echo "PREPARADO SIN CONFIRMAR" > estilos.css && git add estilos.css# 2. Los desastres
git reset -q --hard HEAD~3
git commit -q --amend -m "commit 10 (mensaje cambiado)" 2>/dev/null || true
git switch -q main
git branch -D GT-241# 3. La salida completa
git fsck --full --no-progress 2>&1 | wc -l
git fsck --full --no-progress 2>&1 | headChecking object directories: 100% (256/256), done. Checking objects: 100% (43/43), done. dangling commit 9c4e7b2e4a7f3c8b6d2e9a5f1c7b3d8e4a6f2c9b dangling blob 6f2b9d4a8c1e5f3b7d9a2c6e4f8b1d3a5c7e9f2b dangling commit 3e7f1a8b6d2e9a5f1c7b3d8e4a6f2c9b7d3a8f4a dangling tree 8a1f6c3d5e2b9c7f4a6d1e8b3c5f7a9d2e4b6c8a dangling commit 8f4c2a9b6d2e9a5f1c7b3d8e4a6f2c9b7d3a8f4a
Nueve líneas de aspecto preocupante.
Cero errores. El repositorio está perfectamente sano.
La razón: dangling significa "este objeto existe y es legible, pero ninguna referencia lo alcanza". Es exactamente el resultado esperado de un reset, un --amend y un branch -D: los commits siguen ahí (por eso son recuperables, lección 09-04) pero ya no cuelgan de ninguna rama. Es lo contrario de un problema: es la prueba de que la red de seguridad funciona.
Los errores de verdad empiezan por error:, missing o broken link, y aquí no hay ninguno.
# 5. El blob del add sin confirmar
for b in $(git fsck --lost-found --no-progress 2>/dev/null | awk '/dangling blob/ {print $3}'); do
echo "--- $b ---"; git cat-file -p "$b" | head -2
doneSolución 2:
rm -rf /tmp/p9-05b && mkdir /tmp/p9-05b && cd /tmp/p9-05b && git init -q -b main
git config user.name "Bruno Salas"; git config user.email "[email protected]"
for i in 1 2 3 4 5; do echo "l $i" >> app.js; git add .; git commit -q -m "c$i"; done
git switch -q -c GT-241
echo "filtro" > filtro.js && git add . && git commit -q -m "GT-241 filtro"
git switch -q main
# El clon sano, ANTES de romper nada (paso 5)
git clone -q /tmp/p9-05b /tmp/p9-05b-sanoNada perdido. La modificación seguía en el fichero del disco; el índice solo era la foto de qué iba a entrar en el próximo commit, y se reconstruye desde HEAD más el directorio de trabajo. Es un caché.
# 2. Referencia rota
git rev-parse GT-241 > /tmp/hash-bueno.txt
echo "0000000000000000000000000000000000000000" > .git/refs/heads/GT-241
git fsck --full --no-progress 2>&1 | grep -E "^(error|missing|broken)"git cat-file -t b52c9d1 # comprobar que el objeto existe
git update-ref refs/heads/GT-241 b52c9d1
git log --oneline GT-241 -2Reparada, y con su commit. El reflog conservaba el hash correcto porque el fichero de reflog es independiente del fichero de referencia.
Git no falla, pero cree estar en una rama que no existe: git log no muestra nada y un commit crearía una rama nueva.
ls .git/refs/heads/
git symbolic-ref HEAD refs/heads/main
git status -sb | head -1
git log --oneline -1# 4. Objeto suelto vaciado
git gc -q --prune=now 2>/dev/null # empaquetamos para dejar pocos sueltos
echo "nuevo contenido" > nuevo.txt && git add . && git commit -q -m "c6"
OBJ=$(find .git/objects -type f -path "*/??/*" | head -1)
echo "Objeto elegido: $OBJ"
cp "$OBJ" /tmp/objeto-original # por si acaso
: > "$OBJ"
ls -l "$OBJ"
git fsck --full --no-progress 2>&1 | grep -vE "^(dangling|Checking)"error: object file .git/objects/6f/2b9d4a8c1e5f3b7d9a2c6e4f8b1d3a5c7e9f2b is empty error: unable to mmap .git/objects/6f/2b9d4...: No such device fatal: loose object 6f2b9d4a8c1e5f3b7d9a2c6e4f8b1d3a5c7e9f2b is corrupt
Git se niega a operar: no puede leer un objeto que necesita.
# 5. Reparar desde el clon sano
SHA=$(basename $(dirname "$OBJ"))$(basename "$OBJ")
echo "Falta: $SHA"
rm "$OBJ"
# ¿Lo tiene el clon sano?
git -C /tmp/p9-05b-sano cat-file -t "$SHA"# Extraerlo y volver a escribirlo
git -C /tmp/p9-05b-sano cat-file -p "$SHA" > /tmp/contenido
NUEVO=$(git hash-object -w -t blob /tmp/contenido)
echo "Escrito: $NUEVO"
[ "$NUEVO" = "$SHA" ] && echo "COINCIDE: reparación exacta"El hash coincide, así que la reparación es demostrablemente exacta. No puede ser de otra manera: el nombre del objeto es el hash de su contenido (lección 01-04), de modo que si el hash sale igual, el contenido es idéntico byte a byte. Esta propiedad es la que hace que reparar un repositorio Git desde otro clon sea seguro y verificable.
# 6. Verificación final
git fsck --full --no-progress 2>&1 | grep -vE "^(dangling|notice|Checking)"
git log --oneline --all -3Solución 3:
rm -rf /tmp/p9-05c && mkdir /tmp/p9-05c && cd /tmp/p9-05c
git init -q --bare servidor.git
git clone -q servidor.git trabajo && cd trabajo
git config user.name "Carla Vidal"; git config user.email "[email protected]"
# 2. Lo publicado
echo "// gestor-tareas" > app.js && git add . && git commit -q -m "chore: inicio"
echo "// listado" >> app.js && git commit -q -am "feat: listado"
git push -q -u origin main
# Dos ramas locales SIN publicar
for r in GT-241 GT-247; do
git switch -q -c "$r" main
for i in 1 2 3; do echo "$r parte $i" >> "$r.js"; git add .; git commit -q -m "$r parte $i"; done
done
git switch -q main
# Un stash y cambios sin confirmar
echo "experimento" >> app.js && git stash push -q -m "experimento a medias"
echo "trabajo en curso" >> app.js
echo "borrador" > borrador.txt# 3. Inventario
echo "--- Ramas sin upstream ---"
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads | awk '$2==""{print " "$1}'
echo "--- Commits que no están en ningún remoto ---"
git log --oneline --branches --not --remotes
echo "--- Stashes ---"
git stash list
echo "--- Sin confirmar ---"
git status --short--- Ramas sin upstream ---
GT-241
GT-247
--- Commits que no están en ningún remoto ---
2f8c6e1 GT-247 parte 3
7a4d9b3 GT-247 parte 2
5c1e8f2 GT-247 parte 1
9c4e7b2 GT-241 parte 3
3e7f1a8 GT-241 parte 2
8a1f6c3 GT-241 parte 1
--- Stashes ---
stash@{0}: On main: experimento a medias
--- Sin confirmar ---
M app.js
?? borrador.txtSeis commits, dos ramas, un stash y dos cambios existen únicamente en esta máquina. Ese es exactamente el valor de la reparación.
# 4. El bundle
git bundle create /tmp/rescate.bundle --branches --not --remotes
git bundle verify /tmp/rescate.bundleThe bundle contains these 2 refs: 9c4e7b2... refs/heads/GT-241 2f8c6e1... refs/heads/GT-247 The bundle requires these 1 ref: b52c9d1... /tmp/rescate.bundle is okay
# El stash y lo sin confirmar, aparte
git stash show -p stash@{0} > /tmp/stash.patch
git diff > /tmp/sin-confirmar.patch
mkdir -p /tmp/ficheros-nuevos && cp borrador.txt /tmp/ficheros-nuevos/# 5. La catástrofe
cd /tmp/p9-05c && rm -rf trabajo
git clone -q servidor.git trabajo && cd trabajo
git log --oneline --allSolo lo publicado.
# 6. Reincorporar
git fetch -q /tmp/rescate.bundle 'refs/heads/*:refs/heads/*'
git branch
git log --oneline GT-241 -3
git log --oneline GT-247 -3Los seis commits y las dos ramas, con sus hashes originales.
git apply /tmp/sin-confirmar.patch
cp /tmp/ficheros-nuevos/borrador.txt .
git stash apply --index 2>/dev/null || git apply /tmp/stash.patch
git status --shortLo que se ha perdido:
- La pila de stashes como tal. El contenido se ha reaplicado desde el parche, pero la entrada
stash@{0}no existe. (Un bundle con--allhabría incluidorefs/stash.) - Todo el reflog, que es local y no viaja (lección 09-04). El clon nuevo tiene tres entradas.
- Las ramas de seguimiento antiguas y la configuración local del repositorio.
Lo que no se ha perdido: ni un solo commit, ni un solo cambio.
Cómo se habría evitado: publicando las ramas.
Con las dos ramas publicadas, el inventario del paso 3 habría salido vacío, y toda esta lección se habría reducido a rm -rf trabajo && git clone. Dos segundos de push frente a veinte minutos de rescate.
Conclusión
La corrupción de un repositorio Git asusta mucho más de lo que cuesta.
- La mayoría de los mensajes alarmantes no son corrupción: un cerrojo huérfano, un disco lleno, un problema de permisos o de propiedad. Descártalo primero con
df -hyls -ld .git. - Las causas reales vienen casi siempre de fuera de Git: un repositorio en una carpeta sincronizada con la nube (la número uno), un disco lleno, un apagón, un volumen de red, un antivirus. Los objetos de Git son inmutables y llevan su propia verificación; Git rara vez se rompe solo.
git fsckse lee filtrando el ruido. Los objetos dangling son completamente normales —son los restos de cadareset,rebasey--amend— y su presencia es la prueba de que la red de seguridad de la lección 09-04 funciona. Lo grave empieza porerror:,missingobroken link.- Las reparaciones, de menor a mayor: el índice es un caché derivado y se reconstruye con
rm .git/index && git resetsin perder nada; los cerrojos se borran tras comprobar procesos; una referencia rota se repara con el reflog,packed-refso el remoto;HEADcongit symbolic-ref; un objeto ilegible trayéndolo de otro clon, con la garantía de que si el hash coincide, la reparación es exacta. - El modelo distribuido es la red de seguridad. Cada clon del equipo es una copia casi completa. La pregunta correcta ante un repositorio dañado no es "¿cómo lo reparo?" sino "¿qué tengo yo que no tenga nadie más?", y se responde con
git for-each-refygit log --branches --not --remotes. - El rescate se hace con
git bundle: empaquetar lo local en un fichero, reclonar, y reincorporarlo congit fetch <bundle>. Y siempre con uncp -aprevio y una verificación posterior antes de borrar nada. - Prevención: nada de repositorios en la nube ni en volúmenes de red,
git maintenance start,transfer.fsckObjects true,git bundleperiódico y —lo que más rinde— publicar las ramas. - Y el criterio: si todo está publicado, reclona. Tarda dos minutos y es la respuesta correcta. Reserva la reparación para el índice, los cerrojos,
HEADy las referencias, o para extraer trabajo local antes de reclonar.
Con esto, el módulo ha cubierto los cuatro problemas que anunciaba el cierre del módulo 8: el reset --hard desafortunado, el enredo con el remoto, la rama borrada y el repositorio que se niega a funcionar.
Queda lo transversal. Porque muchas veces el problema no es que Git esté roto ni que hayas perdido algo, sino que Git está haciendo algo que no entiendes: un fichero que se ignora cuando no debería, una configuración que viene de un sitio que no sabías que existía, un push que falla por razones opacas, un cambio de comportamiento que nadie recuerda haber introducido. Para eso hay una caja de herramientas propia —trazas, fontanería, check-ignore, check-attr, ls-files— y, sobre todo, un método.
Continúa en la lección 09-06: Técnicas Avanzadas de Depuración.
Dominando Git: De Principiante a Avanzado
Módulo 1: Introducción a Git
- ¿Qué es Git?
- Instalando Git
- Terminología Básica de Git
- El Modelo de Datos de Git
- Configurando Git
- Configuración Inicial
Módulo 2: Operaciones Básicas de Git
- Creando un Repositorio
- Clonando un Repositorio
- Flujo de Trabajo Básico de Git
- Preparando y Confirmando Cambios
- Inspeccionando Cambios con git diff
- Visualizando el Historial de Confirmaciones
Módulo 3: Ramas y Fusión
- Entendiendo las Ramas
- Creando y Cambiando Ramas
- Fusionando Ramas
- Estrategias de Fusión
- Resolviendo Conflictos de Fusión
- Gestión de Ramas
Módulo 4: Trabajando con Repositorios Remotos
- Entendiendo los Repositorios Remotos
- Agregando un Repositorio Remoto
- Autenticación con Repositorios Remotos
- Obteniendo y Extrayendo Cambios
- Enviando Cambios
- Rastreando Ramas
Módulo 5: Operaciones Avanzadas de Git
- Rebase
- Rebase Interactivo
- Cherry-Picking de Confirmaciones
- Guardando Cambios Temporales
- Etiquetando Confirmaciones
- Revirtiendo Confirmaciones
Módulo 6: Herramientas y Técnicas de Git
- Usando Git Hooks
- Git Bisect
- Git Blame
- Git Log y Alias
- Submódulos de Git
- Múltiples Copias de Trabajo con git worktree
Módulo 7: Estrategias de Colaboración y Flujo de Trabajo
- Forks y Pull Requests
- Revisiones de Código con Git
- Flujo de Trabajo Git Flow
- GitHub Flow
- Trunk Based Development
- Integración Continua con Git
Módulo 8: Mejores Prácticas y Consejos de Git
- Escribiendo Buenos Mensajes de Confirmación
- Manteniendo un Historial Limpio
- Ignorando Archivos con .gitignore
- Atributos de Fichero con .gitattributes
- Mejores Prácticas de Seguridad
- Consejos de Rendimiento
Módulo 9: Solución de Problemas y Depuración
- Problemas Comunes de Git
- Deshaciendo Cambios
- Resolviendo Divergencias con el Remoto
- Recuperando Confirmaciones Perdidas
- Tratando con Repositorios Corruptos
- Técnicas Avanzadas de Depuración
