Bisakah Anda melakukan checkout sebagian dengan Subversion?

155

Jika saya memiliki 20 direktori di bawah trunk / dengan banyak file di masing-masing dan hanya membutuhkan 3 dari direktori tersebut, apakah mungkin untuk melakukan checkout Subversion dengan hanya 3 direktori di bawah trunk?

Hanya baca
sumber

Jawaban:

78

Subversion 1.5 memperkenalkan pemeriksaan jarang yang mungkin bermanfaat bagi Anda. Dari dokumentasi :

... direktori jarang (atau checkout dangkal ) ... memungkinkan Anda untuk dengan mudah memeriksa copy pekerjaan — atau sebagian dari copy pekerjaan — lebih dangkal daripada rekursi penuh, dengan kebebasan untuk memasukkan file dan subdirektori yang sebelumnya diabaikan pada sebuah lain waktu

Richard Morgan
sumber
259

Memang, berkat komentar untuk posting saya di sini, sepertinya direktori jarang adalah cara untuk pergi. Saya percaya yang berikut ini harus melakukannya:

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

Atau, --depth immediatesalih-alih emptymemeriksa file dan direktori trunk/projtanpa isinya. Dengan begitu Anda bisa melihat direktori mana yang ada di repositori.


Seperti disebutkan dalam jawaban @ zigdon, Anda juga dapat melakukan checkout non-rekursif. Ini adalah cara yang lebih tua dan kurang fleksibel untuk mencapai efek yang serupa:

svn checkout --non-recursive http://svnserver/trunk/proj
svn update trunk/foo
svn update trunk/bar
svn update trunk/baz
pkaeding
sumber
4
Jika saya kemudian mengeluarkan pembaruan svn pada direktori trunk, apakah akan menarik semua folder lain, atau hanya memperbarui yang sudah diambil?
Rob Walker
2
Saya dapatkan Skipped 'prom/foo'setelah svn update --set-depth infinity proj/foo:(
sam
2
Oh, Anda harus memperbarui orang tua (proj / foo) sebelum Anda dapat memperbarui lebih dalam (proj / foo / boo).
sam
4
Ini adalah jawaban yang bagus dan harus benar-benar ditandai. Terima kasih pkaeding!
Jimbo
1
Anda mungkin perlu menggunakan langkah perantara dengan svn update --set-depth immediates projsehingga membuat proj / foo untuk memperbarui.
Craig
6

Atau lakukan checkout / trunk non-rekursif, kemudian lakukan saja pembaruan manual pada 3 direktori yang Anda butuhkan.

zigdon
sumber
6

Saya menulis sebuah skrip untuk mengotomatiskan checkout yang jarang dan rumit.

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

Jika Anda sudah memiliki salinan lokal lengkap, Anda dapat menghapus sub folder yang tidak diinginkan dengan menggunakan --set-depthperintah.

svn update --set-depth=exclude www

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

The set-depthperintah dukungan jalur multipile.

Memperbarui salinan lokal root tidak akan mengubah kedalaman folder yang dimodifikasi.

Untuk mengembalikan folder agar menjadi pemeriksaan berulang-ulang, Anda dapat menggunakannya --set-depthlagi dengan param infinity.

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

Semacam. Seperti yang dikatakan Bobby:

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

akan mendapatkan folder, tetapi Anda akan mendapatkan folder terpisah dari perspektif subversi. Anda harus memisahkan komit dan pembaruan pada setiap subfolder.

Saya tidak percaya Anda dapat checkout pohon parsial dan kemudian bekerja dengan pohon parsial sebagai satu kesatuan.

Rob Walker
sumber
-10

Tidak dengan cara yang bermanfaat, tidak. Anda dapat memeriksa subtree (seperti dalam saran Bobby Jack), tetapi kemudian Anda kehilangan kemampuan untuk memperbarui / melakukan mereka secara atom; untuk melakukan itu, mereka harus ditempatkan di bawah induknya, dan segera setelah Anda memeriksa induknya, Anda akan mengunduh semuanya di bawah induk itu. Non-rekursif bukan pilihan yang baik, karena Anda ingin pembaruan dan berkomitmen untuk rekursif.

DrPizza
sumber
16
-1 untuk jawaban yang salah. Ada banyak kasus penggunaan dalam kehidupan nyata di mana Anda ingin mengerjakan hanya sebagian kecil komponen dalam proyek besar, dan Anda tidak ingin memeriksa keseluruhan proyek.
Peter
Karena Anda dapat bekerja dengan subtrees ini secara independen satu sama lain, tetapi saya pikir DrPizza berarti komitmen / pembaruan non atom dalam kasus ini. Dan itu bisa menjadi masalah dalam kondisi tertentu.
Andry