aboutsummaryrefslogtreecommitdiffstats
path: root/src/svn.cpp
diff options
context:
space:
mode:
authorRaja R Harinath <harinath@hurrynot.org>2010-07-01 18:26:26 +0530
committerRaja R Harinath <harinath@hurrynot.org>2010-07-01 18:26:26 +0530
commit883fc2dfc9adbe42f490b6049b4a1db62b843b71 (patch)
tree25e2daa1dbd50ec6db678dd8bd40c602d752d263 /src/svn.cpp
parentc1ae3088b783fc62faf7ee05279b31b8a37b568e (diff)
downloadsvn2git-883fc2dfc9adbe42f490b6049b4a1db62b843b71.tar
svn2git-883fc2dfc9adbe42f490b6049b4a1db62b843b71.tar.gz
svn2git-883fc2dfc9adbe42f490b6049b4a1db62b843b71.tar.bz2
svn2git-883fc2dfc9adbe42f490b6049b4a1db62b843b71.tar.xz
svn2git-883fc2dfc9adbe42f490b6049b4a1db62b843b71.zip
Infer some copy sources as additional parents
We use a literal meaning of multiple commit parents to allow us to infer some partial repository copying as merges. This helps us 1) track history despite some directory reorganization 2) link subset commits to parents 3) infer some merges which were achieved by overwriting a subtree with contents from another branch This seems to work well enough even with cvs2svn monster commits. The heuristics have been tuned by gut feel to work reasonably well with mono's SVN repository. They can definitely be improved.
Diffstat (limited to 'src/svn.cpp')
-rw-r--r--src/svn.cpp108
1 files changed, 63 insertions, 45 deletions
diff --git a/src/svn.cpp b/src/svn.cpp
index a4bf4e6..afb037e 100644
--- a/src/svn.cpp
+++ b/src/svn.cpp
@@ -595,56 +595,61 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change_t *cha
// qDebug() << " " << qPrintable(current) << "rev" << revnum << "->"
// << qPrintable(repository) << qPrintable(branch) << qPrintable(path);
- if (path.isEmpty() && path_from != NULL) {
- QString previous = QString::fromUtf8(path_from) + '/';
+ QString previous;
+ QString prevsvnprefix, prevrepository, prevbranch, prevpath;
+
+ if (path_from != NULL) {
+ QString previous = QString::fromUtf8(path_from) + '/';
MatchRuleList::ConstIterator prevmatch =
findMatchRule(matchRules, rev_from, previous, NoIgnoreRule);
- if (prevmatch != matchRules.constEnd()) {
- QString prevsvnprefix, prevrepository, prevbranch, prevpath;
+ if (prevmatch != matchRules.constEnd())
splitPathName(*prevmatch, previous, &prevsvnprefix, &prevrepository,
&prevbranch, &prevpath);
+ else
+ path_from = NULL;
+ }
- if (!prevpath.isEmpty()) {
- qDebug() << qPrintable(current) << "is a partial branch of repository"
- << qPrintable(prevrepository) << "branch"
- << qPrintable(prevbranch) << "subdir"
- << qPrintable(prevpath);
- } else if (prevrepository != repository) {
- qWarning() << qPrintable(current) << "rev" << revnum
- << "is a cross-repository copy (from repository"
- << qPrintable(prevrepository) << "branch"
- << qPrintable(prevbranch) << "path"
- << qPrintable(prevpath) << "rev" << rev_from << ")";
- } else {
- if (prevbranch == branch) {
- // same branch and same repository
- qDebug() << qPrintable(current) << "rev" << revnum
- << "is an SVN rename from"
- << qPrintable(previous) << "rev" << rev_from;
- } else {
- // same repository but not same branch
- // this means this is a plain branch
- qDebug() << qPrintable(repository) << ": branch"
- << qPrintable(branch) << "is branching from"
- << qPrintable(prevbranch);
- }
- Repository *repo = repositories.value(repository, 0);
- if (!repo) {
- qCritical() << "Rule" << rule
- << "references unknown repository" << repository;
- return EXIT_FAILURE;
- }
-
- repo->createBranch(branch, revnum, prevbranch, rev_from);
- if (rule.annotate) {
- // create an annotated tag
- fetchRevProps();
- repo->createAnnotatedTag(branch, svnprefix, revnum, authorident,
- epoch, log);
- }
- return EXIT_SUCCESS;
- }
- }
+ if (path.isEmpty() && path_from != NULL) {
+ if (!prevpath.isEmpty()) {
+ qDebug() << qPrintable(current) << "is a partial branch of repository"
+ << qPrintable(prevrepository) << "branch"
+ << qPrintable(prevbranch) << "subdir"
+ << qPrintable(prevpath);
+ } else if (prevrepository != repository) {
+ qWarning() << qPrintable(current) << "rev" << revnum
+ << "is a cross-repository copy (from repository"
+ << qPrintable(prevrepository) << "branch"
+ << qPrintable(prevbranch) << "path"
+ << qPrintable(prevpath) << "rev" << rev_from << ")";
+ } else {
+ if (prevbranch == branch) {
+ // same branch and same repository
+ qDebug() << qPrintable(current) << "rev" << revnum
+ << "is an SVN rename from"
+ << qPrintable(previous) << "rev" << rev_from;
+ } else {
+ // same repository but not same branch
+ // this means this is a plain branch
+ qDebug() << qPrintable(repository) << ": branch"
+ << qPrintable(branch) << "is branching from"
+ << qPrintable(prevbranch);
+ }
+ Repository *repo = repositories.value(repository, 0);
+ if (!repo) {
+ qCritical() << "Rule" << rule
+ << "references unknown repository" << repository;
+ return EXIT_FAILURE;
+ }
+
+ repo->createBranch(branch, revnum, prevbranch, rev_from);
+ if (rule.annotate) {
+ // create an annotated tag
+ fetchRevProps();
+ repo->createAnnotatedTag(branch, svnprefix, revnum, authorident,
+ epoch, log);
+ }
+ return EXIT_SUCCESS;
+ }
}
Repository::Transaction *txn = transactions.value(repository + branch, 0);
@@ -663,6 +668,19 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change_t *cha
transactions.insert(repository + branch, txn);
}
+ //
+ // If this path was copied from elsewhere, use it to infer _some_
+ // merge points. However, if the copy was from earlier in the
+ // same branch, we ignore it, since it is unlikely to improve the
+ // quality of the history.
+ //
+ // This is totally a heuristic, but is fairly useful for tracking
+ // changes across directory re-organizations and wholesale branch
+ // imports.
+ //
+ if (path_from != NULL && prevrepository == repository && prevbranch != branch)
+ txn->noteCopyFromBranch (prevbranch, rev_from);
+
if (change->change_kind == svn_fs_path_change_replace && path_from == NULL)
txn->deleteFile(path);
if (change->change_kind == svn_fs_path_change_delete) {