CLASE 05
Git Internals
Mantenimiento y Recuperacion de DatosDe vez en cuando, Git ejecuta automaticamente el comando git gc --auto. La mayor parte del tiempo este comando no hace nada, ya que necesitas tener alrededor de 7.000 objetos sueltos o mas de 50 archivos empaquetadores para que Git arranque una limpieza real.
Puedes lanzarlo manualmente cuando quieras:
git gc --auto
Entre otras cosas, gc agrupa todos los objetos sueltos en empaquetadores, consolida los empaquetadores pequeños en uno grande,
elimina objetos no alcanzables por ningun commit, y actualiza alternativas como git stash.
gc tambien empaqueta tus referencias en un unico archivo eficiente:
find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
Despues de ejecutar git gc, esos archivos desaparecen de refs/ y se consolidan en .git/packed-refs:
cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a346d349e0d0e4196f5f3b1955 refs/heads/experiment
ab1afef80fac8e34258959aa4e8e7b6e655e9e8b refs/heads/master
9585191f37f7b0fb9444511119c5069a8c2e6f28 refs/tags/v1.0
^1a410efbd13591db07496d4f82dfc14aad14979
Las lineas que comienzan con ^ indican que la etiqueta superior es anotada,
y esa linea es el commit al que apunta directamente.
En algun momento de tu trabajo con Git puede que pierdas accidentalmente un commit.
Generalmente esto ocurre porque fuerzas el borrado de una rama con trabajo en ella,
o porque haces un reset --hard moviendo a un commit anterior.
Supongamos que tienes este historial y haces reset a un commit anterior:
git log --pretty=oneline
ab1afef80fac8e34258959aa4e8e7b6e655e9e8b modified repo a bit
484a59275031909876a47e24d18424ca6e0c4bf5 added repo.rb
1a410efbd13591db07496d4f82dfc14aad14979 third commit
cac0cab538b970a346d349e0d0e4196f5f3b1955 second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
git reset --hard 1a410efbd13591db07496d4f82dfc14aad14979
Ahora has perdido los dos commits superiores. Hay dos formas de recuperarlos.
Mientras trabajas, Git registra silenciosamente el valor de HEAD cada vez que cambia en el reflog.
Puedes consultarlo con:
git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: modified repo a bit
484a592 HEAD@{2}: commit: added repo.rb
Puedes ver que perdiste los commits ab1afef y 484a592. Para recuperarlos, crea una nueva rama apuntando a ese commit:
git branch recover-branch ab1afef # recover-branch no es comando, es el nombre de la rama
git log --pretty=oneline recover-branch
ab1afef80fac8e34258959aa4e8e7b6e655e9e8b modified repo a bit
484a59275031909876a47e24d18424ca6e0c4bf5 added repo.rb
1a410efbd13591db07496d4f82dfc14aad14979 third commit
...
git fsckSi el reflog no tiene la informacion que necesitas (por ejemplo porque el gc ya lo limpio), puedes usar git fsck, que comprueba la integridad de tu base de datos y lista todos los objetos a los que no se puede llegar:
git fsck --full
Checking object directories: 100%
Checking connectivity: done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 # Blob perdido
dangling commit ab1afef80fac8e34258959aa4e8e7b6e655e9e8b # <- Commit perdido
dangling tree aea790b9a58f6cf6f2804eeac9359346671de7f0 # Tree perdido
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293 # Blob perdido
El dangling commit es el commit que perdiste. Puedes recuperarla de la misma forma: creando una rama apuntando a ese checksum SHA-1.
tar -xzf 06-recuperacion-commits.tar.gzcd 06-recuperacion-commits/code .) y lee el README.mdUno de los problemas mas comunes que puede ocurrir es que alguien añada por error un archivo muy grande al repositorio. Incluso si lo borras en el siguiente commit, seguira presente en el historial y Git tendra que clonarlo siempre.
Para encontrar el culpable, puedes inspeccionar el empaquetador y buscar el objeto mas pesado con verify-pack:
git verify-pack -v .git/objects/pack/pack-*.idx \ # Verifica el paquete
| sort -k 3 -n \ # Ordena por la 3ra columna, la de tamaño en Bytes
| tail -3 # Mostrar los ultimos 3 resultados
#
dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 22044 5792 4977696
82c99a3e86bb1267b236a4b6eff7868d97489af1 blob 4975916 4976258 1438 # Blob de 4GB!
Luego averigua a que archivo corresponde ese checksum SHA-1 con rev-list:
git rev-list --objects --all | grep 82c99a3 # Listar todos los objetos, luego buscar por 82c99a3
82c99a3e86bb1267b236a90d7b697a8d07cc8b6d git.tgz
Para eliminar ese archivo de todo el historial, primero identifica en que commits aparecio:
git log --oneline --branches -- git.tgz # Lista los commits donde aparece git.tgz
dadf7258 oops - removed large tarball
7b30847d add git tarball
Luego reescribe todos los commits desde ese en adelante para que no contengan ese archivo con filter-branch:
git filter-branch --index-filter \
'git rm --ignore-unmatch --cached git.tgz' -- 7b30847d^..
Este comando revisa los commits desde el 7b30847d en adelante ^, revisa el area de preparacion --index-filter,
y ejecuta la orden de eliminacion git rm --cached git.tgz para quitar el archivo git.tgz.
El comando
filter-branchlo veremos mas adelante en Análisis y Reescritura.
Finalmente, limpia las referencias antiguas, el reflog y ejecuta gc para eliminar de verdad los objetos:
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc
Para verificar que el archivo grande ya no esta usamos count-objects:
git count-objects -v
count: 8
size: 2040
in-pack: 19
packs: 1
size-pack: 3
prune-packable: 0
garbage: 0
size-garbage: 0
El tamaño del empaquetador (
size-pack) es ahora de 3KB en lugar de los 3MB anteriores. El archivo grande ha desaparecido del historial.
Variables de Entorno
Referencia rapidaGit siempre se ejecuta dentro de un shell y utiliza variables de entorno para determinar como comportarse. Aqui las mas utiles para el dia a dia:
| Variable | Descripcion |
|---|---|
GIT_DIR | Cambia la ubicacion de la carpeta .git/ |
GIT_WORK_TREE | Cambia el directorio de trabajo del repositorio |
GIT_AUTHOR_NAME | Sobreescribe el nombre del autor del commit |
GIT_AUTHOR_EMAIL | Sobreescribe el correo del autor del commit |
GIT_COMMITTER_NAME | Sobreescribe el nombre de quien confirma |
GIT_COMMITTER_EMAIL | Sobreescribe el correo de quien confirma |
GIT_TRACE | Activa logging detallado para depuracion |
GIT_SSH | Binario alternativo a usar cuando Git necesita conectarse via SSH |
La referencia completa esta en el Cap. 10.8 de Pro Git.
Entrar al kahoot y esperar el codigo de la sala, o presionar la opcion “Aprende” para responder de forma individual.