public void ExportToGit(string repoPath)
{
workQueue.AddLast(delegate(object work)
{
var stopwatch = Stopwatch.StartNew();
logger.WriteSectionSeparator();
LogStatus(work, "Initializing Git repository");
// create repository directory if it does not exist
if (!Directory.Exists(repoPath))
{
Directory.CreateDirectory(repoPath);
}
var git = new GitWrapper(repoPath, logger);
git.CommitEncoding = commitEncoding;
while (!git.FindExecutable())
{
var button = MessageBox.Show("Git not found in PATH. " +
"If you need to modify your PATH variable, please " +
"restart the program for the changes to take effect.",
"Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
if (button == DialogResult.Cancel)
{
workQueue.Abort();
return;
}
}
if (!RetryCancel(delegate { git.Init(); }))
{
return;
}
if (commitEncoding.WebName != "utf-8")
{
AbortRetryIgnore(delegate
{
git.SetConfig("i18n.commitencoding", commitEncoding.WebName);
});
}
var pathMapper = new VssPathMapper();
// create mappings for root projects
foreach (var rootProject in revisionAnalyzer.RootProjects)
{
var rootPath = VssPathMapper.GetWorkingPath(repoPath, rootProject.Path);
pathMapper.SetProjectPath(rootProject.PhysicalName, rootPath, rootProject.Path);
}
// replay each changeset
var changesetId = 1;
var changesets = changesetBuilder.Changesets;
var commitCount = 0;
var tagCount = 0;
var replayStopwatch = new Stopwatch();
var labels = new LinkedList <Revision>();
tagsUsed.Clear();
foreach (var changeset in changesets)
{
var changesetDesc = string.Format(CultureInfo.InvariantCulture,
"changeset {0} from {1}", changesetId, changeset.DateTime);
// replay each revision in changeset
LogStatus(work, "Replaying " + changesetDesc);
labels.Clear();
replayStopwatch.Start();
bool needCommit;
try
{
needCommit = ReplayChangeset(pathMapper, changeset, git, labels);
}
finally
{
replayStopwatch.Stop();
}
if (workQueue.IsAborting)
{
return;
}
// commit changes
if (needCommit)
{
LogStatus(work, "Committing " + changesetDesc);
if (CommitChangeset(git, changeset))
{
++commitCount;
}
}
if (workQueue.IsAborting)
{
return;
}
// create tags for any labels in the changeset
if (labels.Count > 0)
{
foreach (Revision label in labels)
{
var labelName = ((VssLabelAction)label.Action).Label;
if (string.IsNullOrEmpty(labelName))
{
logger.WriteLine("NOTE: Ignoring empty label");
}
else if (commitCount == 0)
{
logger.WriteLine("NOTE: Ignoring label '{0}' before initial commit", labelName);
}
else
{
var tagName = GetTagFromLabel(labelName);
var tagMessage = "Creating tag " + tagName;
if (tagName != labelName)
{
tagMessage += " for label '" + labelName + "'";
}
LogStatus(work, tagMessage);
// annotated tags require (and are implied by) a tag message;
// tools like Mercurial's git converter only import annotated tags
var tagComment = label.Comment;
if (string.IsNullOrEmpty(tagComment) && forceAnnotatedTags)
{
// use the original VSS label as the tag message if none was provided
tagComment = labelName;
}
if (AbortRetryIgnore(
delegate
{
git.Tag(tagName, label.User, GetEmail(label.User),
tagComment, label.DateTime);
}))
{
++tagCount;
}
}
}
}
++changesetId;
}
stopwatch.Stop();
logger.WriteSectionSeparator();
logger.WriteLine("Git export complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks));
logger.WriteLine("Replay time: {0:HH:mm:ss}", new DateTime(replayStopwatch.ElapsedTicks));
logger.WriteLine("Git time: {0:HH:mm:ss}", new DateTime(git.ElapsedTime.Ticks));
logger.WriteLine("Git commits: {0}", commitCount);
logger.WriteLine("Git tags: {0}", tagCount);
});
}