Lihuen
RSSRSS AtomAtom

Diferencia entre revisiones de «Migración de SVN a Git»

(Migración de repositorios con esquemas (a) y (b))
(Links)
Línea 185: Línea 185:
 
cd $ORIGINAL
 
cd $ORIGINAL
 
</source>
 
</source>
 +
==Si git-svn dice que creó directorios vacíos...==
 +
Git no añade directorios vacíos, así que si git-svn los importó debemos crear un archivo en ellos para que git los pueda versionar. Se recomienda crear un archivo vacío con nombre .gitignore.
 +
 +
Por ejemplo cuando "git svn clone" devuelve:
 +
<nowiki>
 +
Checked out HEAD:
 +
  https://versionador.linti.unlp.edu.ar/svn/lihuen/lihuenconfig/trunk r2888
 +
creating empty directory: lihuenconfig/defaultconfig/lxde-edubook/etc/skel/Desktop
 +
creating empty directory: lihuenconfig/defaultconfig/lxde/etc/skel/Desktop
 +
</nowiki>
 +
 +
Deberíamos marcar esos archivos para que git los pueda versionar:
 +
<source lang="bash">
 +
find -not -path "*/.git*" -type d | while read dir; do
 +
    [ -z "$(ls "$dir")" ] && touch "$dir/.gitignore" && git add "$dir"
 +
done
 +
</source>
 +
 +
 +
https://git.wiki.kernel.org/index.php/SvnMigration#Empty_directories
 +
 +
==Borrando archivos grandes de la historia==
 +
http://stackoverflow.com/questions/2100907/how-do-i-purge-a-huge-file-from-commits-in-git-history
 
==Links==
 
==Links==
 
* Migración de repositorios SVN a GIT: http://viget.com/extend/effectively-using-git-with-subversion
 
* Migración de repositorios SVN a GIT: http://viget.com/extend/effectively-using-git-with-subversion

Revisión de 03:02 4 oct 2013

Existe un paquete, git-svn, que agrega al comando Git, la capacidad de trabajar con repositorios remotos SVN, dependiendo de la estructura que tenga el repositorio SVN a migrar, se puede usar este comando directamente o desde un script que simplifique la tarea.

Estructuras de directorios en SVN

Los repositorios SVN se estructuran en directorios y hay distintos esquemas para estructurarlos, el libro "Control de versiones con Subversion" recomienda 2 posibles esquemas [1].

Estos esquemas reservan un directorio para:

  • trunk -> versión principal de desarrollo.
  • branches -> versiones que divergen de trunk (por ejemplo en un branch dado se agrega una funcionalidad experimental).
  • tags -> versiones con nombre del proyecto (por ejemplo 0.9beta, 0.9, 1.0, etc...).

Los esquemas (a) y (b) son los recomendados por el libro: a. Para repositorios que contienen un único proyecto:

/
   trunk/
   branches/
   tags/

b. Para repositorios con múltiples proyectos:

/
   paint/
      trunk/
      branches/
      tags/
   calc/
      trunk/
      branches/
      tags/

Pero como no hay ninguna restricción técnica para hacerlo de otra forma, uno podría organizar su repositorio como quisiera. Por ejemplo poniendo todos los archivos del proyectos sueltos:

c. Forma desprolija con los archivos sueltos:

/
  main.c
  Makefile
  funcs.c
  funcs.h

Sin embargo en este ultimo formato es imposible tener branches y tags.

Branches y Tags en Git

Git conceptualmente es similar, existen branches (ramificaciones) donde se almacenarán modificaciones que hagan que el proyecto diverja respecto de la versión de referencia. Y tags que marcan versiones con nombre del proyecto. Sin embargo la implementación es muy distinta.

En Git el código no está organizado en directorios como en los esquemas (a) y (b) de SVN antes mencionados, sino que para el usuario se ven como (c). Para acceder a un branch determinado o a un tag se usa checkout:

git checkout nombre_tag_o_branch

Checkout altera, crea y borra los archivos que sea necesario para que el usuario vea el branch o tag (o commit) seleccionado. Para saber en que branch se está actualmente se puede usar el comando:

git status

Por convención el branch master es la línea principal de desarrollo (como el trunk en SVN).

Migración de repositorios con el esquema (c)

Si bien el esquema (c) es el más desprolijo y no es para nada recomendable, es el más fácil de migrar a git:

git svn clone https://svn.servidor.com/svn/lihuen/script-utils

Podemos inspeccionar la historia del proyecto y ver que todo está en orden con:

git log

Luego agregamos el servidor remoto Git donde queremos subir el proyecto con toda su historia:

git remote add origin git@git.servidor.com:usuario/script-utils.git

Y finalmente hacemos un push del branch master (guardándolo de ahora en más como branch por defecto para los push y pull):

git push -u origin master

Migración de repositorios con esquemas (a) y (b)

En estos esquemas podemos aprovechar la división de tags y branches y exportar los mismos a Git. Hacer esto manualmente demanda bastante trabajo, así que podemos automatizar todo con un script:

#!/bin/sh
set -e
git(){
    (tput bold; tput setf 2; echo git "$@";	tput sgr0) 1>&2
	$(which git) "$@"
}
 
ask(){
	tput bold; tput setf 4
	read -p "$1 [S/n]: " answer
	tput sgr0
	case "$answer" in
	N|n)
		return 1
		;;
	S|s|"")
		return 0
		;;
	*)
		echo "Respuesta no válida"
		ask "$1"
		return $?
	esac
	return 0
}
 
 
fetch(){
	# http://stackoverflow.com/questions/2244252/importing-svn-branches-and-tags-on-git-svn
	# supply proper trunk, braches and tags folder names and fetch svn repo:
	git svn init -t tags -b branches -T trunk "https://svn.servidor.com/svn/lihuen/$1"
	git svn fetch
 
	# Since tags in svn are real braches, create git tags from tag branches:
	git for-each-ref '--format=%(refname:short) %(objectname)' refs/remotes/tags |  cut -d / -f 2- |
	while read ref
	do
	  [ "$ref" = "remotes/tags" ] && continue # Descarto esta ref
	  git tag -a svn_$ref -m 'import tag from svn'
	done
 
	# Delete tag branches
 
	git for-each-ref '--format=%(refname:short)' refs/remotes/tags | cut -d / -f 2- |
	while read ref
	do 
	  [ "$ref" = "remotes/tags" ] && continue # Descarto esta ref
	  git branch -rd tags/$ref
	done
	# Since tags marked in the previous step point to a commit "create tag", we need to derive "real" tags, i.e. parents of "create tag" commits.
 
	git for-each-ref '--format=%(refname:short)' refs/tags |
	while read ref
	do
	  tag=`echo $ref | sed -r 's/^svn_//g'` # give tags a new name
	  echo $ref -\> $tag
	  git tag -a $tag `git rev-list -2 $ref | tail -1` -m "proper svn tag"
	  git tag -d svn_$tag # Elimino el tag temporal
	done
 
	# Convierto los branches remotos en branches locales
	git for-each-ref refs/remotes | grep -v '@' |grep -v 'remotes/trunk$' | cut -d/ -f3- |
	while read ref; do
		git branch "$ref" "remotes/$ref"
	done
}
 
push(){
 
	echo -- Tags
	git tag -l
	echo -- Branches
	git branch -v
 
	ask "Si la información anterior es correcta ingresá S para seguir" || exit 0
 
	while true; do
		read -p "Ingresá el namespace del proyecto (por ej. tu nombre de usuario): " usuario
		ask "¿El namespace a usar es {$usuario}?" || continue
		break
	done
	echo "Crea en gitlab (desde la web) un repositorio con el nombre $usuario/$1, después presioná [Enter] para seguir"
	read junk
 
	git remote add origin "git@git.servidor.com:$usuario/$1.git"
	git push origin --mirror
}
 
 
if [ $# -ne 1 ]; then
	echo "Falta el nombre del repo svn"
	echo "Por ejemplo: $0 lihuenconfig"
	exit 1
fi
if [ -n "$(echo $1 | grep -E '/$')" ]; then
	echo "El nombre del repositorio no puede terminar en /"
	exit 2
fi
 
ORIGINAL="$PWD"
FETCH=1
if [ -d "$1" ]; then
	ask "El directorio $1 ya existe ¿subo lo que está ahí a gitlab?" || exit 1
	FETCH=0
fi
 
 
 
if [ $FETCH -eq 1 ]; then
	mkdir "$1"
	cd "$1"
	fetch "$1" # Descarga el repo svn usando git-svn y acomoda los tags y branches
	ask "Importado a repo GIT ¿Querés seguir en el asistente para subirlo al gitlab?" || exit 0
fi
[ $FETCH -eq 0 ] && cd "$1"
push "$1" # Agrega un repo git como remote y sube todo al mismo (con --mirror)
 
cd $ORIGINAL

Si git-svn dice que creó directorios vacíos...

Git no añade directorios vacíos, así que si git-svn los importó debemos crear un archivo en ellos para que git los pueda versionar. Se recomienda crear un archivo vacío con nombre .gitignore.

Por ejemplo cuando "git svn clone" devuelve:

Checked out HEAD:
  https://versionador.linti.unlp.edu.ar/svn/lihuen/lihuenconfig/trunk r2888
creating empty directory: lihuenconfig/defaultconfig/lxde-edubook/etc/skel/Desktop
creating empty directory: lihuenconfig/defaultconfig/lxde/etc/skel/Desktop

Deberíamos marcar esos archivos para que git los pueda versionar:

find -not -path "*/.git*" -type d | while read dir; do
    [ -z "$(ls "$dir")" ] && touch "$dir/.gitignore" && git add "$dir"
done


https://git.wiki.kernel.org/index.php/SvnMigration#Empty_directories

Borrando archivos grandes de la historia

http://stackoverflow.com/questions/2100907/how-do-i-purge-a-huge-file-from-commits-in-git-history

Links