private async Task FindBaselineBranchAsync(MigrationContext context, MigratedProject project, CancellationToken cancellationToken)
        {
            Logger.Info($"Looking for releases branch for '{project.SourcePath}'");

            //Look for the releases folder
            (string itemPath, Version version) = await context.SourceService.FindLatestVersionAsync(ItemPath.BuildPath(project.SourcePath, Settings.ReleaseBranch), cancellationToken).ConfigureAwait(false);

            //If there is a latest release then we'll use it as baseline otherwise download the baseline branch
            if (String.IsNullOrEmpty(itemPath))
            {
                Logger.Debug($"No releases found, looking for base branch from '{project.SourcePath}'");

                var baseline = await context.SourceService.FindItemAsync(ItemPath.BuildPath(project.SourcePath, Settings.BaselineBranch), false, cancellationToken).ConfigureAwait(false);

                if (baseline != null)
                {
                    itemPath = baseline.Path;
                }
                ;
            }
            ;

            if (!String.IsNullOrEmpty(itemPath))
            {
                project.BaselinePath = itemPath;
                project.Version      = version;
            }
            ;

            Logger.Info($"Found branch for '{project.SourcePath}' - baseline Path = {itemPath}, Version = {version}");
        }
        private async Task <MigratedProject> MigrateProjectAsync(MigrationContext context, ProjectSettings projectToMigrate, CancellationToken cancellationToken)
        {
            Logger.StartActivity($"Migrating project '{projectToMigrate.SourcePath}'");

            var migratedProject = new MigratedProject()
            {
                SourcePath    = projectToMigrate.SourcePath,
                LocalFullPath = FileSystem.BuildPath(context.OutputPath, projectToMigrate.DestinationPath),

                DestinationPath        = projectToMigrate.DestinationPath,
                DestinationProjectName = projectToMigrate.DestinationProject
            };

            migratedProject.StartProfiling();
            try
            {
                using (var logger = Logger.BeginScope("MigrateProject"))
                {
                    // Create the target repo
                    migratedProject.DestinationRepo = await CreateGitRepoAsync(context, migratedProject, cancellationToken).ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    if (projectToMigrate.HasBranches)
                    {
                        // Find the baseline branch for this project, if any
                        await FindBaselineBranchAsync(context, migratedProject, cancellationToken).ConfigureAwait(false);

                        if (!String.IsNullOrEmpty(migratedProject.BaselinePath))
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            // Download the baseline
                            await DownloadFolderAsync(context.SourceService, migratedProject.BaselinePath, migratedProject.LocalFullPath, cancellationToken).ConfigureAwait(false);

                            cancellationToken.ThrowIfCancellationRequested();

                            // Clean the folder
                            var fileCount = await CleanFolderAsync(migratedProject.LocalFullPath, cancellationToken).ConfigureAwait(false);

                            cancellationToken.ThrowIfCancellationRequested();

                            // It is possible that the baseline branch is actually empty in which case we'll
                            // get an error when trying to commit so skip this if there are no files
                            if (fileCount > 0)
                            {
                                // Commit the changes to the master branch
                                var msg = $"Committing baseline version from TFS - {migratedProject.BaselinePath}";
                                await CommitRepoAsync(migratedProject, context.GitCommand, msg, cancellationToken).ConfigureAwait(false);

                                cancellationToken.ThrowIfCancellationRequested();

                                // Create a release for this version so it can be found later if there is a release
                                if (migratedProject.Version != null)
                                {
                                    await CreateReleaseBranchAsync(migratedProject, context.GitCommand, cancellationToken).ConfigureAwait(false);

                                    //Switch back to master because we won't be doing anything else with this branch
                                    Logger.Debug($"Changing to branch '{Settings.GitMasterBranch}'");
                                    await context.GitCommand.CheckOutBranchAsync(migratedProject.LocalFullPath, Settings.GitMasterBranch, false, cancellationToken).ConfigureAwait(false);
                                }
                                ;
                            }
                            else
                            {
                                Logger.Warning($"No files in baseline '{migratedProject.BaselinePath}', skipping commit of master branch");
                            }

                            cancellationToken.ThrowIfCancellationRequested();
                        }
                        ;
                    }
                    ;

                    // Download the latest version of the code to master
                    {
                        migratedProject.DevelopmentPath = projectToMigrate.HasBranches ? ItemPath.BuildPath(migratedProject.SourcePath, Settings.DevelopmentBranch) : migratedProject.SourcePath;

                        // We need to be able to tell what stuff was deleted so wipe the directory structure and start over, except the .git folder
                        await FileSystem.ClearDirectoryAsync(migratedProject.LocalFullPath, new[] { ".git" }, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();

                        // Download the dev branch
                        await DownloadFolderAsync(context.SourceService, migratedProject.DevelopmentPath, migratedProject.LocalFullPath, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();

                        // Clean the folder
                        await CleanFolderAsync(migratedProject.LocalFullPath, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();

                        // Copy the template files over any existing files
                        await CopyTemplateAsync(migratedProject.LocalFullPath, Settings.TemplatePath, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();

                        // Update the metadata file, if any
                        if (!String.IsNullOrEmpty(Settings.MetadataFile))
                        {
                            var metadataFile = FileSystem.BuildPath(migratedProject.LocalFullPath, Settings.MetadataFile);
                            await UpdateMetadataFileAsync(metadataFile, migratedProject, cancellationToken).ConfigureAwait(false);

                            cancellationToken.ThrowIfCancellationRequested();
                        }
                        ;

                        // Commit the changes
                        var msg = $"Committing latest version from TFS - {migratedProject.DevelopmentPath}";
                        await CommitRepoAsync(migratedProject, context.GitCommand, msg, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();
                    };

                    //Clean up the structure if set
                    if (Settings.CleanAfterCommit)
                    {
                        await FileSystem.RemoveDirectoryAsync(migratedProject.LocalFullPath, cancellationToken).ConfigureAwait(false);

                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    ;
                };

                var totalTime = migratedProject.StopProfiling();
                Logger.StopActivity($"Migrated project '{projectToMigrate.SourcePath}' in {totalTime}");
            } catch (Exception e)
            {
                migratedProject.Error = e;
                Logger.Error(e);
            };

            return(migratedProject);
        }