From 1532745580099f607c3dd0c65d58bc57afb05f43 Mon Sep 17 00:00:00 2001 From: toby Date: Wed, 30 Apr 2008 02:53:04 +0000 Subject: [PATCH] * Path for renames during restore and renames during share (thanks to Bryan Aldrich for the patch) * Formatting cleanup and removal of commented code git-svn-id: http://vss2svn.googlecode.com/svn/trunk@340 2cfd5912-9055-84bd-9a12-e3c18a4b6e42 --- script/Vss2Svn/ActionHandler.pm | 144 ++++++++----------------------- script/Vss2Svn/Dumpfile.pm | 19 ++-- script/vss2svn.pl | 186 ++++++++++++++++++++++++---------------- 3 files changed, 163 insertions(+), 186 deletions(-) diff --git a/script/Vss2Svn/ActionHandler.pm b/script/Vss2Svn/ActionHandler.pm index ae44b88..02d2735 100644 --- a/script/Vss2Svn/ActionHandler.pm +++ b/script/Vss2Svn/ActionHandler.pm @@ -113,7 +113,7 @@ sub _add_handler { # number here. So we don't need to add the item anyway. if (!defined $version ) { $self->{errmsg} .= "Attempt to add entry '$row->{physname}' with " - . "unknown version number (probably destroyed)\n"; + . "unknown version number (probably destroyed) parent: $row->{parentphys} itemtype: $row->{itemtype}\n"; $gOrphanedInfo {$row->{physname} } = 1; return 0; @@ -263,6 +263,10 @@ sub _share_handler { my $parentpath = $self->_get_current_parent_path (); my $itempath = $parentpath . $row->{itemname}; + # a SHARE *can* rename a file if the parent is no longer present. + $row->{info} = $row->{itemname}; + $self->_rename_handler(); + # 'sourceinfo' contains the source path my $sourceinfo = $self->_get_valid_path ($physname, $row->{parentphys}, $version); @@ -272,20 +276,8 @@ sub _share_handler { # a share anymore; it's a new add. $self->{action} = 'ADD'; -# $self->{version} = $version; -# return $self->_add_handler(); } - # if this is a share from orphan, and not a share+pin action either, we can treat it as a move - elsif (!defined $row->{version} && # share+pin? - defined $physinfo->{orphaned} # orphaned? -# scalar @{$physinfo->{order}} == 1 # only one parent? - ) { - $physinfo->{parents}->{'_' . $row->{physname}}->{deleted} = 1; - undef $physinfo->{orphaned}; - $self->{action} = 'MOVE'; - } - # track the addition of the new parent $self->_add_parent ($physname, $row->{parentphys}); @@ -329,21 +321,6 @@ sub _branch_handler { return 0; } -# # First delete this parentphys from the old shared object; see -# # _delete_handler for details -# if ($oldphysinfo->{parentphys} eq $row->{parentphys}) { -# $oldphysinfo->{parentphys} = shift( @{ $oldphysinfo->{sharedphys} } ); -# } else { -# my $sharedphys = []; -# -# foreach my $oldparent (@{ $oldphysinfo->{sharedphys} }) { -# push @$sharedphys, $oldparent -# unless $oldparent eq $row->{parentphys}; -# } -# -# $oldphysinfo->{sharedphys} = $sharedphys; -# } - my $version = defined $row->{version} ? $row->{version} : $self->{version}; @@ -388,29 +365,13 @@ sub _branch_handler { return $result; - -# # Now create a new entry for this branched item -# $gPhysInfo{$physname} = -# { -# type => $row->{itemtype}, -# name => $row->{itemname}, -## parentphys => $row->{parentphys}, -## sharedphys => [], -# parents => {}, -# }; - -# $self->_add_parent ($physname, $row->{parentphys}); -# $self->{itempaths} = $self->_get_current_item_paths(1); - -# return 1; - } # End _branch_handler ############################################################################### # _move_handler ############################################################################### sub _move_handler { - my($self) = @_; + my($self, $oldName) = @_; my $row = $self->{row}; my $physname = $row->{physname}; @@ -439,11 +400,6 @@ sub _move_handler { } } - # '$sourceinfo' is the path for the old location (the move source); - my $sourceparent = $self->_get_parent_path ($row->{info}); - my $sourceinfo = $sourceparent . $row->{itemname}; - - # check the target path if (!defined ($row->{parentphys})) { # the target directory was destroyed, so there is no apropriate move @@ -452,6 +408,18 @@ sub _move_handler { $row->{parentphys} = '_' . $row->{physname}; } + # '$sourceinfo' is the path for the old location (the move source); + my $sourceparent = $self->_get_parent_path ($row->{info}); + my $sourceinfo; + if (defined $oldName) + { + $sourceinfo = $sourceparent . $oldName; + } + else + { + $sourceinfo = $sourceparent . $row->{itemname}; + } + # '$itempath' contains the move target path my $parentpath = $self->_get_current_parent_path (); my $itempath = $parentpath . $physinfo->{name}; # $row->{itemname}; @@ -494,9 +462,25 @@ sub _restore_handler { $self->{action} = 'MOVE'; $row->{actiontype} = 'MOVE'; - $row->{info} = $row->{parentphys}; - $row->{parentphys} = '_' . $row->{physname}; - return $self->_move_handler (); +# $row->{info} = $row->{parentphys}; +# $row->{parentphys} = '_' . $row->{physname}; + + $gPhysInfo{ $row->{physname} } = + { + type => $row->{itemtype}, + name => $row->{itemname}, + parents => {}, + first_version => 1, + last_version => 1, + orphaned => 1, + was_binary => $row->{is_binary}, + }; + + my $newName = $row->{info}; + + undef $row->{info}; + + return $self->_move_handler ($newName); } ############################################################################### @@ -523,25 +507,6 @@ sub _delete_handler { my $parentpath = $self->_get_current_parent_path (); my $itempaths = [$parentpath . $physinfo->{name}]; -# if ($physinfo->{parentphys} eq $row->{parentphys}) { -# # Deleting from the "main" parent; find a new one by shifting off the -# # first shared path, if any; if none exists this will leave a null -# # parent entry. We could probably just delete the whole node at this -# # point. -# -# $physinfo->{parentphys} = shift( @{ $physinfo->{sharedphys} } ); -# -# } else { -# my $sharedphys = []; -# -# foreach my $parent (@{ $physinfo->{sharedphys} }) { -# push @$sharedphys, $parent -# unless $parent eq $row->{parentphys}; -# } -# -# $physinfo->{sharedphys} = $sharedphys; -# } - # protect for delete/purge cycles: if the parentphys isn't in the shares # anymore, the file was already deleted from the parent and is now purged if (defined $physinfo->{parents}->{$row->{parentphys}}->{deleted}) { @@ -577,17 +542,6 @@ sub _recover_handler { return 0; } -# if (defined $physinfo->{parentphys}) { -# # Item still has other shares, so recover it by pushing this parent -# # onto its shared list -# -# push( @{ $physinfo->{sharedphys} }, $row->{parentphys} ); -# -# } else { -# # Recovering its only location; set the main parent back to this -# $physinfo->{parentphys} = $row->{parentphys}; -# } - # recover this item within the current parent my $parentinfo = $physinfo->{parents}->{$row->{parentphys}}; if (!defined $parentinfo->{deleted}) { @@ -895,15 +849,10 @@ sub _get_item_paths { $self->{physname_seen} .= "$physname, "; -# my @pathstoget = -# ($physinfo->{parentphys}, @{ $physinfo->{sharedphys} } ); my @pathstoget = @parents; my $paths; my $result; -# if (defined $physinfo->{parents}->{$row->{parentphys}}->{deleted}) { -# return 0; -# } PARENT: foreach my $parent (@pathstoget) { @@ -963,25 +912,6 @@ PARENT: $self->_track_item_path ($row->{physname}, $parent, $row->{version}, $result); -# my $versions = \@{$physinfo->{parents}->{$parent}->{versions}}; -# -# # in the case of pinning and sharing with pinning, the version number -# # denotes a version in the past. So if there is already an entry for -# # this version number skip this parent. -# if (exists $versions->[$row->{version}]) { -# next PARENT; -# } - -# # remember the last version, in which the file was modified -# $physinfo->{last_version} = $row->{version}; - -# $result = $self->_get_parent_path ($parent) . $physinfo->{name}; - -# if(!defined($result)) { -# next PARENT; -# } - -# $versions->[$row->{version}] = $result; } } } # End _track_item_paths diff --git a/script/Vss2Svn/Dumpfile.pm b/script/Vss2Svn/Dumpfile.pm index c2035d5..1536d7c 100644 --- a/script/Vss2Svn/Dumpfile.pm +++ b/script/Vss2Svn/Dumpfile.pm @@ -205,9 +205,13 @@ sub _add_handler { return $self->_commit_handler ($itempath, $nodes, $data, $expdir); } else { - $self->add_error("Attempt to re-add directory '$itempath' at " - . "revision $data->{revision_id}, skipping action: possibly " - . "missing delete"); + #creating a new VSS database can cause a "ADD" for a "/" item which will fail. + if (!($itempath eq "/")) { + $self->add_error("Attempt to re-add directory '$itempath' at " + . "revision $data->{revision_id}, skipping action: possibly " + . "missing delete"); + } + return 0; } } @@ -219,9 +223,12 @@ sub _add_handler { return 0; } elsif ($success == 0) { - $self->add_error("Parent path missing while trying to add " - . "item '$itempath' at revision $data->{revision_id}: adding missing " - . "parents"); + if (!($itempath =~ m/^\/orphaned\/_.*/)) + { + $self->add_error("Parent path missing while trying to add " + . "item '$itempath' at revision $data->{revision_id}: adding missing " + . "parents"); + } $self->_create_svn_path ($nodes, $itempath); } diff --git a/script/vss2svn.pl b/script/vss2svn.pl index d2c9bbd..2b758eb 100755 --- a/script/vss2svn.pl +++ b/script/vss2svn.pl @@ -68,7 +68,7 @@ sub RunConversion { MERGEPARENTDATA => {handler => \&MergeParentData, next => 'MERGEMOVEDATA'}, - # Merge data from move actions + # Merge data from move actions MERGEMOVEDATA => {handler => \&MergeMoveData, next => 'REMOVETMPCHECKIN'}, @@ -252,7 +252,7 @@ sub GetVssPhysInfo { print "physdir: \"$filesegment[0]\", physfolder: \"$filesegment[1]\" physname: \"$filesegment[2]\"\n" if $gCfg{debug}; if (!defined $filesegment[0] || !defined $filesegment[1] - || !defined $filesegment[2]) { + || !defined $filesegment[2]) { # physical file doesn't exist; it must have been destroyed later &ThrowWarning("Can't retrieve info from physical file " . "'$physname'; it was either destroyed or corrupted"); @@ -309,9 +309,9 @@ sub GetVssItemVersions { my($parentdata, $version, $vernum, $action, $name, $actionid, $actiontype, $tphysname, $itemname, $itemtype, $parent, $user, $timestamp, $comment, $is_binary, $info, $priority, $sortkey, $label, $cachename); - + my $last_timestamp = 0; - + VERSION: foreach $version (@{ $xml->{Version} }) { $action = $version->{Action}; @@ -341,7 +341,7 @@ VERSION: . "'$timestamp'"); } $last_timestamp = $timestamp; - + $itemtype = $info->{type}; $actiontype = $info->{action}; @@ -355,7 +355,7 @@ VERSION: $parentdata = 0; $priority = 5; $label = undef; - + if ($version->{Comment} && !ref($version->{Comment})) { $comment = $version->{Comment} || undef; } @@ -379,7 +379,7 @@ VERSION: . "'$tphysname;$version->{VersionNumber}'\n"; # if $gCfg{verbose}; $comment .= "\n"; } - + $comment .= $action->{LabelComment} || undef; } } @@ -438,7 +438,7 @@ VERSION: } } elsif ($actiontype eq 'BRANCH') { $info = $action->{Parent}; - } + } $vernum = ($parentdata)? undef : $version->{VersionNumber}; @@ -473,7 +473,7 @@ VERSION: if (defined $version->{Label} && !ref($version->{Label}) && $actiontype ne 'LABEL') { my ($labelComment); - + if ($version->{LabelComment} && !ref($version->{LabelComment})) { $labelComment = $version->{LabelComment}; } @@ -589,7 +589,7 @@ sub GetPathDepth { # Get the row(s) corresponding to the parent(s) of this row, and work out # the maximum depth - + my $sql = <<"EOSQL"; SELECT * @@ -656,7 +656,7 @@ sub GetChildRecs { $parentdata = 0 unless defined $parentdata; $parentdata = 1 if $parentdata != 0; - + my $sql = <<"EOSQL"; SELECT * @@ -722,6 +722,7 @@ sub MergeMoveData { # the MergeParentData function can not deal with this specific problem my($sth, $rows, $row); + $sth = $gCfg{dbh}->prepare('SELECT * FROM PhysicalAction ' . 'WHERE actiontype = "MOVE_FROM"'); $sth->execute(); @@ -738,20 +739,23 @@ sub MergeMoveData { my $source = undef; my $target = $row->{parentphys}; - if (scalar @$childrecs > 1) { - &ThrowWarning("Multiple child recs for parent MOVE rec " - . "'$row->{action_id}'"); - } + my $chosenChildRecord; + my $childRecord; + + foreach $childRecord (@$childrecs) { + if (!(defined $chosenChildRecord) + && $childRecord->{timestamp} == $row->{timestamp} + && !($childRecord->{parentphys} eq $row->{parentphys})) { - if (scalar @$childrecs >= 1) { - # only merge MOVE records that have the same timestamp - if ($row->{timestamp} == @$childrecs[0]->{timestamp}) { - $source = @$childrecs[0]->{parentphys}; - &DeleteChildRec(@$childrecs[0]->{action_id}); + $chosenChildRecord = $childRecord; } } - - my $sql = <<"EOSQL"; + + if (defined $chosenChildRecord) { + $source = $chosenChildRecord->{parentphys}; + &DeleteChildRec($chosenChildRecord->{action_id}); + + my $sql = <<"EOSQL"; UPDATE PhysicalAction SET @@ -761,10 +765,27 @@ SET WHERE action_id = ? EOSQL - my $update; - $update = $gCfg{dbh}->prepare($sql); - - $update->execute( $target, $source, $row->{action_id}); + my $update; + $update = $gCfg{dbh}->prepare($sql); + + $update->execute( $target, $source, $row->{action_id}); + } else { + #the record did not have a matching MOVE_TO. call it a RESTORE + print "Changing $row->{action_id} to a RESTORE\n"; + + my $sql = <<"EOSQL"; +UPDATE + PhysicalAction +SET + actiontype = 'RESTORE' +WHERE + action_id = ? +EOSQL + my $update; + $update = $gCfg{dbh}->prepare($sql); + + $update->execute( $row->{action_id}); + } } @@ -784,6 +805,25 @@ EOSQL $update->execute($row->{info}, $row->{parentphys}, $row->{action_id}); } + $sth = $gCfg{dbh}->prepare('SELECT * FROM PhysicalAction WHERE actiontype = "RESTORE"'); + $sth->execute(); + $rows = $sth->fetchall_arrayref( {} ); + + foreach $row (@$rows) { + #calculate last name of this file. Store it in $info + + my $sql = "SELECT * FROM PhysicalAction WHERE physname = ? AND timestamp < ? ORDER BY timestamp DESC"; + + $sth = $gCfg{dbh}->prepare($sql); + $sth->execute( $row->{physname}, $row->{timestamp} ); + + my $myOlderRecords = $sth->fetchall_arrayref( {} ); + + if (scalar @$myOlderRecords > 0) { + my $update = $gCfg{dbh}->prepare('UPDATE PhysicalAction SET info = ? WHERE action_id = ?'); + $update->execute(@$myOlderRecords[0]->{itemname}, $row->{action_id}); + } + } 1; @@ -806,21 +846,21 @@ sub RemoveTemporaryCheckIns { foreach $row (@$rows) { my $physname = $row->{physname}; - + my $sql = 'SELECT * FROM PhysicalAction WHERE physname = ?'; my $update = $gCfg{dbh}->prepare($sql); - + $update->execute( $physname ); - # need to pull in all recs at once, since we'll be updating/deleting data - my $recs = $update->fetchall_arrayref( {} ); - - foreach my $rec (@$recs) { - print "Remove action_id $rec->{action_id}, $rec->{physname}, $rec->{actiontype}, $rec->{itemname}\n"; - print " $rec->{comment}\n" if defined ($rec->{comment}); - &DeleteChildRec($rec->{action_id}); + # need to pull in all recs at once, since we'll be updating/deleting data + my $recs = $update->fetchall_arrayref( {} ); + + foreach my $rec (@$recs) { + print "Remove action_id $rec->{action_id}, $rec->{physname}, $rec->{actiontype}, $rec->{itemname}\n"; + print " $rec->{comment}\n" if defined ($rec->{comment}); + &DeleteChildRec($rec->{action_id}); } - } + } 1; } @@ -834,26 +874,26 @@ sub MergeUnpinPinData { . 'itemtype ASC, priority ASC, parentdata ASC, sortkey ASC, action_id ASC'; $sth = $gCfg{dbh}->prepare($sql); $sth->execute(); - + # need to pull in all recs at once, since we'll be updating/deleting data $rows = $sth->fetchall_arrayref( {} ); - + return if ($rows == -1); return if (@$rows < 2); - + my @delchild = (); - + for $r (0 .. @$rows-2) { $row = $rows->[$r]; - + if ($row->{actiontype} eq 'PIN' && !defined $row->{version}) # UNPIN - { + { # Search for a matching pin action my $u; for ($u = $r+1; $u <= @$rows-2; $u++) { $next_row = $rows->[$u]; - if ( $next_row->{actiontype} eq 'PIN' + if ( $next_row->{actiontype} eq 'PIN' && defined $next_row->{version} # PIN && $row->{physname} eq $next_row->{physname} && $row->{parentphys} eq $next_row->{parentphys} @@ -862,7 +902,7 @@ sub MergeUnpinPinData { ) { print "found UNPIN/PIN combination for $row->{parentphys}/$row->{physname}" . "($row->{itemname}) @ ID $row->{action_id}\n" if $gCfg{verbose}; - + # if we have a unpinFromVersion number copy this one to the PIN handler if (defined $row->{info}) { @@ -870,7 +910,7 @@ sub MergeUnpinPinData { my $sth2 = $gCfg{dbh}->prepare($sql2); $sth2->execute($row->{info}, $next_row->{action_id}); } - + push (@delchild, $row->{action_id}); } @@ -879,14 +919,14 @@ sub MergeUnpinPinData { } } } - + my $id; foreach $id (@delchild) { &DeleteChildRec($id); } - + 1; - + } # End MergeUnpinPinData ############################################################################### @@ -897,10 +937,10 @@ sub BuildComments { my $sql = 'SELECT * FROM PhysicalAction WHERE actiontype="PIN" AND itemtype=2 ORDER BY physname ASC'; $sth = $gCfg{dbh}->prepare($sql); $sth->execute(); - + # need to pull in all recs at once, since we'll be updating/deleting data $rows = $sth->fetchall_arrayref( {} ); - + foreach $row (@$rows) { # technically we have the following situations: @@ -911,7 +951,7 @@ sub BuildComments { # UNPIN/PIN with known UNPIN version: we merge from UNPIN version to PIN version # UNPIN/PIN with unknown UNPIN version: we are lost in this case and we # can not distinguish this case from the PIN only case. - + my $sql2; my $prefix; @@ -927,7 +967,7 @@ sub BuildComments { . ' ORDER BY version DESC'; $prefix = "reverted changes for: \n"; } - + # UNPIN only if ( !defined $row->{version} # no PIN version number && defined $row->{info}) { # UNPIN version number @@ -940,7 +980,7 @@ sub BuildComments { . ' ORDER BY version ASC'; } - # UNPIN/PIN + # UNPIN/PIN if ( defined $row->{version} # PIN version number && defined $row->{info}) { # UNPIN version number $sql2 = 'SELECT * FROM PhysicalAction' @@ -950,7 +990,7 @@ sub BuildComments { . ' AND version>' . $row->{info} . ' AND version<=' . $row->{version} . ' ORDER BY version '; - + if ($row->{info} > $row->{version}) { $sql2 .= "DESC"; $prefix = "reverted changes for: \n"; @@ -962,24 +1002,24 @@ sub BuildComments { } next if !defined $sql2; - + my $sth2 = $gCfg{dbh}->prepare($sql2); $sth2->execute(); my $comments = $sth2->fetchall_arrayref( {} ); - my $comment; + my $comment; print "merging comments for $row->{physname}" if $gCfg{verbose}; print " from $row->{info}" if ($gCfg{verbose} && defined $row->{info}); print " to $row->{version}" if ($gCfg{verbose} && defined $row->{version}); print "\n" if $gCfg{verbose}; - + foreach my $c(@$comments) { print " $c->{version}: $c->{comment}\n" if $gCfg{verbose}; $comment .= $c->{comment} . "\n"; $comment =~ s/^\n+//; $comment =~ s/\n+$//; } - + if (defined $comment && !defined $row->{comment}) { $comment = $prefix . $comment if defined $prefix; $comment =~ s/"/""/g; @@ -989,7 +1029,7 @@ sub BuildComments { } } 1; - + } # End BuildComments ############################################################################### @@ -1094,12 +1134,12 @@ ROW: # we need to check for the next rev number, after all pathes that can # prematurally call the next row. Otherwise, we get an empty revision. $svnrevs->check($row); - + # May contain add'l info for the action depending on type: # RENAME: the new name (without path) # SHARE: the source path which was shared # MOVE: the old path - # PIN: the path of the version that was pinned + # PIN: the path of the version that was pinned # LABEL: the name of the label $row->{info} = $handler->{info}; @@ -1107,14 +1147,14 @@ ROW: if (defined $handler->{version}) { $row->{version} = $handler->{version}; } - + $allitempaths = join("\t", @$itempaths); $row->{itempaths} = $allitempaths; $vsscache->add(@$row{ qw(parentphys physname version actiontype itempaths itemtype is_binary info) }); $joincache->add( $svnrevs->{revnum}, $vsscache->{pkey} ); - + if (defined $row->{label}) { $labelcache->add(@$row{ qw(physname version label itempaths) }); } @@ -1125,7 +1165,7 @@ ROW: $svnrevs->commit(); $joincache->commit(); $labelcache->commit(); - + } # End BuildVssActionHistory ############################################################################### @@ -1198,11 +1238,11 @@ ACTION: && ( $action->{action} eq 'ADD' || $action->{action} eq 'COMMIT')) { &ThrowWarning("'$physname': no version specified for retrieval"); - + # fall through and try with version 1. $version = 1; } - + if ($itemtype == 2 && defined $version) { $exported{$physname} = &ExportVssPhysFile($physname, $version); } else { @@ -1494,9 +1534,9 @@ sub GetSsVersion { my $out = `\"$gCfg{ssphys}\" --version 2>&1`; # Build numbers look like: # a.) ssphys 0.20.0, Build 123 - # b.) ssphys 0.20.0, Build 123:150 + # b.) ssphys 0.20.0, Build 123:150 # c.) ssphys 0.20.0, Build 123:150 (locally modified) - $out =~ m/^ssphys (.*?), Build (.*?)[ \n]/m; + $out =~ m/^ssphys (.*?), Build (.*?)[ \n]/m; # turn it into # a.) 0.20.0.123 @@ -1700,7 +1740,7 @@ sub SetupActionTypes { DestroyedFile => {type => 2, action => 'DELETE'}, RecoveredFile => {type => 2, action => 'RECOVER'}, ArchiveVersionsofFile => {type => 2, action => 'ADD'}, - ArchiveVersionsofProject => {type => 1, action => 'ADD'}, + ArchiveVersionsofProject => {type => 1, action => 'ADD'}, ArchiveFile => {type => 2, action => 'DELETE'}, RestoredFile => {type => 2, action => 'RESTORE'}, SharedFile => {type => 2, action => 'SHARE'}, @@ -1933,7 +1973,7 @@ FIELD: ############################################################################### sub Initialize { $| = 1; - + GetOptions(\%gCfg,'vssdir=s','tempdir=s','dumpfile=s','resume','verbose', 'debug','timing+','task=s','revtimerange=i','ssphys=s', 'encoding=s','trunkdir=s','auto_props=s', 'label_mapper=s', 'md5'); @@ -1987,7 +2027,7 @@ sub Initialize { $gCfg{labeldir} = '/labels'; $gCfg{errortasks} = []; - + { no warnings 'once'; $gCfg{usingExe} = (defined($PerlApp::TOOL)); @@ -2033,7 +2073,7 @@ sub ConfigureXmlParser { # Prevent the ParserDetails.ini error message when running from .exe XML::SAX->load_parsers($INC[1]); } - + $gCfg{xmlParser} = 'XML::SAX::Expat'; $XML::SAX::ParserPackage = $gCfg{xmlParser}; @@ -2106,7 +2146,7 @@ OPTIONAL PARAMETERS: --resume : Resume a failed or aborted previous run --task : specify the task to resume; task is one of the following INIT, LOADVSSNAMES, FINDDBFILES, GETPHYSHIST, - MERGEPARENTDATA, MERGEMOVEDATA, REMOVETMPCHECKIN, + MERGEPARENTDATA, MERGEMOVEDATA, REMOVETMPCHECKIN, MERGEUNPINPIN, BUILDACTIONHIST, IMPORTSVN --verbose : Print more info about the items being processed -- 2.11.4.GIT