The other day I converted a Subversion repository to Fossil via the script presented at http://www.fossil-scm.org/index.html/wiki?name=Cookbook#SVN . It mostly worked, but the imported commits were not on the trunk branch. (By the way, said Subversion repository did not utilize branching.)

I corrected that by adding propagating tags branch=trunk and sym-trunk. However, at first I mistakenly put the tags somewhere in the middle of the timeline, but I remedied this by putting them at the first non-trunk commit, i.e. the first imported commit.

A day or two later, while dangerously bored, I experimented with shunning, and I removed the erroneous tag edits in the middle of the timeline. I'm not 100% sure how, and I haven't succeeded in completely reproducing the damage with a test repository, but this somehow fractured the timeline with several commit manifests having P cards naming nonexistent predecessors. Very bad. Plus this broke the edit link in the web UI for the affected commits.

I couldn't fix the repository in place without database editing beyond my comfort level (zero), plus it's (currently...) impossible to generate manifests having a predetermined SHA1 sum. It would have been okay to let all the checksums change after the point of my edit, but still it seemed like too much work.

I exported and reimported the repository using [fossil export] and [fossil import], but the tree remained fractured. I tried editing the exported file before reimporting it, but I still couldn't work out how to make it do what I wanted.

My solution was to transfer the contents of each commit to a new repository. Since the repository has fewer than 150 commits; no branches; no special tags, users, or configuration; no tickets, wiki pages, or events; nothing special at all; and no requirement to preserve the checksums, this was acceptable. For this repository, the transfer process takes about four minutes on my computer, almost all of it spent inside [fossil commit], presumably doing checksums.

The strange thing I do is open two repositories simultaneously within a single directory, shuffling multiple copies of .fslckout. Then [fossil update] performs the "edits" that are committed with [fossil delete], [fossil add], and [fossil commit], and I use [fossil changes] to see what needs to be deleted.

Since someone (me?) might find this script useful in the future, perhaps as the foundation for a more comprehensive database regeneration procedure, or a for stress test, I'm pasting it below:

#!/usr/bin/env tclsh
set repo1 CORRUPT.fossil
set repo2 REBUILT.fossil
proc fossil {args} {
    puts [concat fossil $args]
    exec fossil {*}$args
}
set pwd [pwd]
file mkdir tmp
cd tmp
fossil open [file join $pwd $repo1]
foreach line [split [fossil timeline -t ci -n 0 -W 0] \n] {
    if {![regexp {^=== (\d{4}-\d\d-\d\d) ===$} $line _ date]
     && [regexp {(?x)^(\d\d:\d\d:\d\d)\ \[([[:xdigit:]]+)\]
                 \ (?:\*CURRENT\*\ )?(.*)$}\
                $line _ time version comment]} {
        lappend history [list "$date $time" $version $comment]
    }
}
set date [clock format [clock add [clock scan $date] -1 day]\
        -format %Y-%m-%d]
fossil new --date-override "$date 00:00:00" [file join $pwd $repo2]
file rename .fslckout [file join $pwd repo1.fslckout]
fossil open [file join $pwd $repo2]
file rename .fslckout [file join $pwd repo2.fslckout]
foreach checkin [lreverse $history] {
    lassign $checkin timestamp version comment
    file rename [file join $pwd repo1.fslckout] .fslckout
    fossil update $version
    file rename .fslckout [file join $pwd repo1.fslckout]
    file rename [file join $pwd repo2.fslckout] .fslckout
    foreach change [split [fossil changes] \n] {
        if {[regexp {^MISSING +(\S.*)$} $change _ name]} {
            fossil delete $name
        }
    }
    fossil add .
    fossil commit --allow-empty --no-warnings\
            --date-override $timestamp --comment $comment
    file rename .fslckout [file join $pwd repo2.fslckout]
}
file rename [file join $pwd repo1.fslckout] .fslckout
fossil close
file rename [file join $pwd repo2.fslckout] .fslckout
fossil close
cd $pwd
file delete -force tmp
# vim: set sts=4 sw=4 tw=80 et ft=tcl:

--
Andy Goth | <andrew.m.goth/at/gmail/dot/com>
_______________________________________________
fossil-users mailing list
[email protected]
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users

Reply via email to