Você pode fazer um checkout parcial com o Subversion?

155

Se eu tivesse 20 diretórios sob o tronco / com muitos arquivos em cada um deles e apenas precisasse de 3 desses diretórios, seria possível fazer uma verificação no Subversion apenas com esses 3 diretórios no tronco?

Somente leitura
fonte
Veja também: stackoverflow.com/questions/1667986/…
Nakilon 4/13

Respostas:

78

O Subversion 1.5 apresenta checkouts esparsos, que podem ser algo que você pode achar útil. A partir da documentação :

... diretórios esparsos (ou caixas rasas ) ... permitem que você faça check-out facilmente de uma cópia de trabalho - ou de parte de uma cópia de trabalho - mais superficialmente do que a recursão total, com a liberdade de trazer arquivos e subdiretórios anteriormente ignorados de uma vez mais tarde.

Richard Morgan
fonte
259

De fato, graças aos comentários do meu post aqui, parece que diretórios esparsos são o caminho a percorrer. Eu acredito que o seguinte deve fazê-lo:

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

Como alternativa, em --depth immediatesvez de emptyretirar arquivos e diretórios trunk/projsem o conteúdo deles. Dessa forma, você pode ver quais diretórios existem no repositório.


Conforme mencionado na resposta do @ zigdon, você também pode fazer um checkout não recursivo. Essa é uma maneira mais antiga e menos flexível de obter um efeito semelhante:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz
pkaeding
fonte
4
Se eu emitir uma atualização svn no diretório do tronco, ela puxará para baixo todas as outras pastas ou apenas atualiza as que já foram recuperadas?
Rob Walker
2
Eu recebo Skipped 'prom/foo'depois svn update --set-depth infinity proj/foo:(
sam
2
Ah, você precisa atualizar o pai (proj / foo) antes de poder atualizar mais profundamente (proj / foo / boo).
sam
4
Esta é uma boa resposta e, realmente, deve ser a resposta correta. Obrigado pkaeding!
Jimbo
1
Você pode precisar usar uma etapa intermediária svn update --set-depth immediates projpara criar proj / foo para atualização.
Craig
6

Ou faça um checkout não recursivo de / trunk e faça uma atualização manual nos 3 diretórios necessários.

zigdon
fonte
6

Escrevi um script para automatizar checkouts complexos e esparsos.

#!/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
fonte
0

Se você já possui a cópia local completa, poderá remover subpastas indesejadas usando o --set-depthcomando

svn update --set-depth=exclude www

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

O set-depthcomando suporta caminhos de vários arquivos.

A atualização da cópia local raiz não altera a profundidade da pasta modificada.

Para restaurar a pasta para checkout recusativo, você pode usar --set-depthnovamente com o parâmetro infinito.

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

Tipo de. Como Bobby diz:

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

obterá as pastas, mas você obterá pastas separadas da perspectiva do subversion. Você precisará fazer confirmações e atualizações separadas em cada subpasta.

Não acredito que você possa fazer checkout de uma árvore parcial e trabalhar com a árvore parcial como uma única entidade.

Rob Walker
fonte
-10

Não de uma maneira especialmente útil, não. Você pode verificar as subárvores (como na sugestão de Bobby Jack), mas perde a capacidade de atualizá-las / enviá-las atomicamente; para fazer isso, eles precisam ser colocados sob o pai comum e, assim que você verificar o pai comum, você fará o download de tudo sob esse pai. Não recursivo não é uma boa opção, porque você deseja que as atualizações e confirmações sejam recursivas.

DrPizza
fonte
16
-1 para uma resposta que está simplesmente errada. Existem muitos casos de uso na vida real em que você deseja trabalhar apenas em um pequeno subconjunto dos componentes em um projeto grande e não deseja verificar o projeto inteiro.
Peter
Por uma causa, você pode trabalhar com essas subárvores independentemente entre si, mas acho que o DrPizza significava confirmações / atualizações não atômicas neste caso. E isso pode ser um problema em uma determinada condição.
Andry