Escriba un módulo Batch::Simple
que provee:
new
que recibe
'sort'
-n
, etc.
STDIN
input
no se especifica se entenderá que es STDIN
.
Por ejemplo:
my $c = Batch::Simple->new(command => 'sort', stdin => $infile, options => $options);La llamada a
new
retorna un objeto de la clase Batch::Simple
.
Batch::Simple
disponen de un método run
que ejecutará el programa.
El método run
devuelve un objeto Batch::Simple::Result
que tiene los siguientes
atributos:
stdout
: La salida por STDOUT del programa
stderr
: La salida por STDERR del programa
status
: El contenido de $?
Una posible implementación de run
consiste en redirigir los flujos de salida y de error durante
la ejecución a ficheros utilizando la metodología vista en la
sección Salvando Manejadores de Fichero 1.5.
Se usarán ficheros temporales para STDOUT
y STDERR
(veanse File::Temp
y File::Spec).
Para repasar la programación orientada a objetos en Perl puede repasar el capítulo Programación Orientada a Objetos de los apuntes de LHP o mejor aún, usar Moose y leer los siguientes artículos:
Para repasar la creación de módulos véase el capítulo Módulos de los apuntes de LHP.
Cree la estructura de directorios usando h2xs
o Module::Install
(Véase Module::Install::Philosophy):
pp2@nereida:~/src$ h2xs -X -A -n Batch::Simple Defaulting to backwards compatibility with perl 5.8.8 If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option. Writing Batch-Simple/lib/Batch/Simple.pm Writing Batch-Simple/Makefile.PL Writing Batch-Simple/README Writing Batch-Simple/t/Batch-Simple.t Writing Batch-Simple/Changes Writing Batch-Simple/MANIFESTAñada un directorio para el ejecutable e incluya su presencia dándolo de alta en el fichero
Batch-Simple/MANIFEST
y en la
entrada EXE_FILES
en la llamada a WriteMakefile
en el fichero Batch-Simple/Makefile.PL
:
pp2@nereida:~/src/Batch-Simple$ cat -n MANIFEST 1 Changes 2 Makefile.PL 3 MANIFEST 4 README 5 script/batch.pl 6 t/Batch-Simple.t 7 lib/Batch/Simple.pm pp2@nereida:~/src/Batch-Simple$ cat -n Makefile.PL 1 use ExtUtils::MakeMaker; 2 WriteMakefile( 3 NAME => 'Batch::Simple', 4 VERSION_FROM => 'lib/Batch/Simple.pm', # finds $VERSION 5 PREREQ_PM => {}, # e.g., Module::Name => 1.1 6 EXE_FILES => [ qw{script/batch.pl} ], 7 );Hay varias formas de garantizar que durante el periodo de desarrollo de una librería los ejecutables encuentran la librería. Uno es añadir
use blib
en el ejecutable:
pp2@nereida:~/src/Batch-Simple/script$ cat -n batch.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use Carp; 4 use Getopt::Long; 5 use Pod::Usage; 6 use blib; 7 use Batch::Simple; . ....................el módulo blib busca por un directorio de tipo
blib
hasta 5 niveles por encima del actual. Observa que eso significa que trabajas
con la copia en blib
y no el original en lib
.
Por tanto deberás hacer make
para asegurarte la actualización de la copia.
Otra forma de garantizar que la librería se encuentra es incluirla en
la variable PERL5LIB
.
Puedes usar como ejemplo de aplicación
el tar.gz
que implementa un
producto de matrices en C en
la página asociada con estos apuntes
(fichero matrix.tar.gz)
Revision control, also known as version control, source control or (source) code management (SCM), is the management of changes to documents, programs, and other information stored as computer files. It is most commonly used in software development, where a team of people may change the same files. Changes are usually identified by a number or letter code, termed the 'revision number', 'revision level', or simply 'revision'.
Software tools for revision control are essential for the organization of multi-developer projects.
Subversion es un programa para el control de versiones.
Esta imagen del libro de subversion ilustra su funcionamiento:
You can think of every object in the repository as existing in a sort of two-dimensional coordinate system. The first coordinate is a particular revision tree, and the second coordinate is a path within that tree
Parece que en banot
esta instalado subversion.
Para crear un repositorio emita el comando svnadmin create
:
-bash-3.1$ uname -a Linux banot.etsii.ull.es 2.6.24.2 #3 SMP Fri Feb 15 10:39:28 WET 2008 i686 i686 i386 GNU/Linux -bash-3.1$ svnadmin create /home/loginname/repository/ -bash-3.1$ ls -l repository/ total 28 drwxr-xr-x 2 loginname apache 4096 feb 28 11:58 conf drwxr-xr-x 2 loginname apache 4096 feb 28 11:58 dav drwxr-sr-x 5 loginname apache 4096 feb 28 12:09 db -r--r--r-- 1 loginname apache 2 feb 28 11:58 format drwxr-xr-x 2 loginname apache 4096 feb 28 11:58 hooks drwxr-xr-x 2 loginname apache 4096 feb 28 11:58 locks -rw-r--r-- 1 loginname apache 229 feb 28 11:58 README.txt
Una alternativa a considerar es ubicar el repositorio en un dispositivo de almacenamiento portable (pendriver)
Ahora esta en condiciones de añadir proyectos
al repositorio creado usando svn import
:
[loginname@tonga]~/src/perl/> uname -a Linux tonga 2.6.24.2 #1 SMP Thu Feb 14 15:37:31 WET 2008 i686 i686 i386 GNU/Linux [loginname@tonga]~/src/perl/> pwd /home/loginname/src/perl [loginname@tonga]~/src/perl/> ls -ld /home/loginname/src/perl/Grammar-0.02 drwxr-xr-x 5 loginname Profesor 4096 feb 28 2008 /home/loginname/src/perl/Grammar-0.02 [loginname@tonga]~/src/perl/> svn import -m 'Grammar Extended Module' \ Grammar-0.02/ \ svn+ssh://banot/home/loginname/repository/Grammar Añadiendo Grammar-0.02/t Añadiendo Grammar-0.02/t/Grammar.t Añadiendo Grammar-0.02/lib Añadiendo Grammar-0.02/lib/Grammar.pm Añadiendo Grammar-0.02/MANIFEST Añadiendo Grammar-0.02/META.yml Añadiendo Grammar-0.02/Makefile.PL Añadiendo Grammar-0.02/scripts Añadiendo Grammar-0.02/scripts/grammar.pl Añadiendo Grammar-0.02/scripts/Precedencia.yp Añadiendo Grammar-0.02/scripts/Calc.yp Añadiendo Grammar-0.02/scripts/aSb.yp Añadiendo Grammar-0.02/scripts/g1.yp Añadiendo Grammar-0.02/Changes Añadiendo Grammar-0.02/README Commit de la revisión 2.
En general, los pasos para crear un nuevo proyecto son:
* mkdir /tmp/nombreProyecto * mkdir /tmp/nombreProyecto/branches * mkdir /tmp/nombreProyecto/tags * mkdir /tmp/nombreProyecto/trunk * svn mkdir file:///var/svn/nombreRepositorio/nombreProyecto -m 'Crear el proyecto nombreProyecto' * svn import /tmp/nombreProyecto \ file:///var/svn/nombreRepositorio/nombreProyecto \ -m "Primera versión del proyecto nombreProyecto"
La copia en Grammar-0.02
ha sido usada para la creación del proyecto,
pero no pertenece aún al proyecto. Es necesario descargar la copia del
proyecto que existe en el repositorio. Para ello usamos
svn checkout
:
[loginname@tonga]~/src/perl/> rm -fR Grammar-0.02 [loginname@tonga]~/src/perl/> svn checkout svn+ssh://banot/home/loginname/repository/Grammar Grammar A Grammar/t A Grammar/t/Grammar.t A Grammar/MANIFEST A Grammar/META.yml A Grammar/lib A Grammar/lib/Grammar.pm A Grammar/Makefile.PL A Grammar/scripts A Grammar/scripts/grammar.pl A Grammar/scripts/Calc.yp A Grammar/scripts/Precedencia.yp A Grammar/scripts/aSb.yp A Grammar/scripts/g1.yp A Grammar/Changes A Grammar/README Revisión obtenida: 2Ahora disponemos de una copia de trabajo del proyecto en nuestra máquina local:
[loginname@tonga]~/src/perl/> tree Grammar Grammar |-- Changes |-- MANIFEST |-- META.yml |-- Makefile.PL |-- README |-- lib | `-- Grammar.pm |-- scripts | |-- Calc.yp | |-- Precedencia.yp | |-- aSb.yp | |-- g1.yp | `-- grammar.pl `-- t `-- Grammar.t 3 directories, 12 files [loginname@tonga]~/src/perl/> [loginname@tonga]~/src/perl/> cd Grammar [loginname@tonga]~/src/perl/Grammar/> ls -la total 44 drwxr-xr-x 6 loginname Profesor 4096 feb 28 2008 . drwxr-xr-x 5 loginname Profesor 4096 feb 28 2008 .. -rw-r--r-- 1 loginname Profesor 150 feb 28 2008 Changes drwxr-xr-x 3 loginname Profesor 4096 feb 28 2008 lib -rw-r--r-- 1 loginname Profesor 614 feb 28 2008 Makefile.PL -rw-r--r-- 1 loginname Profesor 229 feb 28 2008 MANIFEST -rw-r--r-- 1 loginname Profesor 335 feb 28 2008 META.yml -rw-r--r-- 1 loginname Profesor 1196 feb 28 2008 README drwxr-xr-x 3 loginname Profesor 4096 feb 28 2008 scripts drwxr-xr-x 6 loginname Profesor 4096 feb 28 2008 .svn drwxr-xr-x 3 loginname Profesor 4096 feb 28 2008 tObserve la presencia de los subdirectorios de control
.svn
.
Ahora podemos modificar el proyecto y hacer públicos los cambios
mediante svn commit
:
loginname@tonga]~/src/perl/Grammar/> svn rm META.yml D META.yml [loginname@tonga]~/src/perl/Grammar/> ls -la total 40 drwxr-xr-x 6 loginname Profesor 4096 feb 28 2008 . drwxr-xr-x 5 loginname Profesor 4096 feb 28 12:34 .. -rw-r--r-- 1 loginname Profesor 150 feb 28 12:34 Changes drwxr-xr-x 3 loginname Profesor 4096 feb 28 12:34 lib -rw-r--r-- 1 loginname Profesor 614 feb 28 12:34 Makefile.PL -rw-r--r-- 1 loginname Profesor 229 feb 28 12:34 MANIFEST -rw-r--r-- 1 loginname Profesor 1196 feb 28 12:34 README drwxr-xr-x 3 loginname Profesor 4096 feb 28 12:34 scripts drwxr-xr-x 6 loginname Profesor 4096 feb 28 2008 .svn drwxr-xr-x 3 loginname Profesor 4096 feb 28 12:34 t [loginname@tonga]~/src/perl/Grammar/> echo "Modifico README" >> README [loginname@tonga]~/src/perl/Grammar/> svn commit -m 'Just testing ...' Eliminando META.yml Enviando README Transmitiendo contenido de archivos . Commit de la revisión 3.Observe que ya no es necesario especificar el lugar en el que se encuentra el repositorio: esa información esta guardada en los subdirectorios de administración de subversion
.svn
El servicio de subversion parece funcionar desde fuera de la red del centro. Véase la conexión desde una maquina exterior:
pp2@nereida:/tmp$ svn checkout svn+ssh://loginname@banot.etsii.ull.es/home/loginname/repository/Grammar Grammar loginname@banot.etsii.ull.es's password: loginname@banot.etsii.ull.es's password: A Grammar/t A Grammar/t/Grammar.t A Grammar/MANIFEST A Grammar/lib A Grammar/lib/Grammar.pm A Grammar/Makefile.PL A Grammar/scripts A Grammar/scripts/grammar.pl A Grammar/scripts/Calc.yp A Grammar/scripts/Precedencia.yp A Grammar/scripts/aSb.yp A Grammar/scripts/g1.yp A Grammar/Changes A Grammar/README Revisión obtenida: 3
svn add directorio_o_fichero svn remove directorio_o_fichero
svn commit -m "Nueva version"
svn update
Para evitar la solicitud de claves cada vez que se comunica con el repositorio establezca autentificación SSH automática. Para ver como hacerlo puede consultar las instrucciones en la sección 2.1.3 o en:
http://search.cpan.org/~casiano/GRID-Machine/lib/GRID/Machine.pod#INSTALLATION
Consulte también las páginas del manual Unix de
ssh
, ssh-key-gen
, ssh_config
, scp
, ssh-agent
, ssh-add
, sshd
Véase la sección Revision Specifiers en el libro de Subversion
Véase la sección Examining History en el libro de Subversion
Véase la sección Undoing Working Changes en el libro de Subversion
vim
sobre diff
gvim -d file1 file2
?
diffupdate
?
]c
?
[c
?
8]c
?
do
?
dp
?
:diffg
?
:12,20diffg
?
:buffers
?
:buffer 2
?
:diffg 3
?
:diffg batch.mine
?
:diffput
?
:12,20diffput
?
zo
?
zO
?
zc
?
zO
?
:vnew
?
CTRL-W v
?
:set foldmethod=manual
?
zf}
?
:diffthis
?
:diffsplit filename
?
:windo
?
vim
:
:1,5yank a :6,10yank b :tabedit | put a | vnew | put b :windo diffthis
svn
en su sección
Resolve Conflicts (Merging Others'
Changes)
vimdiff
patch
? ¿Cómo se crea un patch?
:diffpatch filename
? (Véase la sección Patches o Parches
en los apuntes de LHP)
:vert diffpatch filename
?
$ svn diff modulos.tex -r PREV:HEAD > patch $ vi :.!svn cat modulos.tex -r PREV :vert diffpatch patch
Side by side diffs are much more legible and useful than those in unified format or any other lineardiff
. By default, thesvn diff
command presents output in the unified format, though it has an option,--diff-cmd
, which allows you to specify the program that will perform thediff
. Passingvimdiff
as thediff
command doesn't work as the options passed bysvn diff
are a bit complicated:
Veamos que es así. Escribimos el siguiente programa de prueba:
generaciondecodigos@nereida:~/bin$ cat -n ./foo.pl 1 #!/usr/bin/perl 2 3 print "'$_' " for @ARGV; 4 print "\n";
Ejecución:
$ svn diff --diff-cmd=/home/generaciondecodigos/bin/foo.pl overloading.tex -rPREV Index: overloading.tex =================================================================== '-u' '-L' 'overloading.tex (revisión: 5112)' '-L' 'overloading.tex (copia de trabajo)' '.svn/tmp/tempfile.tmp' 'overloading.tex'El argumento
-u
indica que se debe usar unified format y el
argumento -L
especifica la etiqueta que describe la correspondiente
versión.
Es necesario escribir un wrapper que prescinda de esas opciones y que se quede con los nombres de los dos ficheros:
pp2@nereida:~$ cat -n bin/diffwrap.sh 1 #!/bin/sh 2 3 # Configure your favorite diff program here. 4 DIFF="/usr/bin/vimdiff" 5 6 # Subversion provides the paths we need as the sixth and seventh 7 # parameters. 8 LEFT=${6} 9 RIGHT=${7} 10 11 # Call the diff command (change the following line to make sense for 12 # your merge program). 13 $DIFF $LEFT $RIGHT 14 15 # Return an errorcode of 0 if no differences were detected, 1 if some were. 16 # Any other errorcode will be treated as fatal.Ahora podemos establecer que este programa sea nuestro comando
diff
para
svn
editando el fichero de configuración ~/.subversion/config
:
pp2@nereida:~/Lbook$ grep 'diff' ~/.subversion/config ### Set diff-cmd to the absolute path of your 'diff' program. ### Subversion's internal diff implementation. # diff-cmd = diff_program (diff, gdiff, etc.) ### Set diff3-cmd to the absolute path of your 'diff3' program. ### Subversion's internal diff3 implementation. # diff3-cmd = diff3_program (diff3, gdiff3, etc.) ### Set diff3-has-program-arg to 'true' or 'yes' if your 'diff3' ### program accepts the '--diff-program' option. # diff3-has-program-arg = [true | false] diff-cmd = /home/pp2/bin/diffwrap.sh
Subversion admite una variedad de protocolos de red para conectarse con el repositorio.
Con subversion viene el programa svnserve
que escucha por conexiones de red y soporta
un modo de autentificación simple. Sólo debe usarse si esta en una LAN privada. En el siguiente
ejemplo arranco el daemon svnserve
en banot
:
bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-128.1.16.el5 #1 SMP Tue Jun 30 06:10:28 EDT 2009 i686 i686 i386 GNU/Linux -bash-3.2$ svnserve --listen-port=4040 -d -r repository -bash-3.2$ ps -fA | grep svn casiano 11876 1 0 11:16 ? 00:00:00 svnserve --listen-port=4040 -d -r repository casiano 12036 11698 0 11:22 pts/0 00:00:00 grep svn
Ahora puedo acceder al proyecto vía svn
desde otra máquina:
casiano@tonga:~$ svn co svn://banot:4040/acme-svn/trunk chuchu A chuchu/t A chuchu/t/00.load.t A chuchu/t/perlcritic.t A chuchu/t/pod.t A chuchu/t/pod-coverage.t A chuchu/MANIFEST A chuchu/lib A chuchu/lib/Acme A chuchu/lib/Acme/SVN.pm A chuchu/Makefile.PL A chuchu/Changes A chuchu/Build.PL A chuchu/README Revisión obtenida: 6
Aunque no tengo permisos de ejecución:
casiano@tonga:~$ cd chuchu casiano@tonga:~/chuchu$ echo prueba > prueba.txt casiano@tonga:~/chuchu$ svn add prueba.txt A prueba.txt casiano@tonga:~/chuchu$ svn commit prueba.txt -m 'added prueba.txt' svn: Falló el commit (detalles a continuación): svn: falló la autorización
Habría que dar permisos de escritura al repositorio y crear usuarios (véase svnserve, a custom server y svnserve.conf para los detalles)
El comando blame
permite
responder a la pregunta ¿En que revisión se introdujo esta línea?
La salida de svn blame
es una versión formateada del fichero en el que cada línea
es prefijada con la revisión en que la línea fué introducida
y el autor de esa revisión. Un sinónimo para blame
es annotate
.
Sigue un ejemplo de salida:
pp2@nereida:~/LBench-Test/lib/Bench$ svn annotate Test.pm | tail -25 3063 casiano for my $exp_name ( @{ $self->{SELECTED} } ) { 3064 lgforte $self->{EXPERIMENTS}{$exp_name}->connect; 3063 casiano $self->{EXPERIMENTS}{$exp_name}->execute_preamble; 3063 casiano } 2248 casiano 3063 casiano # Tomamos el array TEST como array para mantener el orden 3063 casiano # Por ello, no recorremos con for (keys @array) 3063 casiano # Usamos entonces while (@array) { $key, $value = splice ... } 3063 casiano # 3063 casiano while ( @{ $self->{TESTS} } ) { 3063 casiano my ( $test, $params ) = splice @{ $self->{TESTS} }, 0, 2; 2248 casiano 3063 casiano for my $exp_name ( @{ $self->{SELECTED} } ) { 3129 lgforte $self->{EXPERIMENTS}{$exp_name}->save_result( $params, $test ); 3063 casiano } 3063 casiano } 3063 casiano 3063 casiano for my $exp_name ( @{ $self->{SELECTED} } ) { 3063 casiano $self->{EXPERIMENTS}{$exp_name}->execute_postamble; 3063 casiano } 2248 casiano } 2248 casiano 2248 casiano 1; 2248 casiano 2248 casiano __END__
Las propiedades son metadatos asociados con los ficheros o directorios en el repositorio. Las propiedades pueden ser modificadas y actualizadas por los usuarios de la misma forma que los ficheros. Del mismo modo esta actividad puede dar lugar a conflictos. Las propiedades se usan para asociar datos extra con un fichero. Por ejemplo cada imagen en un repositorio conteniendo imágenes puede tener asociada una propiedad binaria que sea un thumbnail.
Las propiedades cuyo nombre comienzan por svn:
estan reservadas para subversion.
Por ejemplo:
svn:eol-style
es útil cuando debemos compartir ficheros de texto
entre diferentes S.O. Puede tomar uno de los valores: native
,
CRLF
,
LF
y
CR
.
svn:ignore
nos permite ignorar ciertos tipos de ficheros en comandos como svn status
pp2@nereida:~/Lbook$ svn status -u ? perlexamples.bbl ? perlexamples.ilg X perlbib ? labs ? perlexamples.dvi ? ejecuciondeprogramas.tex.bak ? perlexamples.idx ? perlexamples X booktt ? perlexamples.lof ? perlexamples.log ? perlexamples.toc ? perlexamples.aux ? perlexamples.lot M 5463 practicaAndSVN.tex ? perlexamples.blg ? perlexamples.pdf ? perlexamples.ind ? new Estado respecto a la revisión: 5463 Averiguando el estado del recurso externo en 'perlbib' Estado respecto a la revisión: 5463 Averiguando el estado del recurso externo en 'booktt' ? booktt/preamble.bak Estado respecto a la revisión: 5463 pp2@nereida:~/Lbook$ svn propedit svn:ignore . # Editando con vi ... 1 *.bbl 2 *.ilg 3 *.dvi 4 *.bak 5 *.idx 6 *.lof 7 *.log 8 *.toc 9 *.aux 10 *.lot 11 *.blg 12 *.pdf 13 *.ind # Salimos: wq Se asignó un nuevo valor a la propiedad 'svn:ignore' en '.' # Ahora al solicitar el status se ignoran los ficheros especificados: pp2@nereida:~/Lbook$ svn status -u X perlbib ? labs ? perlexamples X booktt ? new Estado respecto a la revisión: 5470 Averiguando el estado del recurso externo en 'perlbib' Estado respecto a la revisión: 5470 Averiguando el estado del recurso externo en 'booktt' ? booktt/preamble.bak Estado respecto a la revisión: 5470
svn:executable
permite especificar que un cierto fichero es ejecutable:
pp2@nereida:~/Lbook$ svn propset svn:executable true socks.pl propiedad 'svn:executable' asignada en 'socks.pl' pp2@nereida:~/Lbook$ svn proplist socks.pl Propiedades en 'socks.pl': svn:executable
svn:mime-type
Véase:
Ejemplo:$ svn propset svn:mime-type image/jpeg foo.jpg property 'svn:mime-type' set on 'foo.jpg'
Véase la sección Keyword Substitution en el libro de Subversion
El directorio ~/.subversion
contiene algunos ficheros de control:
pp2@nereida:~/Lbook$ tree /home/pp2/.subversion/ /home/pp2/.subversion/ |-- README.txt |-- auth | |-- svn.simple | | |-- 0538d14359bc5c0 | | |-- 16dbf53b0205461 | | `-- 7cb71bc67c219b9 | |-- svn.ssl.server | `-- svn.username |-- config `-- servers 4 directories, 6 filesFichero
~/.subversion/config
establece la configuración por defecto.
Utiliza el formato de configuración INI.
Para establecer propiedades en términos
de las extensiones de los ficheros debe rellenarse
la sección auto-props
:
### Set enable-auto-props to 'yes' to enable automatic properties ### for 'svn add' and 'svn import', it defaults to 'no'. ### Automatic properties are defined in the section 'auto-props'. enable-auto-props = yes ### Section for configuring automatic properties. [auto-props] ### The format of the entries is: ### file-name-pattern = propname[=value][;propname[=value]...] ### The file-name-pattern can contain wildcards (such as '*' and ### '?'). All entries which match will be applied to the file. ### Note that auto-props functionality must be enabled, which ### is typically done by setting the 'enable-auto-props' option. *.c = svn:eol-style=native *.cpp = svn:eol-style=native *.h = svn:eol-style=native # *.dsp = svn:eol-style=CRLF # *.dsw = svn:eol-style=CRLF *.sh = svn:eol-style=native;svn:executable *.pl = svn:eol-style=native;svn:executable # *.txt = svn:eol-style=native *.png = svn:mime-type=image/png *.jpg = svn:mime-type=image/jpeg Makefile = svn:eol-style=native
Conforme evolucionan los proyectos descubrimos que existen áreas comunes entre ellos que pueden factorizarse y ser reutilizadas en varios proyectos.
Una forma de gestionar la compartición de subproyectos entre proyectos es mediante
la propiedad svn:externals
, la cual nos permite incluir contenidos en
otro repositorio en nuestra copia de trabajo.
Por ejemplo, en la mayoría de los artículos y apuntes que escribo en LATEX
comparto la bibliografía. En vez de tener múltiples ficheros .bib
de
bibliografía por artículo prefiero tener uno garantizando así la consistencia.
Del mismo modo comparto los ficheros de estilo LATEX y las definiciones de comandos
LATEX. Así en el proyecto svn
de estos apuntes que lee tenemos:
pp2@nereida:~/Lbook$ svn proplist . Propiedades en '.': svn:externals pp2@nereida:~/Lbook$ svn propget svn:externals perlbib svn+ssh://casiano@arlom.pcg.ull.es/var/svn/casiano/BIBTEX/PERLBIB/trunk booktt svn+ssh://casiano@arlom.pcg.ull.es/var/svn/casiano/booktt/trunk lhplabels svn+ssh://casiano@arlom.pcg.ull.es/var/svn/casiano/LHP/perlexamples/labels.plSubversion no hace automáticamente
commit
de los cambios
en las copias de los subproyectos externos. Es necesario cambiar al directorio
en cuestión y ejecutar svn commit
.
pp2@nereida:~/Lbook$ svn status -qu Estado respecto a la revisión: 5463 Averiguando el estado del recurso externo en 'perlbib' Estado respecto a la revisión: 5463 Averiguando el estado del recurso externo en 'booktt' Estado respecto a la revisión: 5463
He aquí un ejemplo de como establecer svn:externals
:
MacBookdeCasiano:LPLDI2011 casiano$ svn propset svn:externals \ 'code svn+ssh://casiano@orion.pcg.ull.es/var/svn/casiano/PL/PLconferences/softwarepracticeandexperience/code' . property 'svn:externals' set on '.'Obsérvese el uso de las comillas simples protegiendo al segundo argumento de
svn propset
.
Ahora un update
cargará el subproyecto externo:
MacBookdeCasiano:LPLDI2011 casiano$ svn update Fetching external item into 'code' A code/MyopicPPCR.eyp A code/pascalnestedeyapp2.eyp A code/noPackratSolvedExpRG2.eyp A code/pascalnestedeyapp3.eyp A code/pascalenumeratedvsrangePPCR.eyp A code/reducereduceconflictnamefirst.eyp A code/Cplusplus.eyp A code/pascalenumeratedvsrangesolvedviadyn.eyp A code/dynamicgrammar.eyp A code/Range.eyp A code/nopackratSolved.eyp A code/reducereduceconflictPPCRwithAction.eyp A code/Myopic.eyp A code/noLRk_exp.eyp A code/Calc.eyp A code/input_for_dynamicgrammar.txt A code/pascalenumeratedvsrange.eyp A code/noPackratSolvedExpRG.eyp A code/pascalenumeratedvsrangenested.eyp A code/reducereduceconflictPPCR.eyp A code/nopackratPPCR.eyp A code/noPackratSolvedExp.eyp A code/Cplusplus2.eyp A code/MyopicSolved.eyp A code/pascalenumeratedvsrangesolvedviadyn2.eyp A code/noLRk_expSolved.eyp A code/noPackratSolvedExpRGconcept.eyp A code/reducereduceconflict.eyp A code/nopackrat.eyp Updated external to revision 6318. Updated to revision 6318. MacBookdeCasiano:LPLDI2011 casiano$
Consejo tomado del libro de subversión:
You should seriously consider using explicit revision numbers in all of your externals definitions. Doing so means that you get to decide when to pull down a different snapshot of external information, and exactly which snapshot to pull. Besides avoiding the surprise of getting changes to third-party repositories that you might not have any control over, using explicit revision numbers also means that as you backdate your working copy to a previous revision, your externals definitions will also revert to the way they looked in that previous revision, which in turn means that the external working copies will be updated to match they way they looked back when your repository was at that previous revision. For software projects, this could be the difference between a successful and a failed build of an older snapshot of your complex codebase.
El comando svn export
es similar a svn checkout
y nos
permite crear una copia del proyecto que no contiene los
directorios de administración .svn
pp2@nereida:~$ svn help export export: Crea una copia no versionada de un árbol. uso: 1. export [-r REV] URL[@REVPEG] [RUTA] 2. export [-r REV] RUTA1[@REVPEG] [RUTA2] 1. Exporta un árbol de directorios limpio del repositorio a RUTA, especificado por RUTA, en la revisión REV si se especifica, de otro modo se exporta HEAD. Si se omite la RUTA, se usa el último componente del URL para el nombre del directorio local creado. 2. Exporta un árbol de directorios limpio a RUTA2 a partir de la copia de trabajo especificada por RUTA1, en la revisión REV si especificada, si no en WORKING. Si se omite RUTA2, se usa el último componente de RUTA1 para el nombre del directorio local creado. Si no se especifica REV se preservarán todos los cambios locales. Los archivos que no estén bajo control de versiones no se copiarán. Si se especifica, REVPEG determina la revisión en la que el objetivo se busca primero.
El comando shopt
permite establecer y ver las opciones de la bash
:
casiano@exthost:~$ help shopt shopt: shopt [-pqsu] [-o] [optname ...] Set and unset shell options. Change the setting of each shell option OPTNAME. Without any option arguments, list all shell options with an indication of whether or not each is set. Options: -o restrict OPTNAMEs to those defined for use with `set -o' -p print each shell option with an indication of its status -q suppress output -s enable (set) each OPTNAME -u disable (unset) each OPTNAME Exit Status: Returns success if OPTNAME is enabled; fails if an invalid option is given or OPTNAME is disabled.Sin argumentos muestra los valores actuales de las opciones:
casiano@exthost:~$ shopt autocd off cdable_vars off cdspell off checkhash off checkjobs off checkwinsize on cmdhist on compat31 off compat32 off dirspell off dotglob off execfail off expand_aliases on extdebug off extglob on extquote on failglob off force_fignore on globstar off gnu_errfmt off histappend off histreedit off histverify off hostcomplete on huponexit off interactive_comments on lithist off login_shell on mailwarn off no_empty_cmd_completion off nocaseglob off nocasematch off nullglob off progcomp on promptvars on restricted_shell off shift_verbose off sourcepath on xpg_echo off
Las opciones extglob
y progcomp
gobiernan
la forma en la que se completan los comandos cuando se presiona la tecla TAB
:
$shopt -s extglob progcompPor otro lado el comando
complete
permite especificar como se completa un comando:
complete: complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] \ [-W wordlist] [-F function] [-C command] [-X filterpat] \ [-P prefix] [-S suffix] [name ...] Specify how arguments are to be completed by Readline. For each NAME, specify how arguments are to be completed. If no options are supplied, existing completion specifications are printed in a way that allows them to be reused as input. Options: -p print existing completion specifications in a reusable format -r remove a completion specification for each NAME, or, if no NAMEs are supplied, all completion specifications When completion is attempted, the actions are applied in the order the uppercase-letter options are listed above. Exit Status: Returns success unless an invalid option is supplied or an error occurs.
Así, si hacemos:
complete -W 'add blame praise annotate cat checkout co cleanup commit ci copy delete del \ remove rm diff di export help h import info list ls log merge mkdir move mv \ rename ren propdel pdel pd propedit pedit pe propget pget pg proplist plist pl \ propset pset ps resolved revert status stat st switch sw update up' svn
Un comando como svn h<TAB>
se completrá a svn help
.
Mejor aún, localize el fichero bash_completion
que viene con la distribución de subversion.
Puede encontrarlo en:
hágale un source a dicho script:
$ . bash_completionAsí podrá completar también las opciones de los subcomandos.
Para copiar un repositorio es necesario asegurarse que el repositorio no es modificado durante la copia. Si eso ocurriera la copia podría no ser válida. Además, para garantizar la consistencia, los distintos ficheros que constituyen la Berkeley DB deben ser copiados en un cierto orden.
El comando svnadmin hotcopy
svnadmin hotcopy RUTA_REPOS NUEVA_RUTA_REPOSpermite realizar una copia consistente de un repositorio. No es necesario detener la actividad de los clientes durante el proceso.
svnadmin dump
y svnadmin load
.
Estos dos comandos usan un sencillo formato de volcado consistente en cabeceras
RFC 822 (como los headers en e-mail) que son sencillos de analizar y en los contenidos en bruto de los ficheros
del repositorio. Una copia por volcado y carga nos protege también contra posibles cambios en la versión de la
librería DBD subyacente.
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-128.1.16.el5 #1 SMP Tue Jun 30 06:10:28 EDT 2009 i686 i686 i386 GNU/Linux -bash-3.2$ svnlook youngest repository/ 6 -bash-3.2$ svnadmin dump repository/ > dumprep.6 * Revisión 0 volcada. * Revisión 1 volcada. * Revisión 2 volcada. * Revisión 3 volcada. * Revisión 4 volcada. * Revisión 5 volcada. * Revisión 6 volcada. -bash-3.2$ ls -ltr | tail -1 -rw-r--r-- 1 casiano apache 14962 abr 3 18:29 dumprep.6
Para restaurar el repositorio en otra máquina debemos primero crear el repositorio y a continuación
cargarcon svnadmin load
el fichero volcado en la operación anterior:
pp2@nereida:~$ ssh banot cat dumprep.6 | svnadmin load mietsiirep <<< Nueva transacción iniciada, basada en la revisión original 1 * añadiendo ruta : acme-svn ... hecho. * añadiendo ruta : acme-svn/branches ... hecho. * añadiendo ruta : acme-svn/trunk ... hecho. * añadiendo ruta : acme-svn/trunk/Build.PL ... hecho. * añadiendo ruta : acme-svn/trunk/Changes ... hecho. * añadiendo ruta : acme-svn/trunk/MANIFEST ... hecho. * añadiendo ruta : acme-svn/trunk/Makefile.PL ... hecho. * añadiendo ruta : acme-svn/trunk/README ... hecho. * añadiendo ruta : acme-svn/trunk/lib ... hecho. * añadiendo ruta : acme-svn/trunk/lib/Acme ... hecho. * añadiendo ruta : acme-svn/trunk/lib/Acme/SVN.pm ... hecho. * añadiendo ruta : acme-svn/trunk/t ... hecho. * añadiendo ruta : acme-svn/trunk/t/00.load.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/perlcritic.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/pod-coverage.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/pod.t ... hecho. ------- Commit de la revisión 1 >>> <<< Nueva transacción iniciada, basada en la revisión original 2 * añadiendo ruta : acme-svn/branches/myacme-svn ...COPIED... hecho. ------- Commit de la revisión 2 >>> <<< Nueva transacción iniciada, basada en la revisión original 3 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 3 >>> <<< Nueva transacción iniciada, basada en la revisión original 4 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 4 >>> <<< Nueva transacción iniciada, basada en la revisión original 5 * editando ruta : acme-svn/branches/myacme-svn/Makefile.PL ... hecho. ------- Commit de la revisión 5 >>> <<< Nueva transacción iniciada, basada en la revisión original 6 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 6 >>>
Ahora el nuevo repositorio puede ser accedido desde cualquier otra máquina:
casiano@orion:~$ svn ls svn+ssh://pp2/home/pp2/mietsiirep acme-svn/ casiano@orion:~$ svn ls svn+ssh://pp2/home/pp2/mietsiirep/acme-svn branches/ trunk/ casiano@orion:~$ svn ls svn+ssh://pp2/home/pp2/mietsiirep/acme-svn/trunk Build.PL Changes MANIFEST Makefile.PL README lib/ t/
El comando svnadmin dump
admite las opciones --incremental
y --revision
que permiten producir copias mas pequeñas.
Guardemos primero las versiones de la 1 a la 4:
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-128.1.16.el5 #1 SMP Tue Jun 30 06:10:28 EDT 2009 i686 i686 i386 GNU/Linux -bash-3.2$ svnadmin dump --incremental --revision 1:4 repository > dumprep.1to4 * Revisión 1 volcada. * Revisión 2 volcada. * Revisión 3 volcada. * Revisión 4 volcada.y después las de la 5 a la 6:
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-128.1.16.el5 #1 SMP Tue Jun 30 06:10:28 EDT 2009 i686 i686 i386 GNU/Linux -bash-3.2$ svnadmin dump --incremental --revision 5:6 repository > dumprep.5to6 * Revisión 5 volcada. * Revisión 6 volcada.
Podemos ahora restaurar el repositorio en otra máquina. Primero creamos el repositorio:
pp2@nereida:~$ svnadmin create mietsiiincrepA continuación restauramos la primera parte:
pp2@nereida:~$ ssh banot cat dumprep.1to4 | svnadmin load mietsiiincrep <<< Nueva transacción iniciada, basada en la revisión original 1 * añadiendo ruta : acme-svn ... hecho. * añadiendo ruta : acme-svn/branches ... hecho. * añadiendo ruta : acme-svn/trunk ... hecho. * añadiendo ruta : acme-svn/trunk/Build.PL ... hecho. * añadiendo ruta : acme-svn/trunk/Changes ... hecho. * añadiendo ruta : acme-svn/trunk/MANIFEST ... hecho. * añadiendo ruta : acme-svn/trunk/Makefile.PL ... hecho. * añadiendo ruta : acme-svn/trunk/README ... hecho. * añadiendo ruta : acme-svn/trunk/lib ... hecho. * añadiendo ruta : acme-svn/trunk/lib/Acme ... hecho. * añadiendo ruta : acme-svn/trunk/lib/Acme/SVN.pm ... hecho. * añadiendo ruta : acme-svn/trunk/t ... hecho. * añadiendo ruta : acme-svn/trunk/t/00.load.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/perlcritic.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/pod-coverage.t ... hecho. * añadiendo ruta : acme-svn/trunk/t/pod.t ... hecho. ------- Commit de la revisión 1 >>> <<< Nueva transacción iniciada, basada en la revisión original 2 * añadiendo ruta : acme-svn/branches/myacme-svn ...COPIED... hecho. ------- Commit de la revisión 2 >>> <<< Nueva transacción iniciada, basada en la revisión original 3 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 3 >>> <<< Nueva transacción iniciada, basada en la revisión original 4 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 4 >>>
A continuación restauramos la segunda parte:
pp2@nereida:~$ ssh banot cat dumprep.5to6 | svnadmin load mietsiiincrep <<< Nueva transacción iniciada, basada en la revisión original 5 * editando ruta : acme-svn/branches/myacme-svn/Makefile.PL ... hecho. ------- Commit de la revisión 5 >>> <<< Nueva transacción iniciada, basada en la revisión original 6 * editando ruta : acme-svn/trunk/Makefile.PL ... hecho. ------- Commit de la revisión 6 >>> pp2@nereida:~$
Podemos acceder al nuevo repositorio desde una tercera máquina:
casiano@orion:~$ svn ls svn+ssh://pp2/home/pp2/mietsiiincrep acme-svn/ casiano@orion:~$ svn log svn+ssh://pp2/home/pp2/mietsiiincrep/acme-svn/trunk/ ------------------------------------------------------------------------ r6 | lgforte | 2009-04-23 11:54:54 +0100 (jue, 23 abr 2009) | 1 line lgforte modification ------------------------------------------------------------------------ r4 | casiano | 2009-03-05 15:56:20 +0000 (jue, 05 mar 2009) | 1 line sally in trunk: list of final comments ------------------------------------------------------------------------ r3 | casiano | 2009-03-05 15:56:02 +0000 (jue, 05 mar 2009) | 1 line sally in trunk: list of comments ------------------------------------------------------------------------ r1 | casiano | 2009-03-05 15:53:05 +0000 (jue, 05 mar 2009) | 1 line branches ------------------------------------------------------------------------
Si múltiples usuarios estan accediendo al repositorio vía svn+ssh
será necesario también garantizar
que los permisos del repositorio son los adecuados. Por ejemplo:
bash-2.05b# ls -l | grep svn drwxrwxr-x 7 svn svnusers 512 Apr 27 15:06 reponame1 drwxrwxr-x 7 svn svnusers 512 Apr 27 15:06 reponame2 drwxrwxr-x 7 svn svnusers 512 Apr 27 15:06 reponame3 bash-2.05b# ls -l reponame1/ | egrep -i "db" drwxrwsr-x 2 svn svnusers 512 Apr 27 15:07 db bash-2.05b#
Veamos un ejemplo de creación de un tag. Primero creamos el proyecto:
casiano@exthost:~/src/subversion/BUG-3035$ svn mkdir svn+ssh://banot/home/casiano/repository/ejemplo/ Committed revision 1. casiano@exthost:~/src/subversion/BUG-3035$ svn mkdir svn+ssh://banot/home/casiano/repository/ejemplo/tags/ Committed revision 2. casiano@exthost:~/src/subversion/BUG-3035$ svn mkdir svn+ssh://banot/home/casiano/repository/ejemplo/branches/ Committed revision 3. casiano@exthost:~/src/subversion$ h2xs -XA -n SVN::Example Defaulting to backwards compatibility with perl 5.10.0 If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option. Writing SVN-Example/lib/SVN/Example.pm Writing SVN-Example/Makefile.PL Writing SVN-Example/README Writing SVN-Example/t/SVN-Example.t Writing SVN-Example/Changes Writing SVN-Example/MANIFEST casiano@exthost:~/src/subversion$ svn import SVN-Example/ svn+ssh://banot/home/casiano/repository/ejemplo/trunk/ Adding SVN-Example/t Adding SVN-Example/t/SVN-Example.t Adding SVN-Example/lib Adding SVN-Example/lib/SVN Adding SVN-Example/lib/SVN/Example.pm Adding SVN-Example/MANIFEST Adding SVN-Example/Makefile.PL Adding SVN-Example/Changes Adding SVN-Example/README Committed revision 4. casiano@exthost:~/src/subversion$ svn ls svn+ssh://banot/home/casiano/repository/ejemplo/trunk/ Changes MANIFEST Makefile.PL README lib/ t/
Para crear una etiqueta hacemos una copia:
casiano@exthost:~/src/subversion/ejemplo$ svn cp svn+ssh://banot/home/casiano/repository/ejemplo/trunk \ svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-1.0 \ -m 'tagging release 1.0' Committed revision 12. casiano@exthost:~/src/subversion/ejemplo$ svn diff svn+ssh://banot/home/casiano/repository/ejemplo/trunk \ svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-1.0 casiano@exthost:~/src/subversion/ejemplo$
casiano@exthost:~/src/subversion$ svn cp svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-1.0 \ svn+ssh://banot/home/casiano/repository/ejemplo/branches/TRY-MGM-cache-pages casiano@exthost:~/src/subversion$ svn checkout svn+ssh://banot/home/casiano/repository/ejemplo/branches/TRY-MGM-cache-pages A TRY-MGM-cache-pages/t A TRY-MGM-cache-pages/t/SVN-Example.t A TRY-MGM-cache-pages/MANIFEST A TRY-MGM-cache-pages/lib A TRY-MGM-cache-pages/lib/SVN A TRY-MGM-cache-pages/lib/SVN/Example.pm A TRY-MGM-cache-pages/Makefile.PL A TRY-MGM-cache-pages/Changes A TRY-MGM-cache-pages/README Checked out revision 7.
Ahora, mientras un grupo trabaja en la rama TRY-MGM-cache-pages ...
casiano@exthost:~/src/subversion$ cd TRY-MGM-cache-pages/ casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ vi lib/SVN/Example.pm casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn commit -mm Sending lib/SVN/Example.pm Transmitting file data . Committed revision 8. casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn diff lib/SVN/Example.pm -r PREV Index: lib/SVN/Example.pm =================================================================== --- lib/SVN/Example.pm (revision 7) +++ lib/SVN/Example.pm (working copy) @@ -28,6 +28,12 @@ our $VERSION = '0.01'; +sub g1{ +} + +sub g2{ +} + # Preloaded methods go here. 1;
otro trabaja en el tronco ...
casiano@exthost:~/src/subversion$ svn checkout svn+ssh://banot/home/casiano/repository/ejemplo/trunk/ ejemplo A ejemplo/t A ejemplo/t/SVN-Example.t A ejemplo/MANIFEST A ejemplo/lib A ejemplo/lib/SVN A ejemplo/lib/SVN/Example.pm A ejemplo/Makefile.PL A ejemplo/Changes A ejemplo/README Checked out revision 4. casiano@exthost:~/src/subversion$ cd ejemplo casiano@exthost:~/src/subversion/ejemplo$ vi lib/SVN/Example.pm casiano@exthost:~/src/subversion/ejemplo$ svn commit Sending lib/SVN/Example.pm Transmitting file data . Committed revision 5. casiano@exthost:~/src/subversion/ejemplo$ svn diff lib/SVN/Example.pm -r PREV Index: lib/SVN/Example.pm =================================================================== --- lib/SVN/Example.pm (revision 4) +++ lib/SVN/Example.pm (working copy) @@ -30,6 +30,12 @@ # Preloaded methods go here. +sub new_functionality1 { +} + +sub new_functionality2 { +} + 1; __END__ # Below is stub documentation for your module. You'd better edit it!
Supongamos que ahora se crea un tag para la release 2.0:
casiano@exthost:~/src/subversion/ejemplo$ svn cp svn+ssh://banot/home/casiano/repository/ejemplo/trunk \ svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-2.0Y que queremos mezclar los cambios que se han producido entre las releases 1.0 y 2.0 en la rama RY-MGM-cache-pages:
casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn merge svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-1.0 \ svn+ssh://banot/home/casiano/repository/ejemplo/tags/REL-2.0 \ . --- Merging differences between repository URLs into '.': U lib/SVN/Example.pmEl estatus nos muestra que el fichero
lib/SVN/Example.pm
ha sido modificado en la copia de trabajo:
casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn status M lib/SVN/Example.pmVeamos cuales son las diferencias:
casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn diff lib/SVN/Example.pm -r BASE Index: lib/SVN/Example.pm =================================================================== --- lib/SVN/Example.pm (revision 8) +++ lib/SVN/Example.pm (working copy) @@ -36,6 +36,15 @@ # Preloaded methods go here. +sub new_functionality1 { +} + +sub new_functionality2 { +} + +sub new_functionality3 { +} + 1; __END__ # Below is stub documentation for your module. You'd better edit it!
Many users (especially those new to version control) are initially
perplexed about the proper syntax of the command and about how and when
the feature should be used. But fear not, this command is actually much
simpler than you think! There's a very easy technique for understanding
exactly how svn merge
behaves.
The main source of confusion is the name of the command. The term“merge”
somehow denotes that branches are combined together, or that some sort of mysterious blending of data is going on. That's not the case. A better name for the command might have beensvn diff-and-apply
, because that's all that happens: two repository trees are compared, and the differences are applied to a working copy.
Supongamos que se sigue trabajando en el tronco:
casiano@exthost:~/src/subversion/ejemplo$ vi lib/SVN/Example.pm casiano@exthost:~/src/subversion/ejemplo$ svn commit -m 'some bug fixed' Sending lib/SVN/Example.pm Transmitting file data . Committed revision 11.Estos fueron los cambios realizados:
casiano@exthost:~/src/subversion/ejemplo$ svn diff lib/SVN/Example.pm -r PREV Index: lib/SVN/Example.pm =================================================================== --- lib/SVN/Example.pm (revision 10) +++ lib/SVN/Example.pm (working copy) @@ -37,6 +37,7 @@ } sub new_functionality3 { + # some bug fixed here } 1;Podemos incorporar los cambios realizados en el tronco a la rama
casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn merge -r10:11 svn+ssh://banot/home/casiano/repository/ejemplo/trunk/ --- Merging r11 into '.': U lib/SVN/Example.pm casiano@exthost:~/src/subversion/TRY-MGM-cache-pages$ svn commit Sending lib/SVN/Example.pm Transmitting file data . Committed revision 13.
After performing the merge, you might also need to resolve some conflicts
(just as you do with svn update
) or possibly make some small edits to get
things working properly.
Remember: just because there are no syntactic conflicts doesn't mean there aren't any semantic conflicts!
If you
encounter serious problems, you can always abort the local changes by
running svn revert . -R
(which will undo all local modifications) and
start a long what's going on? discussion with your collaborators.
If you don't like the results of the merge, simply runsvn revert . -R
to revert the changes from your working copy and retry the command with different options. The merge isn't final until you actuallysvn commit
the results.
...
While it's perfectly fine to experiment with merges by runningsvn merge
andsvn revert
over and over, you may run into some annoying (but easily bypassed) roadblocks.
For example, if the merge operation adds a new file (i.e., schedules it for addition),svn revert
won't actually remove the file; it simply unschedules the addition. You're left with an unversioned file. If you then attempt to run the merge again, you may get conflicts due to the unversioned file“being in the way.”
Solution? After performing arevert
, be sure to clean up the working copy and remove unversioned files and directories. The output ofsvn status
should be as clean as possible, ideally showing no output.
Véanse los artículos de la Wikipedia sobre Gestión de Configuraciones:
Configuration management (CM) is a field of management that focuses on
throughout its life.
In configuration management (CM), one has to control (among other things) changes made to software and documentation. This is called revision control, which manages multiple versions of the same unit of information. Although revision control is important to CM, it is not equal to it.
Synchronization Models, also known as Configuration Management Models, describe methods to enable revision control through allowing simultaneous, concurrent changes to individual files.
In revision control, changesets are a way to group a number of modifications that are relevant to each other in one atomic package, that may be cancelled or propagated as needed.
Los siguientes párrafos están tomados de http://itil.osiatis.es/ITIL_course/it_service_management/configuration_management/introduction_and_objectives_configuration_management/introduction_and_objectives_configuration_management.php.
The four main functions of Configuration Management may be summarised as:
It is essential to have a detailed knowledge of your organisation's IT infrastructure in order to make best use of it. The main task of Configuration Management is to keep an up-to-date record of all the components in the IT infrastructure configuration and the interrelations between them.
This is not a simple task and requires the cooperation of the people managing other processes, in particular Change Management and Release Management.
The main objectives of Configuration Management are:
The benefits of correct Configuration Management include, among other things:
The main activities difficulties in Configuration Management are:
En subversión la definición de changeset es mas concreta:
A changeset is just a collection of changes with a unique name. The changes might include
In more common speak, a changeset is just a patch with a name you can refer to.
In Subversion, a global revision numberN
names a tree in the repository: it's the way the repository looked after theN
th commit. It's also the name of an implicit changeset: if you compare treeN
with treeN−1
, you can derive the exact patch that was committed. For this reason, it's easy to think of revisionN
as not just a tree, but a changeset as well.
If you use an issue tracker to manage bugs, you can use the
revision numbers to refer to particular patches that fix bugs—for
example, 'this issue was fixed by r9238
.' Somebody can then run
svn log -r 9238
to read about the exact changeset that fixed the bug, and run
svn diff -c 9238 # La opción -c REV es equivalente a -r REV-1:REV
to see the patch itself.
Subversion'ssvn merge
command is able to use revision numbers. You can merge specific changesets from one branch to another by naming them in the merge arguments: passing-c 9238
tosvn merge
would merge changesetr9238
into your working copy.
The general act of replicating changes from one branch to another is
called merging, and it is performed using various invocations of the
svn merge
command.
Véase:
A hook script is a program triggered by some repository event, such as the creation of a new revision or the modification of an unversioned property. Each hook is handed enough information to tell what that event is, what target(s) it's operating on, and the username of the person who triggered the event. Depending on the hook's output or return status, the hook program may continue the action, stop it, or suspend it in some way.
To actually install a working hook, you need only place some executable
program or script into the repos/hooks
directory, which can be executed
as the name (such as start-commit or post-commit) of the hook.
Veamos el directorio hooks/
. El fichero pre-commit
tiene permisos de ejecución:
pp2@nereida:~$ ls -l svnrep/hooks/ total 40 -rw-r--r-- 1 pp2 pp2 2000 2010-04-12 10:33 post-commit.tmpl -rw-r--r-- 1 pp2 pp2 1690 2010-04-12 10:33 post-lock.tmpl -rw-r--r-- 1 pp2 pp2 2307 2010-04-12 10:33 post-revprop-change.tmpl -rw-r--r-- 1 pp2 pp2 1606 2010-04-12 10:33 post-unlock.tmpl -rwxr-xr-x 1 pp2 pp2 110 2010-04-19 08:30 pre-commit -rw-r--r-- 1 pp2 pp2 2982 2010-04-19 07:45 pre-commit.tmpl -rw-r--r-- 1 pp2 pp2 2038 2010-04-12 10:33 pre-lock.tmpl -rw-r--r-- 1 pp2 pp2 2764 2010-04-12 10:33 pre-revprop-change.tmpl -rw-r--r-- 1 pp2 pp2 1980 2010-04-12 10:33 pre-unlock.tmpl -rw-r--r-- 1 pp2 pp2 2758 2010-04-12 10:33 start-commit.tmpl
Estos son los contenidos de svnrep/hooks/pre-commit
:
pp2@nereida:~$ cat -n svnrep/hooks/pre-commit 1 #!/bin/sh 2 3 REPOS="$1" 4 TXN="$2" 5 6 /home/pp2/src/perl/subversion/pre-commit.pl "$REPOS" "$TXN" || exit 1 7 8 exit 0
El programa Perl simplemente comprueba que el mensaje de log es suficientemente largo:
pp2@nereida:~$ cat -n /home/pp2/src/perl/subversion/pre-commit.pl 1 #!/usr/bin/perl -w 2 use strict; 3 # creating scalar variables that holds some values 4 5 open my $file, '> /tmp/mylog'; 6 print $file "executing hook\n"; 7 close($file); 8 9 my $min = 8; 10 my $svnlook = '/usr/bin/svnlook'; 11 #-------------------------------------------- 12 my $repos = shift; 13 my $txn = shift; 14 15 unless (defined($repos) and defined($txn)) { 16 warn "Error: Expected repos and txn args\n"; 17 exit(3); 18 } 19 20 my $msg; 21 eval { 22 $msg = `$svnlook log -t "$txn" "$repos" 2>&1`; 23 }; 24 25 if ($@ or $?) { 26 warn qq{Error executing '$svnlook log -t "$txn" "$repos"'\nmessage:\n$msg\n}; 27 exit(2); 28 } 29 warn "repos=$repos txn=$txn msg=$msg\n"; 30 chomp($msg); 31 32 if (length($msg) < $min) { 33 warn "Message should be at least $min characters in length\n"; 34 exit(1); 35 } 36 37 exit(0);
Ahora modificamos un fichero en un proyecto y hacemos un commit con un mensaje corto:
pp2@nereida:~/src/perl/subversion/project$ svn commit -mm Enviando trunk/Makefile.PL Transmitiendo contenido de archivos .svn: Falló el commit (detalles a continuación): svn: Commit bloqueado por hook pre-commit (código de salida 1) con salida: repos=/home/pp2/svnrep txn=16-j msg=m Message should be at least 8 characters in length
El commit es aceptado si el mensaje es suficientemente largo:
pp2@nereida:~/src/perl/subversion/project$ svn commit -m 'longer message' Enviando trunk/Makefile.PL Transmitiendo contenido de archivos . Commit de la revisión 17.
commit-email.pl
puede ser usado como post-commit
hook para enviar emails:
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-164.15.1.el5 #1 SMP Wed Mar 17 11:37:14 EDT 2010 i686 i686 i386 GNU/Linux -bash-3.2$ /usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-email.pl /usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-email.pl: too few arguments. usage (commit mode): /usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-email.pl REPOS REVNUM [[-m regex] [options] [email_addr ...]] ... usage: (revprop-change mode): /usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-email.pl --revprop-change REPOS REVNUM USER PROPNAME [-d diff_file] \ [[-m regex] [options] [email_addr ...]] ... options are: --from email_address Email address for 'From:' (overrides -h) -h hostname Hostname to append to author for 'From:' -l logfile Append mail contents to this log file -m regex Regular expression to match committed path -r email_address Email address for 'Reply-To:' -s subject_prefix Subject line prefix --diff y|n Include diff in message (default: y) (applies to commit mode only) This script supports a single repository with multiple projects, where each project receives email only for actions that affect that project. A project is identified by using the -m command line option with a regular expression argument. If the given revision contains modifications to a path that matches the regular expression, then the action applies to the project. Any of the following -h, -l, -r, -s and --diff command line options and following email addresses are associated with this project. The next -m resets the -h, -l, -r, -s and --diff command line options and the list of email addresses. To support a single project conveniently, the script initializes itself with an implicit -m . rule that matches any modifications to the repository. Therefore, to use the script for a single- project repository, just use the other command line options and a list of email addresses on the command line. If you do not want a rule that matches the entire repository, then use -m with a regular expression before any other command line options or email addresses. 'revprop-change' mode: The message will contain a copy of the diff_file if it is provided, otherwise a copy of the (assumed to be new) property value.
Estos son los contenidos del ejecutable post-commit
en el subdirectorio hooks
:
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-164.15.1.el5 #1 SMP Wed Mar 17 11:37:14 EDT 2010 i686 i686 i386 GNU/Linux bash-3.2$ pwd /home/casiano/newrepository/hooks -bash-3.2$ ls -ltra post-commit -rwxr-xr-x 1 casiano apache 280 abr 20 14:08 post-commit -bash-3.2$ cat post-commit #!/bin/sh REPOS="$1" REV="$2" /usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-email.pl "$REPOS" "$REV" --from 'aluXXX@ull.es' -r 'aluXXX@ull.es' 'aluXXX@gmail.com'Supongamos que modificamos nuestra copia de trabajo y hacemos un commit:
pp2@nereida:~/src/perl/subversion/banotnewrepproject2$ svn info Ruta: . URL: svn+ssh://banot/home/casiano/newrepository/project2/trunk Raíz del repositorio: svn+ssh://banot/home/casiano/newrepository UUID del repositorio: faf63038-71ca-4861-8080-6a701f9d687f Revisión: 11 Tipo de nodo: directorio Agendado: normal Autor del último cambio: casiano Revisión del último cambio: 11 Fecha de último cambio: 2010-04-20 09:17:16 +0100 (mar 20 de abr de 2010) pp2@nereida:~/src/perl/subversion/banotnewrepproject2$ vi Makefile.PL pp2@nereida:~/src/perl/subversion/banotnewrepproject2$ svn commit -m 'checking post-commit' Enviando Makefile.PL Transmitiendo contenido de archivos . Commit de la revisión 20.Ahora en nuestra cuenta de correo tenemos un mensaje:
from aluXXX@ull.es reply-to aluXXX@ull.es to aluXXX@gmail.com date 20 April 2010 14:09 subject r20 - project2/trunk mailed-by ull.es hide details 14:09 (21 minutes ago) Author: aluXXX Date: 2010-04-20 14:09:35 +0100 (Tue, 20 Apr 2010) New Revision: 20 Modified: project2/trunk/Makefile.PL Log: checking post-commit Modified: project2/trunk/Makefile.PL =================================================================== --- project2/trunk/Makefile.PL 2010-04-20 08:32:45 UTC (rev 19) +++ project2/trunk/Makefile.PL 2010-04-20 13:09:35 UTC (rev 20) @@ -1,11 +1,4 @@ use ExtUtils::MakeMaker; - - -# -# -# -# -# WriteMakefile( NAME => 'project2', VERSION_FROM => 'lib/project2.pm', # finds $VERSION
pre-commit
:
-bash-3.2$ uname -a Linux banot.etsii.ull.es 2.6.18-164.15.1.el5 #1 SMP Wed Mar 17 11:37:14 EDT 2010 i686 i686 i386 GNU/Linux -bash-3.2$ pwd /home/casiano/newrepository/hooks -bash-3.2$ ls -l pre-commit -rwxr-xr-x 1 casiano apache 281 abr 20 17:17 pre-commit -bash-3.2$ -bash-3.2$ cat pre-commit #!/bin/sh REPOS="$1" TXN="$2" perl -I/home/casiano/perl5/lib/perl5/site_perl/5.8.8/ /home/casiano/newrepository/hooks/commit-access-control.pl \ "$REPOS" "$TXN" /home/casiano/newrepository/hooks/commit-access-control.cfg || exit 1 # All checks passed, so allow the commit. exit 0 -bash-3.2$En
/home/casiano/perl5/lib/perl5/site_perl/5.8.8/
se encuentra la librería Config::IniFiles
usada por
commit-access-control.pl
para parsear el fichero de configuración.
svn+ssh
.
Para ello, si no lo ha hecho ya, genere una pareja de claves y publique la clave en el servidor
subversion.
Recuerde el formato en el fichero authorized_keys
para identificarle:
-bash-3.2$ cat ~/.ssh/authorized_keys ............................................................. # key for subversion command="/usr/bin/svnserve -t -r /home/casiano/newrepository/ --tunnel-user=aluXXXX",no-port-forwarding ssh-dss AAAAB...................= myfriend key
-bash-3.2$ cat commit-access-control.cfg [Make everything read-only for all users] match = .* access = read-only [project1 aluXXXX permissions] match = ^project1/trunk users = myfriend access = read-write [casiano permissions] match = .* users = casiano access = read-write
ssh
para facilitar el acceso via svn
al repositorio:
aluXXXX@nereida:/tmp$ sed -ne '/svn/,//p' /home/aluXXXX/.ssh/config Host svn HostName banot.etsii.ull.es user casiano IdentityFile /home/aluXXXX/.ssh/id_dsa_svnA continuación descarga los proyectos en los que está interesado:
aluXXXX@nereida:/tmp$ svn ls svn+ssh://svn/ project1/ project2/ aluXXXX@nereida:/tmp$ svn checkout svn+ssh://svn/ A svn/project1 A svn/project1/trunk A svn/project1/trunk/t A svn/project1/trunk/t/project1.t A svn/project1/trunk/MANIFEST A svn/project1/trunk/lib A svn/project1/trunk/lib/project1.pm A svn/project1/trunk/Makefile.PL A svn/project1/trunk/Changes A svn/project1/trunk/README A svn/project1/branches A svn/project1/branches/branch1 A svn/project1/branches/branch1/t A svn/project1/branches/branch1/t/project1.t A svn/project1/branches/branch1/MANIFEST A svn/project1/branches/branch1/lib A svn/project1/branches/branch1/lib/project1.pm A svn/project1/branches/branch1/Makefile.PL A svn/project1/branches/branch1/Changes A svn/project1/branches/branch1/README A svn/project2 A svn/project2/trunk A svn/project2/trunk/t A svn/project2/trunk/t/project2.t A svn/project2/trunk/MANIFEST A svn/project2/trunk/lib A svn/project2/trunk/lib/project2.pm A svn/project2/trunk/Makefile.PL A svn/project2/trunk/Changes A svn/project2/trunk/README Revisión obtenida: 24Hace modificaciones e intenta un commit en la zona prohibida:
aluXXXX@nereida:/tmp$ cd svn/project1/branches/branch1 aluXXXX@nereida:/tmp/svn/project1/branches/branch1$ echo '# comentario'>>Makefile.PL aluXXXX@nereida:/tmp/svn/project1/branches/branch1$ svn commit -m 'checking permits' Enviando branch1/Makefile.PL Transmitiendo contenido de archivos .svn: Falló el commit (detalles a continuación): svn: El hook 'pre-commit' falló con la siguiente salida de error: /home/casiano/newrepository/hooks/commit-access-control.pl: user `aluXXXX' does not have permission to commit to these paths: project1/branches/branch1 project1/branches/branch1/Makefile.PL
Veamos que ocurre en la zona en la que tiene permisos de escritura:
aluXXXX@nereida:/tmp/svn/project1/branches/branch1$ cd /tmp/svn/project1/trunk/ aluXXXX@nereida:/tmp/svn/project1/trunk$ echo '# comentario'>>Makefile.PL aluXXXX@nereida:/tmp/svn/project1/trunk$ svn commit -m 'checking permits' Enviando trunk/Makefile.PL Transmitiendo contenido de archivos . Commit de la revisión 25. aluXXXX@nereida:/tmp/svn/project1/trunk$
Véanse:
/usr/share/doc/subversion-1.4.2/tools/hook-scripts/commit-access-control.pl
en banot
y en https://svn.apache.org/repos/asf/subversion/trunk/tools/hook-scripts/commit-access-control.pl.in
(Para entender el código necesitará repasar
las secciones
4.2,
4.2.1 y
4.2.2)
A sample configuration might look like the following, in which usersmother
,father
,dick
,jane
, andspot
(along with any other users who have unix-file-permission access to the repository) have read-access ontestproj-a
andtestproj-b
; but onlydick
andjane
can write (commit) totestproj-a
. Onlyspot
can write (commit) to any part oftestproj-b
, butfather
can commit to thebbq
directory oftestproj-b
, in thebranches
,tags
, and/ortrunk
directories of that project.
Note the special case login,mother
, who can write to all directories and files in this repository - includingSVN/
which is where the commit permission configuration file is versioned. Some account with this level of privilege is necessary if new projects are to be created in the repository (as siblings - if you will - totestproj-a
andtestproj-b
). It ismother
who would import the new projects and, presumably, modify the commit access configuration file to allow write access on the new project to appropriate users.
[Make everything read-only for all users] match = .* access = read-only [REPOSITORY WRITE EVERYTHING] match = .* access = read-write users = mother [SVN - config modification permissions] match = ^SVN access = read-write users = mother [testproj-a commit permissions] match = ^testproj-a/(branches|tags|trunk) users = dick jane access = read-write [testproj-b commit permissions] match = ^testproj-b/(branches|tags|trunk) users = spot access = read-write [testproj-b/bbq commit permissions] match = ^testproj-b/(branches|tags|trunk)/bbq users = father access = read-write
It's a common developer practice to track down a bug by looking for the change that introduced it. This is most efficiently done by performing a binary search between the last known working commit and the first known broken commit in the commit history.
At each step of the binary search, the bisect method checks out the source code at the commit chosen by the search. The user then has to test to see if the software is working or not. If it is, the user performs asvn-bisect good
, otherwise they do asvn-bisect bad
, and the search proceeds accordingly.
export LC_MESSAGES=C
)
casiano@exthost:~$ env | grep -i perl MANPATH=:/soft/perl5lib/man/ PERL5LIB=/soft/perl5lib/lib/perl5:/soft/perl5lib/lib/perl/5.10.0/:/soft/perl5lib/share/perl/5.10.0:/soft/perl5lib/share/perl/5.10/ PATH=.:/home/casiano/bin:/opt/groovy/groovy-1.7.1//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/soft/perl5lib/bin casiano@exthost:~$
svn-bisect
para averiguar en que versión del proyecto
se introdujo la funcionalidad que comprueba el test t/73dynamicshiftreduceconflictresolution.t
Consulte
En KDE puede instalar el cliente gráfico KDEsvn.