/// <inheritdoc />
        public override bool ExecuteTask()
        {
            bool analyzeFile               = File.Exists(ChangeLogFilePath) && PreserveChanges;
            var  versionDescMap            = new Dictionary <string, VersionDescription>();
            VersionDescription nextRelDesc = null;

            RefSpec.DefaultIfWhiteSpaceOrNull("master");

            //
            // Read and analyze existing ChangeLog
            using (var fs = File.Open(ChangeLogFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                if (analyzeFile)
                {
                    versionDescMap = ReadChangeLog(fs, out nextRelDesc);
                }

            //
            // Synchronize Git and ChangeLog
            var tagCommitMap = this.GetTagCommitMap(RefSpec, TagSortField);

            // Remove versions that do not exist in the tag list. That might cause issue when switching between branches
            foreach (var versionName in versionDescMap.Keys
                     .Where(vn => tagCommitMap.ContainsKey(vn) == false)
                     .ToArray())
            {
                versionDescMap.Remove(versionName);
            }

            // Define the ordering of our ChangeLog
            foreach (var versionName in versionDescMap.Keys.ToArray())
            {
                versionDescMap[versionName].No = tagCommitMap[versionName].No;
            }

            var noCommitMap = tagCommitMap.Values.ToDictionary(k => k.No);

            // Add missing tags and compose their content
            foreach (var tagName in tagCommitMap.Keys
                     .Where(tn => versionDescMap.ContainsKey(tn) == false)
                     .ToArray())
            {
                var tag     = tagCommitMap[tagName];
                var prevTag = tag.No > 0
          ? noCommitMap[tag.No - 1]
          : null;

                versionDescMap[tagName] = ComposeExistingVersionDescription(tag, prevTag?.CommitHash);
            }

            //
            // Create the next version release note
            var allVersions        = versionDescMap.Values.ToList();
            var lastTag            = versionDescMap.Values.OrderByDescending(v => v.No).FirstOrDefault();
            var fromCommitExcluded = nextRelDesc?.CommitHash ?? lastTag?.CommitHash;
            var toCommitIncluded   = RefSpec;
            var toCommitExpanded   = this.ExpandToCommitHash(toCommitIncluded);

            if (toCommitExpanded != fromCommitExcluded)
            {
                string releaseNote = this.ConcatCommitInfo(fromCommitExcluded, toCommitIncluded);

                if (nextRelDesc != null && string.IsNullOrWhiteSpace(nextRelDesc.Content.ToString()) == false)
                {
                    releaseNote += "\n" + nextRelDesc.Content;
                }

                nextRelDesc = new VersionDescription(VersionDescription.NextVersionName,
                                                     toCommitExpanded,
                                                     (lastTag?.No ?? 0) + 1);
                nextRelDesc.Content.Append(releaseNote);

                allVersions.Add(nextRelDesc);
            }

            else
            {
                nextRelDesc = lastTag;
            }


            //
            // Save ChangeLog
            WriteChangeLog(allVersions);

            CurrentVersionReleaseNotes    = nextRelDesc?.Content.ToString();
            CurrentVersionHasReleaseNotes = string.IsNullOrWhiteSpace(nextRelDesc?.Content.ToString()) == false;

            //
            // Write NuSpec if required
            if (string.IsNullOrWhiteSpace(NuSpecFilePath) == false && File.Exists(NuSpecFilePath) && nextRelDesc != null)
            {
                this.WriteNuSpec(NuSpecFilePath, "Replace", nuSpecProperty: "releaseNotes", nuSpecValue: nextRelDesc.Content.ToString());
            }

            return(true);
        }