basin
basin

Reputation: 4190

Can I create a shallow repository copy with svnsync?

There's a repo online that has 13k commits, but I'm only interested in last 1000 of them. Is it possible to copy them with svnsync?

I want to be able to checkout within the last 1000 commits from this local repository, and it should be faster than from the server

Revision numbers must be preserved.
svnsync must be able to sync the future revisions normally into the local repository.

Upvotes: 0

Views: 350

Answers (2)

basin
basin

Reputation: 4190

In the following example I save last 45 commits of a repo. The helper python script is below.

# svnsync 1.6.11
# rhel 6 x86_64

# params
svn_baserepourl="http://svn.igniterealtime.org/svn/repos"
svn_subdir="spark/trunk"
reponame=spark
skipuntil=13774


# well-known svnsync preparation
repopath=`pwd`/$reponame.svn
svnadmin create "$repopath"

echo '#!/bin/sh' >"$repopath"/hooks/pre-revprop-change
chmod +x "$repopath"/hooks/pre-revprop-change

svnsync init file://"$repopath" "$svn_baserepourl/$svn_subdir"

expectedfmt="4
layout sharded 1000"

if [ x"$expectedfmt" != x"$(cat "$repopath/db/format")" ]; then
    echo unknown db format
fi

# create database folder structure
( cd "$repopath/db" && echo $(for (( i=0; i<=$((skipuntil / 1000)) ; i++ )) ; do mkdir -p revprops/$i revs/$i; done ) )

# don't create last skipped revision
skipuntil=$((skipuntil - 1))

# create dummy revision files
( cd "$repopath/db" && for (( i=0; i<=$skipuntil; i++ )) ; do echo revprops/$((i/1000))/$i; echo revs/$((i/1000))/$i; done | xargs touch )

# update revision counter
echo $skipuntil >"$repopath/db/current"

# we need a valid revision file
cp "$repopath/db/revs/0/0" "$repopath/db/revs/$((skipuntil/1000))/$skipuntil"

# last skipped revision number
skipuntil=$((skipuntil + 1))

if false; then
    # TODO: if svnrdump available
    # mkdir in local repo
    # svnrdump last skipped revision and subdir
    # svnadmin load --parent-dir subdir
    :
else
    # checkout last skipped revision
    rm -rf temptree
    svn co -r $skipuntil "$svn_baserepourl/$svn_subdir" "temptree/$svn_subdir"
    cd temptree
    pushd "$svn_subdir"

    # save properties
    svn proplist --xml -v -R  | ~/svnprops.py >/tmp/propset.sh

    # remove .svn folders
    find . -name .svn -print0 | xargs -0 rm -rf

    popd

    # checkout our copy
    svn co "file://$repopath" .

    # add the files
    svn add --no-ignore --force .

    # delete automatic props
    for p in $(svn proplist -q -R | sort -u); do svn propdel -q -R $p; done

    # restore original props
    pushd "$svn_subdir"
    sh /tmp/propset.sh
    popd

    # commit the last skipped revision
    svn commit -m"shallow root"

    cd ..
    rm -rf temptree
fi

# update svnsync counters
svn propset --revprop -r 0 svn:sync-last-merged-rev $skipuntil  "file://$repopath"
svn propset --revprop -r 0 svn:sync-currently-copying $((skipuntil+1))  "file://$repopath"

# sync!
svnsync sync "file://$repopath"

This is some old svnprops.py to copy svn properties between repos:

#!/usr/bin/env python

import sys
import xml.sax
import xml.sax.handler

"""
<?xml version="1.0"?>
<properties>
<target
   path="file:///.snapshots/persist/builds/cyg-apt/cyg-apt.svn/trunk">
<property
   name="svn:ignore">build
</property>
</target>
</properties>
"""

class Subhandler:
  def __init__(self, mainHandler, parenthandler):
    self.mainHandler = mainHandler
    self.parenthandler = parenthandler
    self.subhandler = None
    self.lvl = 0
  def startElement(self, name, attributes):
    self.lvl = self.lvl + 1
  def characters(self, data):
    pass
  def endElement(self, name):
    self.lvl = self.lvl - 1

class Subhandler_properties(Subhandler):
  def startElement(self, name, attributes):
    pass
  def characters(self, data):
    pass
  def endElement(self, name):
    pass

class P1ropertiesDocHandler(xml.sax.handler.ContentHandler):
  def __init__(self):
    self.subhandler = None

  def startElement(self, name, attributes):
    if subhandler != None:
      subhandler.startElement(name, attributes)
    elif name == "properties":
      Subhandler_properties(self)

  def endElement(self, name):
    if subhandler != None:
      subhandler.endElement(name)

  def characters(self, data):
    if subhandler != None:
      subhandler.characters(data)


class PropertiesDocHandler(xml.sax.handler.ContentHandler):
  def __init__(self):
    self.target = None
    self.property = None

  def startElement(self, name, attributes):
    if name == "target":
      self.target = attributes["path"]
    elif name == "property":
      self.property = attributes["name"]
      self.propval = ""

  def endElement(self, name):
    if name == "target":
      self.target = None
    elif name == "property":
      print("svn ps \"" + self.property.replace("\"","\\\"") + "\" \"" + self.propval.replace("\"","\\\"") + "\" \"" + self.target.replace("\"","\\\"") + "\"")
      self.property = None
      self.propval = None

  def characters(self, data):
    if self.property != None:
      self.propval += data

parser = xml.sax.make_parser()
handler = PropertiesDocHandler()
parser.setContentHandler(handler)
#print("aa\"ass".replace("\"","\\\""))
parser.parse(sys.stdin)

Upvotes: 1

bahrep
bahrep

Reputation: 30662

Copy these last 1000 revisions where? svnsync tool is used for repository replication, not 'copying' revisions. If you want to get last 1000 revisions remotely, use svnrdump tool where you can specify revision range.

Upvotes: 1

Related Questions