Können Sie mit Subversion eine teilweise Kaufabwicklung durchführen?

155

Wenn ich 20 Verzeichnisse unter Trunk / mit vielen Dateien in jedem hätte und nur 3 dieser Verzeichnisse benötige, wäre es dann möglich, eine Subversion-Prüfung mit nur diesen 3 Verzeichnissen unter Trunk durchzuführen?

Schreibgeschützt
quelle

Antworten:

78

Subversion 1.5 führt spärliche Kassen ein, die möglicherweise nützlich sind. Aus der Dokumentation :

... spärliche Verzeichnisse (oder flache Kassen ) ... ermöglichen das einfache Auschecken einer Arbeitskopie - oder eines Teils einer Arbeitskopie - flacher als die vollständige Rekursion, wobei Sie zuvor ignorierte Dateien und Unterverzeichnisse in a einfügen können späteren Zeitpunkt.

Richard Morgan
quelle
259

Dank der Kommentare zu meinem Beitrag hier sieht es tatsächlich so aus, als wären spärliche Verzeichnisse der richtige Weg. Ich glaube, das sollte es tun:

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

Alternativ --depth immediatesstatt emptycheckt Dateien und Verzeichnisse in trunk/projohne deren Inhalte. Auf diese Weise können Sie sehen, welche Verzeichnisse im Repository vorhanden sind.


Wie in der Antwort von @ zigdon erwähnt, können Sie auch eine nicht rekursive Prüfung durchführen. Dies ist ein älterer und weniger flexibler Weg, um einen ähnlichen Effekt zu erzielen:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz
pkaeding
quelle
4
Wenn ich dann ein SVN-Update für das Trunk-Verzeichnis herausgebe, werden dann alle anderen Ordner abgerufen oder nur die bereits abgerufenen aktualisiert?
Rob Walker
2
Ich bekomme Skipped 'prom/foo'nach svn update --set-depth infinity proj/foo:(
Sam
2
Oh, Sie müssen das übergeordnete Element (proj / foo) aktualisieren, bevor Sie tiefer aktualisieren können (proj / foo / boo).
Sam
4
Dies ist eine gute Antwort und sollte wirklich die richtig markierte sein. Danke pkaeding!
Jimbo
1
Möglicherweise müssen Sie einen Zwischenschritt mit verwenden svn update --set-depth immediates proj, damit proj / foo für die Aktualisierung erstellt wird.
Craig
6

Oder führen Sie eine nicht rekursive Prüfung von / trunk durch und führen Sie dann einfach eine manuelle Aktualisierung der 3 benötigten Verzeichnisse durch.

Zickdon
quelle
6

Ich habe ein Skript geschrieben, um komplexe, spärliche Kassen zu automatisieren.

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

Wenn Sie bereits über die vollständige lokale Kopie verfügen, können Sie unerwünschte Unterordner mithilfe des --set-depthBefehls entfernen .

svn update --set-depth=exclude www

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

Der set-depthBefehl unterstützt Multipile-Pfade.

Durch das Aktualisieren der lokalen Stammkopie wird die Tiefe des geänderten Ordners nicht geändert.

Sie können den Ordner mit dem Parameter --set-depthinfinity erneut verwenden, um das rekusive Auschecken des Ordners wiederherzustellen.

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

Art von. Wie Bobby sagt:

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

wird die Ordner erhalten, aber Sie werden separate Ordner aus einer Subversion-Perspektive erhalten. Sie müssen für jeden Unterordner separate Commits und Updates durchführen.

Ich glaube nicht, dass Sie einen Teilbaum auschecken und dann mit dem Teilbaum als eine Einheit arbeiten können.

Rob Walker
quelle
-10

Nicht besonders nützlich, nein. Sie können Teilbäume auschecken (wie in Bobby Jacks Vorschlag), aber dann verlieren Sie die Fähigkeit, sie atomar zu aktualisieren / festzuschreiben. Dazu müssen sie unter ihrem gemeinsamen Elternteil platziert werden. Sobald Sie das gemeinsame Elternteil auschecken, laden Sie alles unter diesem gemeinsamen Elternteil herunter. Nicht rekursiv ist keine gute Option, da Updates und Commits rekursiv sein sollen.

DrPizza
quelle
16
-1 für eine Antwort, die einfach falsch ist. Im wirklichen Leben gibt es viele Anwendungsfälle, in denen Sie nur eine kleine Teilmenge der Komponenten in einem großen Projekt bearbeiten und nicht das gesamte Projekt überprüfen möchten.
Peter
Natürlich können Sie mit diesen Teilbäumen unabhängig voneinander arbeiten, aber ich denke, DrPizza bedeutete in diesem Fall nicht atomare Commits / Updates. Und es kann unter bestimmten Umständen ein Problem sein.
Andry