Cómo migrar un repo SVN a GIT, con historia

Hace algunos meses emprendí la titánica tarea de  aprender a migrar los repositorios de mi trabajo de SVN (localmente alojados) a Git (alojados en Github) conservando la historia de todos los commits históricos para saber a quién culpar de cada bug que se descubra en el futuro.

Tuve que dar muchas vueltas, hacer muchos ensayos, deconstruir y reconstruir muchas guías que sólo abordan una parte del problema, contrastarlas con otras que listan los pases mágicos sin detallar lo que hace cada uno, y entender el trasfondo conceptual del cambio de esquema que ocurre tras bambalinas. De esos meses ensayando en mis ratos libres adquirí valiosa experiencia, una cicatriz bajo el codo derecho y una acidez crónica por tanto café. Bueno, en realidad lo de la cicatriz me lo inventé porque ya la tenía.

La primera pregunta es ¿Para qué migrar la historia de un repo SVN a GIT? Si sólo necesitas el código fuente y la historia te da igual, puede que sea preferible seguir el camino más corto: Copiar un working copy local a un repositorio en Git es trivial. Casi les diría que es cosa de borrar la carpeta .svn e inicializar git dentro de la working copy. Pero eso, querido lector, no migrará la historia y puede hacerse una sola vez. Si el repo SVN recibe a futuro otros 20 commits y en tu local repites el proceso, lo que tienes en tu Git es un solo commit inicial y un segundo commit de tu autoría con los 20 cambios firmados por ti: no es lo que queremos. Queremos que cada commit, y sus respectivos mensajes, se pasen de un sistema al otro.

Para repetir los pasos siguientes necesitarás instalar Git y Git-svn. En Linux ambos paquetes se instalan con yum (fedora, RHEL, etc) o apt-get (Debian, Ubuntu). En Windows necesitas instalar msysGit. No es la única manera pero es la mejor, y te deja una consola muy bien lograda.

En nuestro ejemplo vamos a tomarnos de un caso práctico. Quería usar el Google Client PHP API para un proyecto, pero no me gustaba el hecho de que éste viniera versionado en SVN. Quería tenerlo en mis repositorios de Git y añadirle algunos cambios (por ejemplo para usar con Composer, pero esa es otra historia). Para esto procedí como sigue:

1.- Me hice un repositorio en GitHub que bauticé, muy originalmente, google-php-api. Lo generé con un Readme muy básico y un .gitignore genérico.

2.- Cloné localmente el repositorio:

No es muy impresionante… apenas tiene lo básico.

3.- Ahora dentro de esa carpeta recién creada vamos a usar Git SVN para enlazar con el repo de Google API PHP Client.

Disectando lo que dice ahí: git svn clone equivale a hacer un svn checkout. El resto de los parámetros le dicen que la rama principal se llama trunk (esto es asi por defecto) y la ruta ./ le dice que use la carpeta actual como inicio, porque en caso contrario creará una subcarpeta llamada svn y no nos sirve esa estructura.

Al ejecutar el git svn clone verás pasar uno a uno los commits hechos en svn. Se están convirtiendo en commits de git pero no en tu working copy sino en la carpeta de referencias, en este caso .git/svn/refs. Si el repo que estás clonando tiene una historia muy larga esto puede demorar fácil una hora.

4.- Estamos parados sobre un repositorio en cuya working copy no hay nada salvo el README.md que creamos en GitHub, pero en sus referencias hay dos remotos:
origin, el repo de GitHub, creado hace unos minutos
trunk, el repo svn de Google API PHP Client, con toda la historia

 

5.- Vamos a hacer que nuestro master herede toda la historia de svn:

Verás que se crean todos los archivos correspondientes en tu working copy y ocurre implícitamente un nuevo commit cuyo mensaje es “Merge remote-tracking branch ‘remotes/trunk’“.

6.- Subimos todo a GitHub

Si miras ahora en GitHub, el repo tiene toda la historia:

 

Tengo una guía algo más compleja que describe estos mismos pasos para el caso en que quieras importar desde un repo SVN con varios tags, cada uno de los cuales se importará a un branch de tu nuevo repositorio Git.

Leave a Reply