Pouvez-vous effectuer un paiement partiel avec Subversion?


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.


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

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.


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)

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

-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.


-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.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.