Pouvez-vous effectuer un paiement partiel avec Subversion?

155

Si j'avais 20 répertoires sous le tronc / avec beaucoup de fichiers dans chacun et que j'avais besoin de seulement 3 de ces répertoires, serait-il possible de faire une extraction Subversion avec seulement ces 3 répertoires sous le tronc?

Lecture seulement
la source

Réponses:

78

Subversion 1.5 introduit des extractions éparses qui peuvent être quelque chose que vous pourriez trouver utile. De la documentation :

... répertoires clairsemés (ou extractions superficielles ) ... vous permet d'extraire facilement une copie de travail - ou une partie d'une copie de travail - de manière plus superficielle que la récursivité complète, avec la liberté d'importer des fichiers et sous-répertoires précédemment ignorés à un plus tard.

Richard Morgan
la source
259

En effet, grâce aux commentaires sur mon article ici, il semble que les répertoires clairsemés soient la voie à suivre. Je pense que ce qui suit devrait le faire:

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

Sinon, --depth immediatesau lieu d' emptyextraire les fichiers et les répertoires trunk/projsans leur contenu. De cette façon, vous pouvez voir quels répertoires existent dans le référentiel.


Comme mentionné dans la réponse de @ zigdon, vous pouvez également effectuer une extraction non récursive. Il s'agit d'un moyen plus ancien et moins flexible d'obtenir un effet similaire:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz
pkaeding
la source
4
Si j'émets ensuite une mise à jour svn sur le répertoire du tronc, est-ce que cela va dérouler tous les autres dossiers ou simplement mettre à jour ceux qui ont déjà été récupérés?
Rob Walker
2
Je reçois Skipped 'prom/foo'après svn update --set-depth infinity proj/foo:(
sam
2
Oh, vous devez mettre à jour le parent (proj / foo) avant de pouvoir mettre à jour plus profondément (proj / foo / boo).
sam
4
C'est une bonne réponse et, vraiment, devrait être celle correctement marquée. Merci pkaeding!
Jimbo
1
Vous devrez peut-être utiliser une étape intermédiaire avec svn update --set-depth immediates projafin de créer proj / foo pour la mise à jour.
Craig
6

Ou faites une extraction non récursive de / trunk, puis faites simplement une mise à jour manuelle des 3 répertoires dont vous avez besoin.

Zigdon
la source
6

J'ai écrit un script pour automatiser les caisses clairsemées complexes.

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

Si vous disposez déjà de la copie locale complète, vous pouvez supprimer les sous-dossiers indésirables à l'aide de la --set-depthcommande.

svn update --set-depth=exclude www

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

La set-depthcommande prend en charge les chemins multi-fichiers.

La mise à jour de la copie locale racine ne changera pas la profondeur du dossier modifié.

Pour restaurer le dossier en cours d'extraction récusive, vous pouvez l'utiliser à --set-depthnouveau avec le paramètre infinity.

svn update --set-depth=infinity www
Feng Weiwei
la source
-1

Sorte de. Comme le dit Bobby:

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

obtiendra les dossiers, mais vous obtiendrez des dossiers séparés du point de vue de la subversion. Vous devrez effectuer des validations et des mises à jour distinctes sur chaque sous-dossier.

Je ne pense pas que vous puissiez extraire un arbre partiel, puis travailler avec l'arbre partiel en tant qu'entité unique.

Rob Walker
la source
-10

Pas d'une manière particulièrement utile, non. Vous pouvez vérifier les sous-arbres (comme dans la suggestion de Bobby Jack), mais vous perdez alors la possibilité de les mettre à jour / de les valider de manière atomique; pour ce faire, ils doivent être placés sous leur parent commun, et dès que vous vérifiez le parent commun, vous téléchargez tout sous ce parent. La non-récursivité n'est pas une bonne option, car vous voulez que les mises à jour et les validations soient récursives.

DrPizza
la source
16
-1 pour une réponse qui est tout simplement fausse. Il existe de nombreux cas d'utilisation dans la vie réelle où vous souhaitez travailler uniquement sur un petit sous-ensemble de composants dans un grand projet, et vous ne souhaitez pas vérifier l'ensemble du projet.
Peter
Bien sûr, vous pouvez travailler avec ces sous-arbres indépendamment les uns des autres, mais je pense que DrPizza signifiait des commits / mises à jour non atomiques dans ce cas. Et cela peut être un problème dans certaines conditions.
Andry