public void UpdateItems(IEnumerable<SyncAction> syncActions)
        {
            syncActions = syncActions.ToList();

            if (!syncActions.Any())
            {
                return;
            }

            // make sure all to be updated actions exist (no need to check the state, this property might have changed)
            AssertSyncActionsExist(syncActions, false);
            
            using (var workingDir = new TemporaryWorkingDirectory(GitGroup.Repository.Info.Path, BranchName.ToString()))
            {
                var root = new Directory(null, "root");

                foreach (var syncAction in syncActions)
                {
                    PathValidator.EnsureIsRootedPath(syncAction.Path);

                    // remove existing files for this sync action
                    var filesToDelete = Enum.GetValues(typeof (SyncActionState)).Cast<SyncActionState>()
                        .Where(state => state != syncAction.State)
                        .Select(state => GetRelativeSyncActionDirectoryPath(state, syncAction.Path))
                        .Select(relativeDirectoryPath => Path.Combine(relativeDirectoryPath, SyncActionFile.GetFileName(syncAction)))
                        .Select(relativePath => Path.Combine(workingDir.Location, relativePath))
                        .Where(System.IO.File.Exists).ToList();

                    foreach (var file in filesToDelete)
                    {
                        System.IO.File.Delete(file);
                    }

                    // add a new file
                    var directory = DirectoryHelper.GetOrAddDirectory(root, GetRelativeSyncActionDirectoryPath(syncAction));
                    directory.Add(d => new SyncActionFile(d, syncAction));
                }

                var localItemCreator = new LocalItemCreator();
                localItemCreator.CreateDirectoryInPlace(root, workingDir.Location);

                workingDir.Commit($"{nameof(GitSyncActionService)}: Updated {syncActions.Count()} items");
                workingDir.Push();
            }
        }
        public static GitBasedMultiFileSystemSnapshot Create(Repository repository, BranchName branchName, IHistoryService historyService)
        {
            var directoryCreator = new LocalItemCreator();            

            var branch = repository.GetBranch(branchName);

            string commitId;
            using (var workingRepository = new TemporaryWorkingDirectory(repository.Info.Path, branch.FriendlyName))
            {

                var snapshotDirectory = new Directory(null, s_SnapshotDirectoryName);
                foreach (var fileSystemHistory in historyService.Items)
                {
                    var fileName = fileSystemHistory.Name + s_FileNameSuffix;
                    var content = fileSystemHistory.LatestFileSystemSnapshot?.Id ?? "";
                    snapshotDirectory.Add(d => new TextFile(d, fileName, content));
                }
                
                var snapshotDirectoryPath = Path.Combine(workingRepository.Location, s_SnapshotDirectoryName);
                directoryCreator.CreateDirectoryInPlace(snapshotDirectory, snapshotDirectoryPath, true);

                if (workingRepository.HasChanges)
                {
                    try
                    {
                        commitId = workingRepository.Commit("Created multi-filesystem snapshot");
                        workingRepository.Push();
                    }
                    catch (EmptyCommitException)
                    {
                        // no changes after all (HasChanges does not seem to be a 100% accurate)
                        commitId = repository.GetBranch(branchName).Tip.Sha;
                    }

                }
                else
                {
                    commitId = repository.GetBranch(branchName).Tip.Sha;
                }
            }

            var commit = repository.Lookup<Commit>(commitId);
            return IsSnapshot(commit) ? new GitBasedMultiFileSystemSnapshot(commit, historyService) : null;
        }
        public void AddItems(IEnumerable<SyncAction> syncActions)
        {
            syncActions = syncActions.ToArray();

            if (!syncActions.Any())
            {
                return;
            }

            // make sure, the action does not already exist
            foreach (var action in syncActions)
            {
                var exisitingActions = this[action.State, action.Path].Where(a => a.Id == action.Id);
                if (exisitingActions.Any())
                {
                    throw new DuplicateSyncActionException($"A sync action with id {action.Id} already exists");
                }
            }

            // create the branch if it does not already exist
            EnsureBranchExists();

            // create a file system tree for the actions
            var root = new Directory(null, "root");
            foreach (var syncAction in syncActions)
            {
                PathValidator.EnsureIsRootedPath(syncAction.Path);

                var directory = DirectoryHelper.GetOrAddDirectory(root, GetRelativeSyncActionDirectoryPath(syncAction));
                directory.Add(d => new SyncActionFile(d, syncAction));
            }


            // store the actions
            using (var workingDir = new TemporaryWorkingDirectory(GitGroup.Repository.Info.Path, BranchName.ToString()))
            {               
                // create the actions on disk
                var localItemCreator = new LocalItemCreator();
                localItemCreator.CreateDirectoryInPlace(root, workingDir.Location);

                // commit (no check if there are pending changes, because there will always be changes (we made sure that syncActions is not empty and action do not yet exist))
                workingDir.Commit($"{nameof(GitSyncActionService)}: Added {syncActions.Count()} items");
                workingDir.Push();
            }
        }
        public void AddItems(IEnumerable<ConflictInfo> conflicts)
        {
            if (conflicts == null)
            {
                throw new ArgumentNullException(nameof(conflicts));
            }
            conflicts = conflicts.ToArray();

            if(!conflicts.Any())
            {
                return;
            }

            EnsureBranchExists();

            var exisitngRoot = new GitDirectory(null, "root", GitGroup.Repository.GetLocalBranch(BranchName).Tip);
            var createdRoot = new Directory(null, "root");

            // verify conflicts
            foreach (var conflict in conflicts)
            {                
                var relativePath = GetRelativeConflictInfoFilePath(conflict.FilePath);
                if (exisitngRoot.FileExists(relativePath))
                {
                    throw new DuplicateItemException($"A ConflictInfo for '{conflict.FilePath}' already exists");
                }

                var directory = DirectoryHelper.GetOrAddDirectory(createdRoot, PathParser.GetDirectoryName(relativePath));
                directory.Add(f => new ConflictInfoFile(f, conflict));
            }


            using (var workingDirectory = new TemporaryWorkingDirectory(GitGroup.Repository.Info.Path, BranchName.ToString()))
            {                
                var localItemCreator = new LocalItemCreator();
                localItemCreator.CreateDirectoryInPlace(createdRoot, workingDirectory.Location);

                workingDirectory.Commit($"{nameof(GitConflictService)}: Added {conflicts.Count()} items");
                workingDirectory.Push();
            }            

        }