{"id":970,"date":"2012-03-20T11:18:52","date_gmt":"2012-03-20T09:18:52","guid":{"rendered":"http:\/\/guimi.net\/blogs\/hiparco\/?page_id=970"},"modified":"2012-03-20T11:19:02","modified_gmt":"2012-03-20T09:19:02","slug":"guia-rapida-de-subversion-svn","status":"publish","type":"page","link":"http:\/\/guimi.net\/blogs\/hiparco\/tutoriales\/guia-rapida-de-subversion-svn\/","title":{"rendered":"Gu\u00eda r\u00e1pida de subversi\u00f3n (svn)"},"content":{"rendered":"<p>Esta entrada no pretende ser una gu\u00eda completa de subversion, solo una gu\u00eda r\u00e1pida para comenzar a trabajar con esta potente herramienta.<\/p>\n<h2>Introducci\u00f3n<\/h2>\n<p>Muchos proyectos est\u00e1n migrando de Svn a Git ya que Git les aporta una serie de ventajas, principalmente que Git es distribuido (SVN es centralizado). Git parece ser claramente mejor para proyectos grandes y, sobre todo, con mucha gente.<br \/>\nLa alternativa a svn+trac ser\u00eda git+gitorious. Aunque Git parece ser mejor que Svn en algunos aspectos, trac sigue siendo mejor que gitorious.<br \/>\nAqu\u00ed tenemos una <a href=\"http:\/\/git.or.cz\/course\/svn.html\">gu\u00eda de Git para usuarios de svn<\/a>.<\/p>\n<h2>Antes de empezar<\/h2>\n<p>Para organizar los proyectos se suele asumir por convenio crear tres directorios por proyecto:<\/p>\n<ul>\n<li><strong>Trunk<\/strong>: Directorio de un repositorio bajo el cual se encuentran los directorios y ficheros de nuestro proyecto.\n<li><strong>Tag<\/strong>: Directorio bajo el cual se almacenan las diferentes versiones o releases de nuestro software.\n<li><strong>Branches<\/strong>: Directorio donde se almacenan ramas de nuestro proyecto (por ejemplo, para pruebas de concepto).<\/ul>\n<p>Las reglas de oro del trabajo con sistemas de versiones, son dos:<\/p>\n<ul>\n<li><strong>Nunca har\u00e1s un commit de c\u00f3digo que no compile<\/strong> o tenga errores: Si lo haces, cuando otro programador haga un update su c\u00f3digo tambi\u00e9n tendr\u00e1 esos errores y por tanto no compilar\u00e1.\n<li><strong>Siempre har\u00e1s un update antes de empezar a trabajar<\/strong> sobre el c\u00f3digo. De esta manera, te aseguras de estar trabajando siempre sobre la \u00faltima versi\u00f3n del c\u00f3digo.<\/ul>\n<p>Dicho esto queda recordar que subversion usa por defecto el puerto 3690.<\/p>\n<p>Los comandos principales (hay m\u00e1s) de svn son:<\/p>\n<ul>\n<li><strong>Status<\/strong>: Nos indica la situaci\u00f3n de nuestra copia local respecto al proyecto en el repositorio.\n<li><strong>Import<\/strong>: Comando utilizado para subir al repositorio la estructura inicial de nuestro proyecto.\n<li><strong>Checkout<\/strong> (co): Comando para descargar en un PC un proyecto desde un repositorio.\n<li><strong>Update<\/strong> (up): Comando que nos permite actualizar nuestro proyecto en local desde el repositorio central.\n<li><strong>Add<\/strong>: Comando utilizado para a\u00f1adir un fichero a nuestro proyecto. No es subido al repositorio hasta que se indique con el comando &#8220;commit&#8221;. El comando add solo deja &#8220;marcado&#8221; ese fichero o directorio como parte del repositorio.\n<li><strong>Delete<\/strong>: Comando que permita marcar un fichero o directorio para ser eliminado del respositorio.\n<li><strong>Commit<\/strong> (ci): Comando que nos permite subir al repositorio todos los cambios hechos sobre un proyecto en local.\n<li><strong>Log<\/strong>: Consulta el trabajo realizado con un repositorio<\/ul>\n<p>&nbsp;<\/p>\n<h1>SERVIDOR SUBVERSION<\/h1>\n<p>Primero debemos instalar subversion:<br \/>\n<font class=\"comando\"># aptitude install subversion<\/font><\/p>\n<h2>Crear un repositorio<\/h2>\n<p>Generamos un directorio para el repositorio (gestionado por svn, el servidor)<br \/>\n<font class=\"comando\">$ mkdir repositorio<br \/>\n$ cd repositorio<\/font><br \/>\nCreamos un proyecto, para estos ejemplos usaremos un proyecto llamado &#8220;ANA&#8221;<br \/>\n<font class=\"comando\">$ svnadmin create ANA<\/font><\/p>\n<p>Configuramos el acceso. Una configuraci\u00f3n habitual es lectura a todo el mundo y escritura a los autorizados.<br \/>\n<font class=\"comando\">$ vi ANA\/conf\/svnserve.conf<\/font><\/p>\n<pre class=\"codigo\">\r\n[general]\r\nanon-access = read\r\nauth-access = write\r\nrealm = My First Repository\r\npassword-db = passwd\r\n<\/pre>\n<p>Generamos los usuarios con permiso de escritura. Las claves van en texto claro, por tanto deber\u00edamos cuidar los permisos de este fichero.<br \/>\n<font class=\"comando\">$ vi ANA\/conf\/passwd<\/font><\/p>\n<pre class=\"codigo\">\r\n[users]\r\nharry = harryssecret\r\nsally = sallyssecret\r\n<\/pre>\n<p>Lanzamos el servidor<br \/>\n<font class=\"comando\">$ svnserve -d -r \/path_de_repositorio\/<\/font><br \/>\nEl par\u00e1metro &#8216;-d&#8217; hace que el servidor se ponga en modo &#8220;demonio&#8221;.<br \/>\nEl par\u00e1metro &#8216;-r&#8217; indica la ruta al repositorio. Si no usamos el par\u00e1metro -r, los clientes deben indicar siempre la ruta completa de la carpeta, con los problemas que conlleva de comodidad (ruta muy larga), seguridad (publicidad de la estructura de directorios) y administraci\u00f3n (cambios en el sistema de archivos).<br \/>\n&nbsp;<\/p>\n<h1>CLIENTE SVN<\/h1>\n<p>Para trabajar con un servidor mediante ssh:<br \/>\n<a href=\"http:\/\/guimi.net\/blogs\/hiparco\/svnssh-conectar-con-un-servidor-svn-mediante-ssh\/\">SVN+SSH: Conectar con un servidor svn mediante ssh<\/a><\/p>\n<h2>Puesta en marcha<\/h2>\n<h3>Importar un repositorio<\/h3>\n<p>Si trabajamos con un servidor preinstalado podemos, como clientes, crear proyectos a partir de unas fuentes pre-existentes mediante &#8220;import&#8221;:<br \/>\n<font class=\"comando\">$ svn import nuevoProyecto http:\/\/urlDelRepositorio\/ -m &#8220;Importacion inicial&#8221;<\/font><br \/>\nEsto requiere de una configuraci\u00f3n un poco m\u00e1s compleja en el servidor.<\/p>\n<h3>Creando un nuevo proyecto a partir de fuentes anteriores<\/h3>\n<p>En el equipo en que vamos a programar (puede ser el mismo que el servidor) generamos un directorio para la copia local -copia de trabajo- (las fuentes con que trabajamos)<br \/>\n<font class=\"comando\">$ mkdir copia_local<br \/>\n$ cd copia_local<\/font><\/p>\n<p>Tomamos las fuentes del proyecto (CheckOut &#8211; co)<br \/>\n<font class=\"comando\">$ svn co svn:\/\/localhost\/ANA<\/font><\/p>\n<pre class=\"codigo\">En la revisi\u00f3n 0.<\/pre>\n<p>Copiamos en el nuevo directorio los ficheros fuente del proyecto (si exist\u00edan).<br \/>\n<font class=\"comando\">$ cd ANA<br \/>\n$ cp -R \/ruta_fuentes_anteriores\/* .<\/font><br \/>\nA\u00f1adimos los ficheros al proyecto<br \/>\n<font class=\"comando\">$ svn add *<\/font><\/p>\n<p>Actualizamos la informaci\u00f3n local sobre los ficheros. Nos indica todos los ficheros que est\u00e1n marcados para ser a\u00f1adidos al repositorio.<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">A   fichero1\r\nA   fichero2\r\n...\r\nEn la revisi\u00f3n 0.<\/pre>\n<p>Hacemos commit (ci) de las modificaciones y dejamos una nota o mensaje (-m)<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Importacion inicial&#8221;<\/font><\/p>\n<h2>Uso y disfrute<\/h2>\n<p><strong>Lo primero<\/strong> que se debe hacer al empezar a programar es actualizar las fuentes (ver reglas de oro), para asegurarnos que disponemos de la \u00faltima versi\u00f3n:<br \/>\n<font class=\"comando\">$ cd \/ruta_copia_local\/ANA<br \/>\n$ svn update<\/font><\/p>\n<p><strong>Al acabar<\/strong> (si el programa no compila no has acabado -ver reglas de oro-):<br \/>\n&#8211; Comprobamos los cambios que tenemos pendientes con:<br \/>\n<font class=\"comando\">$ svn status<\/font><br \/>\n&#8211; Hacemos los ajustes necesarios (svn add, svn delete&#8230; ver m\u00e1s adelante).<br \/>\n&#8211; Guardamos los cambios con un comentario indicando los cambios realizados.<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Cambios blablablabla&#8221;<\/font><\/p>\n<p>Veamos algunas de las funciones m\u00e1s habituales.<\/p>\n<h3>A\u00f1adir ficheros<\/h3>\n<p>Ya hemos visto en la importaci\u00f3n como a\u00f1adir ficheros, pero lo vamos a volver a ver con un poco m\u00e1s de detalle.<br \/>\nGeneramos un nuevo fichero:<br \/>\n<font class=\"comando\">$ touch kk<\/font><br \/>\nConsultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">?       kk<\/pre>\n<p>La \u00fanica diferencia con el repositorio es que hay un fichero kk que no conoce<\/p>\n<p>A\u00f1adimos el fichero kk al proyecto<br \/>\n<font class=\"comando\">$ svn add kk<\/font><\/p>\n<pre class=\"codigo\">A         kk<\/pre>\n<p>Consultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">A       kk<\/pre>\n<p>La \u00fanica diferencia con el repositorio es que hay un fichero kk por a\u00f1adir<\/p>\n<p>Hacemos commit (ci) del fichero y dejamos una nota o mensaje (-m)<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Prueba add kk&#8221;<\/font><\/p>\n<pre class=\"codigo\">A\u00f1adiendo      kk\r\nTransmitiendo contenido de archivos .\r\nCommit de la revisi\u00f3n 1.<\/pre>\n<h3>Modificar ficheros<\/h3>\n<p>Modificamos el fichero de prueba<br \/>\n<font class=\"comando\">$ vi kk<\/font><br \/>\nConsultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">M       kk<\/pre>\n<p>La \u00fanica diferencia con el repositorio es que hay un fichero kk por modificar<\/p>\n<p>Podemos ver las diferencias entre el fichero local y el del repositorio<br \/>\n<font class=\"comando\">$ svn diff kk<\/font><\/p>\n<pre class=\"codigo\">Index: kk\r\n===================================================================\r\n--- kk (revisi\u00f3n: 1)\r\n+++ kk (copia de trabajo)\r\n@@ -1,2 +1,3 @@\r\n #Llalala\r\n+#lilililili\r\n #lelele\r\n<\/pre>\n<p>Hacemos commit (ci) del fichero y dejamos una nota o mensaje (-m)<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Prueba kk modificado&#8221;<\/font><\/p>\n<pre class=\"codigo\">Commit de la revisi\u00f3n 2.<\/pre>\n<p>Consultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><br \/>\nNo hay diferencias con el repositorio<\/p>\n<h3>Conflictos con ficheros<\/h3>\n<p>Si existen varios desarrolladores, puede ocurrir un conflicto al &#8220;subir&#8221; un fichero que haya sido modificado desde que hicimos el update.<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Forzamos conflicto&#8221;<\/font><\/p>\n<pre class=\"codigo\">Enviando       kk\r\nsvn: Fall\u00f3 el commit (detalles a continuaci\u00f3n):\r\nsvn: Desactualizado: 'kk' en transacci\u00f3n '5-1'\r\n<\/pre>\n<p><font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">M      ejemplo2.py<\/pre>\n<p>Podemos abreviar &#8216;update&#8217; como &#8216;up&#8217;<br \/>\n<font class=\"comando\">$ svn up<\/font><\/p>\n<pre class=\"codigo\">C    ejemplo2.py\r\nActualizado a la revisi\u00f3n 3.<\/pre>\n<p>Al encontrar el conflicto, SVN genera 4 ficheros, uno con el conflicto, el local, el de la revisi\u00f3n anterior (r2) y el de la nueva revisi\u00f3n (r3).<br \/>\n<font class=\"comando\">$ ls -l<\/font><\/p>\n<pre class=\"codigo\">...\r\n-rw-r--r-- 1 guimi guimi 111 2007-07-09 19:51 kk\r\n-rw-r--r-- 1 guimi guimi  49 2007-07-09 19:51 kk.mine\r\n-rw-r--r-- 1 guimi guimi  29 2007-07-09 19:51 kk.r2\r\n-rw-r--r-- 1 guimi guimi  57 2007-07-09 19:51 kk.r3\r\n<\/pre>\n<p>Tras corregir el conflicto, indicamos que lo hemos resuelto:<br \/>\n<font class=\"comando\">$ vi kk<br \/>\n$ svn resolved ejemplo2.py<\/font><\/p>\n<pre class=\"codigo\">Se resolvi\u00f3 el conflicto de 'ejemplo2.py'<\/pre>\n<p>Al marcar el conflicto como resuelto, SVN borra los ficheros de resoluci\u00f3n.<\/p>\n<p>Volvemos a realizar el commit.<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Conflicto resuelto&#8221;<\/font><\/p>\n<h3>Borrar ficheros<\/h3>\n<p>Probamos a borrar un fichero de nuestro disco duro<br \/>\n<font class=\"comando\">$ rm kk<\/font><br \/>\nConsultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">!       kk<\/pre>\n<p>La diferencia con el repositorio es que localmente falta un fichero<\/p>\n<p>Si actualizamos la informaci\u00f3n del repositorio&#8230;<br \/>\n<font class=\"comando\">$ svn update<\/font><\/p>\n<pre class=\"codigo\">Se restituy\u00f3 'kk'\r\nEn la revisi\u00f3n 2.<\/pre>\n<p>&#8230;recuperamos el fichero borrado.<br \/>\nPara eliminar un fichero del proyecto debemos indicar al sistema que lo elimine del repositorio.<br \/>\nQuitamos un fichero del proyecto (y lo borramos de nuestro disco duro)<br \/>\n<font class=\"comando\">$ svn delete kk<\/font><br \/>\nQuitamos otro fichero del repositorio, pero mantenemos la copia local<br \/>\n<font class=\"comando\">$ svn delete &#8211;keep-local kk2<\/font><br \/>\nConsultamos la informaci\u00f3n de los ficheros locales<br \/>\n<font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">D         kk\r\nD         kk2<\/pre>\n<p>La \u00fanica diferencia con el repositorio es que hay dos fichero por eliminar.<\/p>\n<p>Hacemos commit (ci) de las modificaciones y dejamos una nota o mensaje (-m)<br \/>\n<font class=\"comando\">$ svn ci -m &#8220;Borrado de ficheros&#8221;<\/font><\/p>\n<pre class=\"codigo\">Eliminando     kk\r\nEliminando     kk2\r\nCommit de la revisi\u00f3n 3.<\/pre>\n<h3>Renombrar ficheros<\/h3>\n<p><font class=\"comando\">$ svn mv kk ejemplo<\/font><\/p>\n<pre class=\"codigo\">\r\nA         ejemplo\r\nD         kk\r\n<\/pre>\n<p><font class=\"comando\">$ svn status<\/font><\/p>\n<pre class=\"codigo\">\r\nD      kk\r\nA  +   ejemplo\r\n<\/pre>\n<p><font class=\"comando\">$ svn commit &#8211;message &#8220;Cambio de nombre&#8221;<\/font><\/p>\n<pre class=\"codigo\">\r\nEliminando     ejemplo1.py\r\nA\u00f1adiendo      ejemplo2.py\r\n\r\nCommit de la revisi\u00f3n 3.\r\n<\/pre>\n<h2>Consultar el trabajo realizado<\/h2>\n<p>Vemos todo el trabajo que hemos realizado<br \/>\n<font class=\"comando\">$ svn log<\/font><\/p>\n<pre class=\"codigo\">------------------------------------------------------------------------\r\nr4 | guimi | 2012-02-07 20:52:05 +0100 (mar 07 de feb de 2012) | 1 line\r\n\r\nPrueba del kk\r\n------------------------------------------------------------------------\r\nr3 | guimi | 2012-02-07 20:51:39 +0100 (mar 07 de feb de 2012) | 1 line\r\n\r\nPrueba add kk\r\n------------------------------------------------------------------------\r\nr2 | guimi | 2012-02-07 20:39:46 +0100 (mar 07 de feb de 2012) | 1 line\r\n\r\nPrueba\r\n------------------------------------------------------------------------\r\nr1 | guimi | 2012-02-07 20:33:02 +0100 (mar 07 de feb de 2012) | 1 line\r\n\r\nImportacion inicial\r\n------------------------------------------------------------------------\r\n<\/pre>\n<p>podemos consultar el trabajo que hemos realizado respecto a un fichero concreto, por ejemplo AndroidManifest.xml<br \/>\n<font class=\"comando\">$ svn log AndroidManifest.xml<\/font><\/p>\n<pre class=\"codigo\">------------------------------------------------------------------------\r\nr1 | (sin autor) | 2012-02-07 20:33:02 +0100 (mar 07 de feb de 2012) | 1 line\r\n\r\nImportacion version inicial 0.1.5-Beta\r\n------------------------------------------------------------------------\r\n<\/pre>\n<div class=\"keywords\"><strong>svn, subversion, control de versiones<\/strong><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Esta entrada no pretende ser una gu\u00eda completa de subversion, solo una gu\u00eda r\u00e1pida para comenzar a trabajar con esta potente herramienta. Introducci\u00f3n Muchos proyectos est\u00e1n migrando de Svn a Git ya que Git les aporta una serie de ventajas, principalmente que Git es distribuido (SVN es centralizado). Git parece ser claramente mejor para proyectos [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":965,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-970","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/pages\/970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/comments?post=970"}],"version-history":[{"count":2,"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/pages\/970\/revisions"}],"predecessor-version":[{"id":972,"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/pages\/970\/revisions\/972"}],"up":[{"embeddable":true,"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/pages\/965"}],"wp:attachment":[{"href":"http:\/\/guimi.net\/blogs\/hiparco\/wp-json\/wp\/v2\/media?parent=970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}