Modo colocado: dos almacenes, un directorio

Parte 2 de 9.

La instalación en sí no tiene nada de particular: un gestor de paquetes o un cargo install, luego una configuración de user.name/user.email, con la misma forma que la configuración de primera ejecución de Git. La parte interesante empieza en jj git init --colocate.

Ejecuta eso dentro de un checkout de Git existente y deja un directorio .jj junto a .git, añade .jj/ a .git/info/exclude para que nunca aparezca como sin seguir, e importa las ramas actuales y HEAD como commits de jj. Nada en .git se reescribe. Si borrara .jj ahora mismo, el repositorio sería exactamente el repo Git puro que era antes, sin perder nada.

Esa reversibilidad es lo que hizo que probar esto se sintiera de bajo riesgo. No es una migración con un punto de no retorno; se parece más a instalar un segundo lector encima de un almacenamiento que ya existe. git log sigue funcionando. git status sigue funcionando. Cualquier hook de pre-commit, cualquier runner de CI, el IDE de cualquier compañero sigue funcionando sin modificación.

Lo que enseguida pareció raro fue el primer jj status:

The working copy has no changes.
Working copy  (@) : qpvuntsm 230dd059 (empty) (no description set)
Parent commit (@-): mzvwutvl a1b2c3d4 main | Initial commit

Ya hay un commit en checkout, y está vacío. Viniendo de Git, un “commit vacío sin mensaje” en la punta parece un estado de error. No lo es: es la propia copia de trabajo, siempre representada como un commit real. Esa única idea basta para reorganizar cómo se lee el resto de la herramienta, y es el tema entero del siguiente artículo.