Subversion으로 부분 체크 아웃을 할 수 있습니까?


답변:


78

Subversion 1.5에는 유용 ​​할 수있는 희소 체크 아웃이 도입되었습니다. 로부터 문서 :

... 스파 스 디렉토리 (또는 얕은 체크 아웃 ) ... 이전에 무시되었던 파일과 하위 디렉토리를 자유롭게 가져올 수있어 전체 재귀보다 얕게 작업 복사본 또는 작업 복사본의 일부를 쉽게 확인할 수 있습니다. 나중에.


259

실제로, 여기 내 게시물에 대한 의견 덕분에 희소 한 디렉토리 가 갈 길 처럼 보입니다 . 나는 다음과 같이해야한다고 생각합니다.

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

또는 내용없이 파일과 디렉토리 --depth immediatesempty체크 아웃하는 대신 trunk/proj. 이렇게하면 저장소에 어떤 디렉토리가 있는지 확인할 수 있습니다.


@zigdon의 답변에서 언급했듯이 비 재귀 체크 아웃을 수행 할 수도 있습니다. 비슷한 효과를 얻을 수있는 오래되고 덜 유연한 방법입니다.

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

4
그런 다음 트렁크 디렉토리에서 svn 업데이트를 실행하면 다른 모든 폴더가 풀 다운되거나 이미 검색된 폴더가 업데이트됩니까?
Rob Walker

2
내가 도착 Skipped 'prom/foo'svn update --set-depth infinity proj/foo:(

2
아, 더 깊이 업데이트하려면 (proj / foo / boo) 상위 (proj / foo)를 업데이트해야합니다.
sam

4
이것은 좋은 답변이며, 실제로 올바르게 표시된 답변이어야합니다. 감사합니다!
Jimbo

1
svn update --set-depth immediates projproj / foo를 업데이트 하기 위해 중간 단계를 사용해야 할 수도 있습니다 .
Craig

6

또는 / trunk의 비 재귀 체크 아웃을 수행 한 다음 필요한 3 개의 디렉토리에서 수동 업데이트를 수행하십시오.


6

복잡한 스파 스 체크 아웃을 자동화하는 스크립트를 작성했습니다.

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

전체 로컬 복사본이 이미 있으면 --set-depth명령 을 사용하여 원치 않는 하위 폴더를 제거 할 수 있습니다 .

svn update --set-depth=exclude www

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

set-depth명령은 다중 파일 경로를 지원합니다.

루트 로컬 복사본을 업데이트해도 수정 된 폴더의 깊이는 변경되지 않습니다.

폴더가 복구 적으로 체크 아웃되도록 복원하려면 --set-depth무한 매개 변수와 함께 다시 사용할 수 있습니다 .

svn update --set-depth=infinity www

-1

일종의. 바비의 말 :

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

폴더를 가져 오지만 하위 버전 관점에서 별도의 폴더를 가져옵니다. 각 하위 폴더에서 별도의 커밋 및 업데이트를 수행해야합니다.

부분 트리를 체크 아웃 한 다음 부분 트리를 단일 엔티티로 사용할 수 있다고 생각하지 않습니다.


-10

특별히 유용한 방법은 아닙니다. 하위 트리를 체크 아웃 할 수 있지만 (Bobby Jack의 제안에서와 같이) 원자 적으로 하위 트리를 업데이트 / 커밋하는 기능이 손실됩니다. 그렇게하려면 공통 부모 아래에 배치해야하며 공통 부모를 확인하자마자 해당 부모 아래에있는 모든 항목을 다운로드하게됩니다. 비 재귀는 업데이트 및 커밋을 재귀 적으로 원하기 때문에 좋은 옵션이 아닙니다.


16
-1은 틀린 답입니다. 실제 프로젝트에는 대규모 프로젝트에서 구성 요소의 작은 하위 집합에 대해서만 작업하고 전체 프로젝트를 확인하지 않으려는 사용 사례가 많이 있습니다.
피터

원인은이 하위 트리를 서로 독립적으로 사용할 수 있지만 DrPizza는이 경우 원자가 아닌 커밋 / 업데이트를 의미한다고 생각합니다. 특정 상황에서는 문제가 될 수 있습니다.
Andry
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.