/// <summary>
        /// Splits the specified repository by creating a new repository containing only specified directories.
        /// </summary>
        /// <param name="repository">Directory path for the repository to split.</param>
        public void Split(string repository)
        {
            #region Pre-Verifications
            // TODO: Consider moving these into directory helper
            // verify repository directory exists
            if (!Directory.Exists(repository))
            {
                throw new DirectoryNotFoundException(repository);
            }

            // verify we have a name for the new repository
            if (string.IsNullOrWhiteSpace(SplitRepositoryName))
            {
                throw new Exception("The new repository name is invalid.");
            }

            // verify we know which directories to split into the new repository
            if (DirectoriesToRetain == null || DirectoriesToRetain.Count() == 0)
            {
                throw new Exception("No directories will be included in the new repository.");
            }

            string parentDirectory = Directory.GetParent(repository).FullName;
            string newRepository   = string.Format("{0}\\{1}", parentDirectory, SplitRepositoryName);

            // verify new repository directory does not already exist
            if (Directory.Exists(newRepository))
            {
                throw new Exception("The new repository directory already exists.");
            }
            #endregion Pre-Verifications

            // clone existing repository into to-be new repository
            Git.WorkingDirectory = parentDirectory;
            Git.Execute(string.Format("clone {0} {1}", repository, newRepository));

            // protect existing repository from changes
            Git.WorkingDirectory = newRepository;
            Git.Execute("remote rm origin");

            // identify directories to remove
            var directoriesToRemove = GetDirectoriesToRemove(newRepository);

            // remove all directories except for the the directories to include
            // TODO: Consider offering alternative filter-branch options (e.g. besides index-filter)
            Git.Execute(string.Format("filter-branch --index-filter \"git rm -r --cached --ignore-unmatch {0}\" --prune-empty -f -- --all", directoriesToRemove.Implode(" ")));
            Git.Execute("for-each-ref --format=\" % (refname)\" refs/original/ | xargs -n 1 git update-ref -d");

            // add each removed subdirectory into .gitignore
            // TODO: Ensure each directory is on its own line in .gitignore
            File.AppendAllLines(string.Format("{0}\\.gitignore", newRepository), directoriesToRemove.Select(sdr => DirectoryHelper.AppendDirectorySeparatorChar(sdr, true)));

            // commit removal and invoke git garbage collection
            // TODO: Support custom commit message
            Git.Execute("commit -a -m \"Removed unnecessary directories from git history and added them to .gitignore\"");
            Git.Execute("gc");

            // TODO: Support removal of directories that were split into new repository from original repository
        }
        /// <summary>
        /// Gets the directories, including subdirectories if IncludeSubdirectories is true, to remove from the new repository.
        /// </summary>
        /// <param name="newRepository">The path to the new repository.</param>
        /// <returns></returns>
        public IEnumerable <string> GetDirectoriesToRemove(string newRepository)
        {
            // get all directories for removal, and exclude git directories, as well as directories (and their subdirectories) to retain
            var directories = new List <string>(DirectoryHelper.GetDirectories(newRepository, "*", true ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly));

            directories.RemoveAll(d => d.StartsWith(".git"));   // always retain git directories
            directories.RemoveAll(d => DirectoriesToRetain.Any(dtr => d == dtr || d.StartsWith(dtr + Path.AltDirectorySeparatorChar)));

            // ensure parent directories for directories to retain are also retained
            // TODO: Refactor this into a directory helper
            foreach (var directory in DirectoriesToRetain)
            {
                string path;
                int    index = directory.LastIndexOf(Path.AltDirectorySeparatorChar);
                while (index > 0)
                {
                    path = directory.Substring(0, index);
                    if (directories.Contains(path))
                    {
                        directories.Remove(path);
                    }
                    index = path.LastIndexOf(Path.AltDirectorySeparatorChar);
                }
            }

            // for all directories to remove, their subdirectories will automatically be removed,
            // so no need to duplicate the effort by including them in the filter-branch match
            // TODO: Refactor this into directory helper and for better performance
            bool          keepGoing       = true;
            List <string> alreadyScanned  = new List <string>();
            var           directoriesCopy = directories.ToList();

            while (keepGoing)
            {
                keepGoing = false;
                foreach (var dc in directoriesCopy)
                {
                    if (!DirectoriesToRetain.Any(dtr => dtr.StartsWith(dc)))
                    {
                        directories.RemoveAll(d => d.StartsWith(dc + Path.AltDirectorySeparatorChar));
                        alreadyScanned.Add(dc);
                        keepGoing = true;
                        break;
                    }
                }

                if (keepGoing)
                {
                    directoriesCopy = directories.ToList();
                    directoriesCopy.RemoveAll(d => alreadyScanned.Contains(d));
                }
            }

            return(directories);
        }