¿Puedes hacer un pago parcial con Subversion?

Respuestas:

78

Subversion 1.5 presenta pagos escasos que pueden ser algo que puede resultarle útil. De la documentación :

... directorios dispersos (o pagos poco profundos ) ... le permite retirar fácilmente una copia de trabajo, o una parte de una copia de trabajo, más superficialmente que la recursión completa, con la libertad de traer archivos y subdirectorios previamente ignorados en un tiempo más tarde.

Richard Morgan
fuente
259

De hecho, gracias a los comentarios a mi publicación aquí, parece que los directorios dispersos son el camino a seguir. Creo que lo siguiente debería hacerlo:

svn checkout --depth empty http://svnserver/trunk/proj
svn update --set-depth infinity proj/foo
svn update --set-depth infinity proj/bar
svn update --set-depth infinity proj/baz

Alternativamente, en --depth immediateslugar de emptyretirar archivos y directorios trunk/projsin sus contenidos. De esa manera puede ver qué directorios existen en el repositorio.


Como se menciona en la respuesta de @ zigdon, también puede hacer un pago no recursivo. Esta es una forma más antigua y menos flexible de lograr un efecto similar:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz
pkaeding
fuente
44
Si luego publico una actualización de svn en el directorio troncal, ¿eliminará todas las demás carpetas o solo actualizará las que ya se han recuperado?
Rob Walker
2
Me sale Skipped 'prom/foo'después svn update --set-depth infinity proj/foo:(
sam
2
Oh, debe actualizar el padre (proj / foo) antes de poder actualizar más profundamente (proj / foo / boo).
sam
44
Esta es una buena respuesta y, realmente, debería ser la marcada correctamente. Gracias pkaeding!
Jimbo
1
Es posible que necesite usar un paso intermedio svn update --set-depth immediates projpara que haga proj / foo para la actualización.
Craig
6

O haga un pago no recursivo de / trunk, luego simplemente haga una actualización manual en los 3 directorios que necesita.

zigdon
fuente
6

Escribí un script para automatizar pagos complejos y escasos.

#!/usr/bin/env python

'''
This script makes a sparse checkout of an SVN tree in the current working directory.

Given a list of paths in an SVN repository, it will:
1. Checkout the common root directory
2. Update with depth=empty for intermediate directories
3. Update with depth=infinity for the leaf directories
'''

import os
import getpass
import pysvn

__author__ = "Karl Ostmo"
__date__ = "July 13, 2011"

# =============================================================================

# XXX The os.path.commonprefix() function does not behave as expected!
# See here: http://mail.python.org/pipermail/python-dev/2002-December/030947.html
# and here: http://nedbatchelder.com/blog/201003/whats_the_point_of_ospathcommonprefix.html
# and here (what ever happened?): http://bugs.python.org/issue400788
from itertools import takewhile
def allnamesequal(name):
    return all(n==name[0] for n in name[1:])

def commonprefix(paths, sep='/'):
    bydirectorylevels = zip(*[p.split(sep) for p in paths])
    return sep.join(x[0] for x in takewhile(allnamesequal, bydirectorylevels))

# =============================================================================
def getSvnClient(options):

    password = options.svn_password
    if not password:
        password = getpass.getpass('Enter SVN password for user "%s": ' % options.svn_username)

    client = pysvn.Client()
    client.callback_get_login = lambda realm, username, may_save: (True, options.svn_username, password, True)
    return client

# =============================================================================
def sparse_update_with_feedback(client, new_update_path):
    revision_list = client.update(new_update_path, depth=pysvn.depth.empty)

# =============================================================================
def sparse_checkout(options, client, repo_url, sparse_path, local_checkout_root):

    path_segments = sparse_path.split(os.sep)
    path_segments.reverse()

    # Update the middle path segments
    new_update_path = local_checkout_root
    while len(path_segments) > 1:
        path_segment = path_segments.pop()
        new_update_path = os.path.join(new_update_path, path_segment)
        sparse_update_with_feedback(client, new_update_path)
        if options.verbose:
            print "Added internal node:", path_segment

    # Update the leaf path segment, fully-recursive
    leaf_segment = path_segments.pop()
    new_update_path = os.path.join(new_update_path, leaf_segment)

    if options.verbose:
        print "Will now update with 'recursive':", new_update_path
    update_revision_list = client.update(new_update_path)

    if options.verbose:
        for revision in update_revision_list:
            print "- Finished updating %s to revision: %d" % (new_update_path, revision.number)

# =============================================================================
def group_sparse_checkout(options, client, repo_url, sparse_path_list, local_checkout_root):

    if not sparse_path_list:
        print "Nothing to do!"
        return

    checkout_path = None
    if len(sparse_path_list) > 1:
        checkout_path = commonprefix(sparse_path_list)
    else:
        checkout_path = sparse_path_list[0].split(os.sep)[0]



    root_checkout_url = os.path.join(repo_url, checkout_path).replace("\\", "/")
    revision = client.checkout(root_checkout_url, local_checkout_root, depth=pysvn.depth.empty)

    checkout_path_segments = checkout_path.split(os.sep)
    for sparse_path in sparse_path_list:

        # Remove the leading path segments
        path_segments = sparse_path.split(os.sep)
        start_segment_index = 0
        for i, segment in enumerate(checkout_path_segments):
            if segment == path_segments[i]:
                start_segment_index += 1
            else:
                break

        pruned_path = os.sep.join(path_segments[start_segment_index:])
        sparse_checkout(options, client, repo_url, pruned_path, local_checkout_root)

# =============================================================================
if __name__ == "__main__":

    from optparse import OptionParser
    usage = """%prog  [path2] [more paths...]"""

    default_repo_url = "http://svn.example.com/MyRepository"
    default_checkout_path = "sparse_trunk"

    parser = OptionParser(usage)
    parser.add_option("-r", "--repo_url", type="str", default=default_repo_url, dest="repo_url", help='Repository URL (default: "%s")' % default_repo_url)
    parser.add_option("-l", "--local_path", type="str", default=default_checkout_path, dest="local_path", help='Local checkout path (default: "%s")' % default_checkout_path)

    default_username = getpass.getuser()
    parser.add_option("-u", "--username", type="str", default=default_username, dest="svn_username", help='SVN login username (default: "%s")' % default_username)
    parser.add_option("-p", "--password", type="str", dest="svn_password", help="SVN login password")

    parser.add_option("-v", "--verbose", action="store_true", default=False, dest="verbose", help="Verbose output")
    (options, args) = parser.parse_args()

    client = getSvnClient(options)
    group_sparse_checkout(
        options,
        client,
        options.repo_url,
        map(os.path.relpath, args),
        options.local_path)
kostmo
fuente
0

Si ya tiene la copia local completa, puede eliminar las subcarpetas no deseadas mediante el --set-depthcomando.

svn update --set-depth=exclude www

Ver: http://blogs.collab.net/subversion/sparse-directories-now-with-exclusion

El set-depthcomando admite múltiples rutas.

La actualización de la copia local raíz no cambiará la profundidad de la carpeta modificada.

Para restaurar la carpeta para que esté pagando recusivamente, puede usarla --set-depthnuevamente con infinity param.

svn update --set-depth=infinity www
Feng Weiwei
fuente
-1

Algo así como. Como dice Bobby:

svn co file:///.../trunk/foo file:///.../trunk/bar file:///.../trunk/hum

obtendrá las carpetas, pero obtendrá carpetas separadas desde una perspectiva de subversión. Tendrá que ir por separado confirmaciones y actualizaciones en cada subcarpeta.

No creo que pueda pagar un árbol parcial y luego trabajar con el árbol parcial como una sola entidad.

Rob Walker
fuente
-10

No de ninguna manera especialmente útil, no. Puede consultar los subárboles (como en la sugerencia de Bobby Jack), pero luego pierde la capacidad de actualizarlos / confirmarlos atómicamente; para hacerlo, deben colocarse debajo de su padre común, y tan pronto como revise el padre común, descargará todo debajo de ese padre. No recursivo no es una buena opción, porque desea que las actualizaciones y los commits sean recursivos.

DrPizza
fuente
16
-1 para una respuesta que simplemente es incorrecta. Hay muchos casos de uso en la vida real en los que desea trabajar solo en un pequeño subconjunto de componentes en un proyecto grande, y no desea verificar todo el proyecto.
Peter
Por supuesto, puede trabajar con estos subárboles de forma independiente entre sí, pero creo que DrPizza significaba confirmaciones / actualizaciones no atómicas en este caso. Y puede ser un problema en ciertas condiciones.
Andry