Puoi fare un checkout parziale con Subversion?


Risposte:


78

Subversion 1.5 introduce checkout sparsi che potrebbero essere utili. Dalla documentazione :

... directory sparse (o checkout superficiali ) ... ti consente di estrarre facilmente una copia di lavoro - o una parte di una copia di lavoro - più superficialmente della ricorsione completa, con la libertà di inserire file e sottodirectory precedentemente ignorati in un più tardi.


259

In effetti, grazie ai commenti al mio post qui, sembra che le directory sparse siano la strada da percorrere. Credo che dovrebbe farlo:

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

In alternativa, --depth immediatesinvece di emptyestrarre file e directory trunk/projsenza il loro contenuto. In questo modo puoi vedere quali directory esistono nel repository.


Come menzionato nella risposta di @ zigdon, puoi anche fare un checkout non ricorsivo. Questo è un modo più vecchio e meno flessibile per ottenere un effetto simile:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz

4
Se poi invio un aggiornamento svn sulla directory trunk, tirerà giù tutte le altre cartelle o aggiornerà solo quelle che sono già state recuperate?
Rob Walker,

2
Ottengo Skipped 'prom/foo'dopo svn update --set-depth infinity proj/foo:(
sam

2
Oh, devi aggiornare il genitore (proj / foo) prima di poter aggiornare più in profondità (proj / foo / boo).
sam,

4
Questa è una buona risposta e, in realtà, dovrebbe essere quella correttamente contrassegnata. Grazie pkaeding!
Jimbo,

1
Potrebbe essere necessario utilizzare un passaggio intermedio in svn update --set-depth immediates projmodo da renderlo proj / foo per l'aggiornamento.
Craig,

6

Oppure esegui un checkout non ricorsivo di / trunk, quindi esegui un aggiornamento manuale delle 3 directory di cui hai bisogno.


6

Ho scritto una sceneggiatura per automatizzare checkout sparsi complessi.

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

Se hai già la copia locale completa, puoi rimuovere le sottocartelle indesiderate usando il --set-depthcomando.

svn update --set-depth=exclude www

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

Il set-depthcomando supporta percorsi multipli.

L'aggiornamento della copia locale root non cambierà la profondità della cartella modificata.

Per ripristinare il checkout della cartella in modo ricusivo, è possibile utilizzare --set-depthnuovamente con infinity param.

svn update --set-depth=infinity www

-1

Una specie di. Come dice Bobby:

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

otterrà le cartelle, ma otterrai cartelle separate dal punto di vista della sovversione. Dovrai eseguire commit e aggiornamenti separati su ogni sottocartella.

Non credo che puoi fare il checkout di un albero parziale e quindi lavorare con l'albero parziale come una singola entità.


-10

Non in alcun modo particolarmente utile, no. Puoi controllare i sottotitoli (come nel suggerimento di Bobby Jack), ma poi perdi la possibilità di aggiornarli / commetterli atomicamente; per farlo, devono essere posizionati sotto il loro genitore comune e non appena verifichi il genitore comune, scaricherai tutto sotto quel genitore. Non ricorsivo non è una buona opzione, perché si desidera che gli aggiornamenti e gli commit siano ricorsivi.


16
-1 per una risposta che è semplicemente sbagliata. Esistono molti casi d'uso nella vita reale in cui si desidera lavorare solo su un piccolo sottoinsieme dei componenti in un grande progetto e non si desidera controllare l'intero progetto.
Peter,

Di causa puoi lavorare con questi sottotitoli indipendentemente l'uno dall'altro, ma penso che DrPizza abbia significato commit / aggiornamenti non atomici in questo caso. E può essere un problema in una certa condizione.
Andry,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.