docs: @Override
      public void execute() throws MojoExecutionException, MojoFailureException {
          validateConfiguration(preReleaseGoals, postReleaseGoals);
  
          try {
              // check uncommitted changes
              checkUncommittedChanges();
  
              // git for-each-ref --format='%(refname:short)' refs/heads/release/*
              final String releaseBranch = gitFindBranches(
                      gitFlowConfig.getReleaseBranchPrefix(), false).trim();
  
              if (StringUtils.isBlank(releaseBranch)) {
                  throw new MojoFailureException("There is no release branch.");
              } else if (StringUtils.countMatches(releaseBranch,
                      gitFlowConfig.getReleaseBranchPrefix()) > 1) {
                  throw new MojoFailureException(
                          "More than one release branch exists. Cannot finish release.");
              }
  
              // check snapshots dependencies
              if (!allowSnapshots) {
                  gitCheckout(releaseBranch);
  
                  checkSnapshotDependencies();
              }
  
              if (fetchRemote) {
                  // fetch and check remote
                  gitFetchRemoteAndCompare(releaseBranch);
  
                  // checkout from remote if doesn't exist
                  gitFetchRemoteAndCreate(gitFlowConfig.getDevelopmentBranch());
  
                  // fetch and check remote
                  gitFetchRemoteAndCompare(gitFlowConfig.getDevelopmentBranch());
  
                  if (notSameProdDevName()) {
                      // checkout from remote if doesn't exist
                      gitFetchRemoteAndCreate(gitFlowConfig.getProductionBranch());
  
                      // fetch and check remote
                      gitFetchRemoteAndCompare(gitFlowConfig
                              .getProductionBranch());
                  }
              }
  
              // git checkout release/...
              gitCheckout(releaseBranch);
  
              if (!skipTestProject) {
                  // mvn clean test
                  mvnCleanTest();
              }
  
              // maven goals before merge
              if (StringUtils.isNotBlank(preReleaseGoals)) {
                  mvnRun(preReleaseGoals);
              }
  
              String currentReleaseVersion = getCurrentProjectVersion();
  
              Map<String, String> messageProperties = new HashMap<String, String>();
              messageProperties.put("version", currentReleaseVersion);
  
              if (useSnapshotInRelease && ArtifactUtils.isSnapshot(currentReleaseVersion)) {
                  String commitVersion = currentReleaseVersion.replace("-" + Artifact.SNAPSHOT_VERSION, "");
  
                  mvnSetVersions(commitVersion);
  
                  messageProperties.put("version", commitVersion);
  
                  gitCommit(commitMessages.getReleaseFinishMessage(), messageProperties);
              }
  
              // git checkout master
              gitCheckout(gitFlowConfig.getProductionBranch());
  
              gitMerge(releaseBranch, releaseRebase, releaseMergeNoFF, releaseMergeFFOnly,
                      commitMessages.getReleaseFinishMergeMessage(), messageProperties);
  
              // get current project version from pom
              final String currentVersion = getCurrentProjectVersion();
  
              if (!skipTag) {
                  String tagVersion = currentVersion;
                  if ((tychoBuild || useSnapshotInRelease) && ArtifactUtils.isSnapshot(currentVersion)) {
                      tagVersion = currentVersion.replace("-"
                              + Artifact.SNAPSHOT_VERSION, "");
                  }
  
                  messageProperties.put("version", tagVersion);
  
                  // git tag -a ...
                  gitTag(gitFlowConfig.getVersionTagPrefix() + tagVersion,
                          commitMessages.getTagReleaseMessage(), gpgSignTag, messageProperties);
              }
  
              // maven goals after merge
              if (StringUtils.isNotBlank(postReleaseGoals)) {
                  mvnRun(postReleaseGoals);
              }
  
              if (notSameProdDevName()) {
                  // git checkout develop
                  gitCheckout(gitFlowConfig.getDevelopmentBranch());
  
                  // get develop version
                  final String developReleaseVersion = getCurrentProjectVersion();
                  if (commitDevelopmentVersionAtStart && useSnapshotInRelease) {
                      // updating develop poms to master version to avoid merge conflicts
                      mvnSetVersions(currentVersion);
  
                      // commit the changes
                      gitCommit(commitMessages.getUpdateDevToAvoidConflictsMessage());
                  }
  
                  // merge branch master into develop
                  gitMerge(releaseBranch, releaseRebase, releaseMergeNoFF, false, null, null);
  
                  if (commitDevelopmentVersionAtStart && useSnapshotInRelease) {
                      // updating develop poms version back to pre merge state
                      mvnSetVersions(developReleaseVersion);
  
                      // commit the changes
                      gitCommit(commitMessages.getUpdateDevBackPreMergeStateMessage());
                  }
              }
  
              if (commitDevelopmentVersionAtStart && !notSameProdDevName()) {
                  getLog().warn(
                          "The commitDevelopmentVersionAtStart will not have effect. It can be enabled only when there are separate branches for development and production.");
                  commitDevelopmentVersionAtStart = false;
              }
  
              if (!commitDevelopmentVersionAtStart) {
                  // get next snapshot version
                  final String nextSnapshotVersion;
                  if (!settings.isInteractiveMode()
                          && StringUtils.isNotBlank(developmentVersion)) {
                      nextSnapshotVersion = developmentVersion;
                  } else {
                      GitFlowVersionInfo versionInfo = new GitFlowVersionInfo(
                              currentVersion);
                      if (digitsOnlyDevVersion) {
                          versionInfo = versionInfo.digitsVersionInfo();
                      }
  
                      nextSnapshotVersion = versionInfo
                              .nextSnapshotVersion(versionDigitToIncrement);
                  }
  
                  if (StringUtils.isBlank(nextSnapshotVersion)) {
                      throw new MojoFailureException(
                              "Next snapshot version is blank.");
                  }
  
                  // mvn versions:set -DnewVersion=... -DgenerateBackupPoms=false
                  mvnSetVersions(nextSnapshotVersion);
  
                  messageProperties.put("version", nextSnapshotVersion);
  
                  // git commit -a -m updating for next development version
                  gitCommit(commitMessages.getReleaseFinishMessage(), messageProperties);
              }
  
              if (installProject) {
                  // mvn clean install
                  mvnCleanInstall();
              }
  
              if (pushRemote) {
                  gitPush(gitFlowConfig.getProductionBranch(), !skipTag);
                  if (notSameProdDevName()) {
                      gitPush(gitFlowConfig.getDevelopmentBranch(), !skipTag);
                  }
  
                  if (!keepBranch) {
                      gitPushDelete(releaseBranch);
                  }
              }
  
              if (!keepBranch) {
                  // git branch -d release/...
                  gitBranchDelete(releaseBranch);
              }
          } catch (Exception e) {
              throw new MojoFailureException("release-finish", e);
          }
      }